From d056f59704cdd283733fa8a896e45f1731725cbb Mon Sep 17 00:00:00 2001 From: matwatson Date: Sun, 21 Sep 2025 14:14:29 -0700 Subject: [PATCH 001/340] corrected Cell module level doc replaced `&mut T` with `&T` to finally state "a &T to the inner value can never be obtained" --- library/core/src/cell.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9b53b75ebee8..1b3126700ff3 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -27,10 +27,9 @@ //! //! ## `Cell` //! -//! [`Cell`] implements interior mutability by moving values in and out of the cell. That is, an -//! `&mut T` to the inner value can never be obtained, and the value itself cannot be directly -//! obtained without replacing it with something else. Both of these rules ensure that there is -//! never more than one reference pointing to the inner value. This type provides the following +//! [`Cell`] implements interior mutability by moving values in and out of the cell. That is, a +//! `&T` to the inner value can never be obtained, and the value itself cannot be directly +//! obtained without replacing it with something else. This type provides the following //! methods: //! //! - For types that implement [`Copy`], the [`get`](Cell::get) method retrieves the current From ae310e230a14205b26f2c2796d80e9d90a6b5333 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 12 Nov 2025 19:26:31 +0000 Subject: [PATCH 002/340] fix: `redundant_pattern_matching` misses `)` in suggestion span --- .../src/matches/redundant_pattern_match.rs | 14 ++++---------- tests/ui/redundant_pattern_matching_option.fixed | 13 +++++++++++++ tests/ui/redundant_pattern_matching_option.rs | 13 +++++++++++++ tests/ui/redundant_pattern_matching_option.stderr | 14 +++++++++++++- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index bc3783750e5c..897e7da5a967 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -1,7 +1,6 @@ use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::{Sugg, make_unop}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; @@ -25,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { .. }) = higher::WhileLet::hir(expr) { - find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false); + find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false, let_span); find_if_let_true(cx, let_pat, let_expr, let_span); } } @@ -39,7 +38,7 @@ pub(super) fn check_if_let<'tcx>( let_span: Span, ) { find_if_let_true(cx, pat, scrutinee, let_span); - find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else); + find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else, let_span); } /// Looks for: @@ -182,6 +181,7 @@ fn find_method_sugg_for_if_let<'tcx>( let_expr: &'tcx Expr<'_>, keyword: &'static str, has_else: bool, + let_span: Span, ) { // also look inside refs // if we have &None for example, peel it so we can detect "if let None = x" @@ -239,15 +239,9 @@ fn find_method_sugg_for_if_let<'tcx>( let expr_span = expr.span; let ctxt = expr.span.ctxt(); - // if/while let ... = ... { ... } - // ^^^ - let Some(res_span) = walk_span_to_context(result_expr.span.source_callsite(), ctxt) else { - return; - }; - // if/while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(res_span.shrink_to_hi()); + let span = expr_span.until(let_span.shrink_to_hi()); let mut app = if needs_drop { Applicability::MaybeIncorrect diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index 08903ef7fdda..b44009446640 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -195,3 +195,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if x! {}.is_some() {}; + //~^ redundant_pattern_matching + while x! {}.is_some() {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 95eff3f9ebf9..c13cf993e786 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -231,3 +231,16 @@ fn issue16045() { } } } + +fn issue14989() { + macro_rules! x { + () => { + None:: + }; + } + + if let Some(_) = (x! {}) {}; + //~^ redundant_pattern_matching + while let Some(_) = (x! {}) {} + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 6fd0c5a6f859..5c9edfd4c50a 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -236,5 +236,17 @@ error: redundant pattern matching, consider using `is_some()` LL | if let Some(_) = x.await { | -------^^^^^^^---------- help: try: `if x.await.is_some()` -error: aborting due to 33 previous errors +error: redundant pattern matching, consider using `is_some()` + --> tests/ui/redundant_pattern_matching_option.rs:242:12 + | +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:244:15 + | +LL | while let Some(_) = (x! {}) {} + | ----------^^^^^^^---------- help: try: `while x! {}.is_some()` + +error: aborting due to 35 previous errors From c17b4a2ec78e9d726e471feba169572ec33ea230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Fischer?= Date: Thu, 18 Sep 2025 23:10:59 -0300 Subject: [PATCH 003/340] Clarify `strlen_on_c_strings` documentation --- clippy_lints/src/strlen_on_c_strings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 33856c750d7e..2e7affb8d07f 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -14,8 +14,8 @@ declare_clippy_lint! { /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. /// /// ### Why is this bad? - /// This avoids calling an unsafe `libc` function. - /// Currently, it also avoids calculating the length. + /// libc::strlen is an unsafe function, which we don't need to call + /// if all we want to know is the length of the c-string. /// /// ### Example /// ```rust, ignore From 4081c149b890c7536d0fa03c4c379a7c58074c2a Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sat, 13 Dec 2025 19:18:17 -0500 Subject: [PATCH 004/340] create_dir_all() operates iteratively instead of recursively --- library/std/src/fs.rs | 50 ++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b548eb4939d4..90e619ffbc15 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3333,26 +3333,42 @@ impl DirBuilder { return Ok(()); } - match self.inner.mkdir(path) { - Ok(()) => return Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} - Err(_) if path.is_dir() => return Ok(()), - Err(e) => return Err(e), - } - match path.parent() { - Some(p) => self.create_dir_all(p)?, - None => { - return Err(io::const_error!( - io::ErrorKind::Uncategorized, - "failed to create whole tree", - )); + let ancestors = path.ancestors(); + let mut uncreated_dirs = 0; + + for ancestor in ancestors { + // for relative paths like "foo/bar", the parent of + // "foo" will be "" which there's no need to invoke + // a mkdir syscall on + if ancestor == Path::new("") { + break; + } + + match self.inner.mkdir(ancestor) { + Ok(()) => break, + Err(e) if e.kind() == io::ErrorKind::NotFound => uncreated_dirs += 1, + // we check if the err is AlreadyExists for two reasons + // - in case the path exists as a *file* + // - and to avoid calls to .is_dir() in case of other errs + // (i.e. PermissionDenied) + Err(e) if e.kind() == io::ErrorKind::AlreadyExists && ancestor.is_dir() => break, + Err(e) => return Err(e), } } - match self.inner.mkdir(path) { - Ok(()) => Ok(()), - Err(_) if path.is_dir() => Ok(()), - Err(e) => Err(e), + + // collect only the uncreated directories w/o letting the vec resize + let mut uncreated_dirs_vec = Vec::with_capacity(uncreated_dirs); + uncreated_dirs_vec.extend(ancestors.take(uncreated_dirs)); + + for uncreated_dir in uncreated_dirs_vec.iter().rev() { + if let Err(e) = self.inner.mkdir(uncreated_dir) { + if e.kind() != io::ErrorKind::AlreadyExists || !uncreated_dir.is_dir() { + return Err(e); + } + } } + + Ok(()) } } From cd39f5a5fe0dededd4d53823fe395f98f0747cc2 Mon Sep 17 00:00:00 2001 From: tison Date: Sun, 14 Dec 2025 14:35:07 +0800 Subject: [PATCH 005/340] Add waker_fn and local_waker_fn to std::task Signed-off-by: tison --- library/alloc/src/task.rs | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index b4116f4988b6..73b732241974 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -127,6 +127,44 @@ impl From> for RawWaker { } } +/// Converts a closure into a [`Waker`]. +/// +/// The closure gets called every time the waker is woken. +/// +/// # Examples +/// +/// ``` +/// #![feature(waker_fn)] +/// use std::task::waker_fn; +/// +/// let waker = waker_fn(|| println!("woken")); +/// +/// waker.wake_by_ref(); // Prints "woken". +/// waker.wake(); // Prints "woken". +/// ``` +#[cfg(target_has_atomic = "ptr")] +#[unstable(feature = "waker_fn", issue = "149580")] +pub fn waker_fn(f: F) -> Waker { + struct WakeFn { + f: F, + } + + impl Wake for WakeFn + where + F: Fn(), + { + fn wake(self: Arc) { + (self.f)() + } + + fn wake_by_ref(self: &Arc) { + (self.f)() + } + } + + Waker::from(Arc::new(WakeFn { f })) +} + // NB: This private function for constructing a RawWaker is used, rather than // inlining this into the `From> for RawWaker` impl, to ensure that // the safety of `From> for Waker` does not depend on the correct @@ -306,6 +344,44 @@ impl From> for RawWaker { } } +/// Converts a closure into a [`LocalWaker`]. +/// +/// The closure gets called every time the local waker is woken. +/// +/// # Examples +/// +/// ``` +/// #![feature(local_waker)] +/// #![feature(waker_fn)] +/// use std::task::local_waker_fn; +/// +/// let waker = local_waker_fn(|| println!("woken")); +/// +/// waker.wake_by_ref(); // Prints "woken". +/// waker.wake(); // Prints "woken". +/// ``` +#[unstable(feature = "waker_fn", issue = "149580")] +pub fn local_waker_fn(f: F) -> LocalWaker { + struct LocalWakeFn { + f: F, + } + + impl LocalWake for LocalWakeFn + where + F: Fn(), + { + fn wake(self: Rc) { + (self.f)() + } + + fn wake_by_ref(self: &Rc) { + (self.f)() + } + } + + LocalWaker::from(Rc::new(LocalWakeFn { f })) +} + // NB: This private function for constructing a RawWaker is used, rather than // inlining this into the `From> for RawWaker` impl, to ensure that // the safety of `From> for Waker` does not depend on the correct From 167ad11c229a5804b8373b500d5a8cc5f67731f4 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sun, 14 Dec 2025 15:57:23 -0500 Subject: [PATCH 006/340] check if current path is root through seeing if its parent is None --- library/std/src/fs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 90e619ffbc15..feb17877d96f 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3329,7 +3329,9 @@ impl DirBuilder { } fn create_dir_all(&self, path: &Path) -> io::Result<()> { - if path == Path::new("") { + // if path's parent is None, it is "/" path, which should + // return Ok immediately + if path == Path::new("") || path.parent() == None { return Ok(()); } @@ -3340,7 +3342,7 @@ impl DirBuilder { // for relative paths like "foo/bar", the parent of // "foo" will be "" which there's no need to invoke // a mkdir syscall on - if ancestor == Path::new("") { + if ancestor == Path::new("") || ancestor.parent() == None { break; } From dc3786eb3c0b373665939763ddeac1d630f07ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 14 Nov 2025 10:10:06 +0100 Subject: [PATCH 007/340] stabilize map_next_if --- library/core/src/iter/adapters/peekable.rs | 7 ++----- library/coretests/tests/lib.rs | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index ee40d2b74c64..b9bdb827209b 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -337,7 +337,6 @@ impl Peekable { /// /// 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(|c| c.to_digit(10).ok_or(c)) { @@ -349,7 +348,6 @@ impl Peekable { /// /// Matching custom types. /// ``` - /// #![feature(peekable_next_if_map)] /// /// #[derive(Debug, PartialEq, Eq)] /// enum Node { @@ -408,7 +406,7 @@ impl Peekable { ///# ], ///# ) /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] pub fn next_if_map(&mut self, f: impl FnOnce(I::Item) -> Result) -> Option { let unpeek = if let Some(item) = self.next() { match f(item) { @@ -437,7 +435,6 @@ impl Peekable { /// /// 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)) { @@ -446,7 +443,7 @@ impl Peekable { /// assert_eq!(line_num, 125); /// assert_eq!(iter.collect::(), " GOTO 10"); /// ``` - #[unstable(feature = "peekable_next_if_map", issue = "143702")] + #[stable(feature = "peekable_next_if_map", since = "CURRENT_RUSTC_VERSION")] 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) { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0387b442562d..222e5dd32c86 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -91,7 +91,6 @@ #![feature(one_sided_range)] #![feature(option_reduce)] #![feature(pattern)] -#![feature(peekable_next_if_map)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] From 3566b6775c45169ffc9c5ede434ad0500ba0476e Mon Sep 17 00:00:00 2001 From: delta17920 Date: Mon, 15 Dec 2025 15:28:57 +0000 Subject: [PATCH 008/340] Fix macro_metavar_expr_concat behavior with nested repetitions --- compiler/rustc_expand/src/mbe/transcribe.rs | 29 +++++++-------- tests/ui/macros/concat-nested-repetition.rs | 35 +++++++++++++++++++ .../in-repetition.rs | 2 +- .../in-repetition.stderr | 6 ++-- .../metavar-expressions/concat-repetitions.rs | 7 ++-- .../concat-repetitions.stderr | 18 +++++----- 6 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 tests/ui/macros/concat-nested-repetition.rs diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index dddd62a4945a..d53d180a4ab9 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -558,25 +558,20 @@ fn metavar_expr_concat<'tx>( MetaVarExprConcatElem::Ident(elem) => elem.name, MetaVarExprConcatElem::Literal(elem) => *elem, MetaVarExprConcatElem::Var(ident) => { - match matched_from_ident(dcx, *ident, tscx.interp)? { - NamedMatch::MatchedSeq(named_matches) => { - let Some((curr_idx, _)) = tscx.repeats.last() else { - return Err(dcx.struct_span_err(dspan.entire(), "invalid syntax")); - }; - match &named_matches[*curr_idx] { - // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => { - return Err(dcx.struct_span_err( - ident.span, - "nested repetitions with `${concat(...)}` metavariable expressions are not yet supported", - )); - } - MatchedSingle(pnr) => extract_symbol_from_pnr(dcx, pnr, ident.span)?, - } - } - NamedMatch::MatchedSingle(pnr) => { + let key = MacroRulesNormalizedIdent::new(*ident); + match lookup_cur_matched(key, tscx.interp, &tscx.repeats) { + Some(NamedMatch::MatchedSingle(pnr)) => { extract_symbol_from_pnr(dcx, pnr, ident.span)? } + Some(NamedMatch::MatchedSeq(..)) => { + return Err(dcx.struct_span_err( + ident.span, + "`${concat(...)}` variable is still repeating at this depth", + )); + } + None => { + return Err(dcx.create_err(MveUnrecognizedVar { span: ident.span, key })); + } } } }; diff --git a/tests/ui/macros/concat-nested-repetition.rs b/tests/ui/macros/concat-nested-repetition.rs new file mode 100644 index 000000000000..ac5394ef8dcc --- /dev/null +++ b/tests/ui/macros/concat-nested-repetition.rs @@ -0,0 +1,35 @@ +//@ check-pass +#![feature(macro_metavar_expr_concat)] + +struct A; +struct B; +const AA: A = A; +const BB: B = B; + +macro_rules! define_ioctl_data { + (struct $s:ident { + $($field:ident: $ty:ident $([$opt:ident])?,)* + }) => { + pub struct $s { + $($field: $ty,)* + } + + impl $s { + $($( + fn ${concat(get_, $field)}(&self) -> $ty { + let _ = $opt; + todo!() + } + )?)* + } + }; +} + +define_ioctl_data! { + struct Foo { + a: A [AA], + b: B [BB], + } +} + +fn main() {} diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs index d2bd31b06d60..3ee11d373e05 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs @@ -11,7 +11,7 @@ macro_rules! InRepetition { ) => { $( $( - ${concat(_, $arg)} //~ ERROR nested repetitions with `${concat(...)}` metavariable expressions are not yet supported + ${concat(_, $arg)} //~ ERROR macro expansion ends with an incomplete expression: expected one of `!` or `::` )* )* }; diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr index ec39ca799e19..b84d98874931 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr @@ -1,8 +1,8 @@ -error: nested repetitions with `${concat(...)}` metavariable expressions are not yet supported - --> $DIR/in-repetition.rs:14:30 +error: macro expansion ends with an incomplete expression: expected one of `!` or `::` + --> $DIR/in-repetition.rs:14:35 | LL | ${concat(_, $arg)} - | ^^^ + | ^ expected one of `!` or `::` error: aborting due to 1 previous error diff --git a/tests/ui/macros/metavar-expressions/concat-repetitions.rs b/tests/ui/macros/metavar-expressions/concat-repetitions.rs index 52a7d5cd8a7e..133a969b1248 100644 --- a/tests/ui/macros/metavar-expressions/concat-repetitions.rs +++ b/tests/ui/macros/metavar-expressions/concat-repetitions.rs @@ -11,8 +11,7 @@ macro_rules! one_rep { macro_rules! issue_128346 { ( $($a:ident)* ) => { A( - const ${concat($a, Z)}: i32 = 3; - //~^ ERROR invalid syntax + const ${concat($a, Z)}: i32 = 3; //~ ERROR `${concat(...)}` variable is still repeating at this depth )* }; } @@ -20,8 +19,8 @@ macro_rules! issue_128346 { macro_rules! issue_131393 { ($t:ident $($en:ident)?) => { read::<${concat($t, $en)}>() - //~^ ERROR invalid syntax - //~| ERROR invalid syntax + //~^ ERROR `${concat(...)}` variable is still repeating at this depth + //~| ERROR `${concat(...)}` variable is still repeating at this depth } } diff --git a/tests/ui/macros/metavar-expressions/concat-repetitions.stderr b/tests/ui/macros/metavar-expressions/concat-repetitions.stderr index 18b0a90c1c8a..0ef20c65a284 100644 --- a/tests/ui/macros/metavar-expressions/concat-repetitions.stderr +++ b/tests/ui/macros/metavar-expressions/concat-repetitions.stderr @@ -1,20 +1,20 @@ -error: invalid syntax - --> $DIR/concat-repetitions.rs:14:20 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:14:29 | LL | const ${concat($a, Z)}: i32 = 3; - | ^^^^^^^^^^^^^^^ + | ^ -error: invalid syntax - --> $DIR/concat-repetitions.rs:22:17 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:21:30 | LL | read::<${concat($t, $en)}>() - | ^^^^^^^^^^^^^^^^^ + | ^^ -error: invalid syntax - --> $DIR/concat-repetitions.rs:22:17 +error: `${concat(...)}` variable is still repeating at this depth + --> $DIR/concat-repetitions.rs:21:30 | LL | read::<${concat($t, $en)}>() - | ^^^^^^^^^^^^^^^^^ + | ^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` From 558ff51722a7944e37c60ea73525bb9090955f90 Mon Sep 17 00:00:00 2001 From: Coca Date: Thu, 18 Dec 2025 17:13:55 +0000 Subject: [PATCH 009/340] `transmuting_null`: Check single expression const blocks and blocks changelog: [`transmuting_null`]: now checks single expression const blocks and blocks --- .../src/transmute/transmuting_null.rs | 20 ++++++++++++++++++- tests/ui/transmuting_null.rs | 11 ++++++++++ tests/ui/transmuting_null.stderr | 14 ++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 31e770f421e1..3f435f255d91 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -2,7 +2,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_integer_const; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{ConstBlock, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; use rustc_span::symbol::sym; @@ -42,5 +42,23 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } + // Catching: + // `std::mem::transmute({ 0 as *const u64 })` and similar const blocks + if let ExprKind::Block(block, _) = arg.kind + && block.stmts.is_empty() + && let Some(inner) = block.expr + { + // Run again with the inner expression + return check(cx, expr, inner, to_ty); + } + + // Catching: + // `std::mem::transmute(const { u64::MIN as *const u64 });` + if let ExprKind::ConstBlock(ConstBlock { body, .. }) = arg.kind { + // Strip out the const and run again + let block = cx.tcx.hir_body(body).value; + return check(cx, expr, block, to_ty); + } + false } diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index 0d3b26673452..00aa35dff803 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -37,8 +37,19 @@ fn transmute_const_int() { } } +fn transumute_single_expr_blocks() { + unsafe { + let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + //~^ transmuting_null + + let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); transmute_const_int(); + transumute_single_expr_blocks(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index ed7c3396a243..e1de391813bd 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -25,5 +25,17 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(u64::MIN as *const u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:42:23 + | +LL | let _: &u64 = std::mem::transmute({ 0 as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:45:23 + | +LL | let _: &u64 = std::mem::transmute(const { u64::MIN as *const u64 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors From b00739765c89f9182a8284c1718de7c858217869 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Tue, 16 Dec 2025 13:25:27 -0800 Subject: [PATCH 010/340] Update provider API docs --- library/core/src/error.rs | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 9ca91ee009ee..011d6ac4a1c7 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -205,6 +205,56 @@ pub trait Error: Debug + Display { /// assert!(request_ref::(dyn_error).is_none()); /// } /// ``` + /// + /// # Delegating Impls + /// + ///
+ /// + /// **Warning**: We recommend implementors avoid delegating implementations of `provide` to + /// source error implementations. + /// + ///
+ /// + /// This method should expose context from the current piece of the source chain only, not from + /// sources that are exposed in the chain of sources. Delegating `provide` implementations cause + /// the same context to be provided by multiple errors in the chain of sources which can cause + /// unintended duplication of information in error reports or require heuristics to deduplicate. + /// + /// In other words, the following implementation pattern for `provide` is discouraged and should + /// not be used for [`Error`] types exposed in public APIs to third parties. + /// + /// ```rust + /// # #![feature(error_generic_member_access)] + /// # use core::fmt; + /// # use core::error::Request; + /// # #[derive(Debug)] + /// struct MyError { + /// source: Error, + /// } + /// # #[derive(Debug)] + /// # struct Error; + /// # impl fmt::Display for Error { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "Example Source Error") + /// # } + /// # } + /// # impl fmt::Display for MyError { + /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// # write!(f, "Example Error") + /// # } + /// # } + /// # impl std::error::Error for Error { } + /// + /// impl std::error::Error for MyError { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// Some(&self.source) + /// } + /// + /// fn provide<'a>(&'a self, request: &mut Request<'a>) { + /// self.source.provide(request) // <--- Discouraged + /// } + /// } + /// ``` #[unstable(feature = "error_generic_member_access", issue = "99301")] #[allow(unused_variables)] fn provide<'a>(&'a self, request: &mut Request<'a>) {} From 5610d84ab12502922459ae5da17ac8e0774a8e44 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Dec 2025 07:55:00 -0800 Subject: [PATCH 011/340] rustc: Fix `-Zexport-executable-symbols` on wasm This commit reorders some cases in `export_symbols` in the linker implementation for wasm to ensure that the `is_like_wasm` case is handled before the catch-all `CrateType::Executable` case. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index c73e950bed40..b47652092ed5 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -839,6 +839,11 @@ impl<'a> Linker for GccLinker<'a> { self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); } self.link_arg(path); + } else if self.sess.target.is_like_wasm { + self.link_arg("--no-export-dynamic"); + for (sym, _) in symbols { + self.link_arg("--export").link_arg(sym); + } } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris { let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; @@ -853,11 +858,6 @@ impl<'a> Linker for GccLinker<'a> { self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); } self.link_arg("--dynamic-list").link_arg(path); - } else if self.sess.target.is_like_wasm { - self.link_arg("--no-export-dynamic"); - for (sym, _) in symbols { - self.link_arg("--export").link_arg(sym); - } } else { // Write an LD version script let res: io::Result<()> = try { From a2102a528c9e7d320ca08a7d934bbb614dcc8809 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 20 Dec 2025 03:52:46 +0000 Subject: [PATCH 012/340] fix: `new_without_default` misses where clause in `new` --- clippy_lints/src/new_without_default.rs | 30 +++++++++++--- tests/ui/new_without_default.fixed | 55 +++++++++++++++++++++++++ tests/ui/new_without_default.rs | 36 ++++++++++++++++ tests/ui/new_without_default.stderr | 55 ++++++++++++++++++++++++- 4 files changed, 170 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 6fc034b6fc5d..af78c093db6f 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::return_ty; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::sugg::DiagExt; use rustc_errors::Applicability; use rustc_hir as hir; @@ -57,6 +57,7 @@ pub struct NewWithoutDefault { impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]); impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { + #[expect(clippy::too_many_lines)] fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let hir::ItemKind::Impl(hir::Impl { of_trait: None, @@ -140,10 +141,29 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { }; let generics_sugg = snippet_with_applicability(cx, generics.span, "", &mut app); let where_clause_sugg = if generics.has_where_clause_predicates { - format!( - "\n{}\n", - snippet_with_applicability(cx, generics.where_clause_span, "", &mut app) - ) + let where_clause_sugg = + snippet_with_applicability(cx, generics.where_clause_span, "", &mut app).to_string(); + let mut where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4)); + if impl_item.generics.has_where_clause_predicates { + if !where_clause_sugg.ends_with(',') { + where_clause_sugg.push(','); + } + + let additional_where_preds = + snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app); + let ident = indent_of(cx, generics.where_clause_span).unwrap_or(0); + // Remove the leading `where ` keyword + let additional_where_preds = additional_where_preds.trim_start_matches("where").trim_start(); + where_clause_sugg.push('\n'); + where_clause_sugg.extend(std::iter::repeat_n(' ', ident)); + where_clause_sugg.push_str(additional_where_preds); + } + format!("\n{where_clause_sugg}\n") + } else if impl_item.generics.has_where_clause_predicates { + let where_clause_sugg = + snippet_with_applicability(cx, impl_item.generics.where_clause_span, "", &mut app); + let where_clause_sugg = reindent_multiline(&where_clause_sugg, true, Some(4)); + format!("\n{}\n", where_clause_sugg.trim_start()) } else { String::new() }; diff --git a/tests/ui/new_without_default.fixed b/tests/ui/new_without_default.fixed index 9a5e90b48065..f6591820feeb 100644 --- a/tests/ui/new_without_default.fixed +++ b/tests/ui/new_without_default.fixed @@ -409,3 +409,58 @@ mod issue15778 { } } } + +pub mod issue16255 { + use std::fmt::Display; + use std::marker::PhantomData; + + pub struct Foo { + marker: PhantomData, + } + + impl Default for Foo + where + T: Display, + T: Clone, + { + fn default() -> Self { + Self::new() + } + } + + impl Foo + where + T: Display, + { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } + + pub struct Bar { + marker: PhantomData, + } + + impl Default for Bar + where + T: Clone, + { + fn default() -> Self { + Self::new() + } + } + + impl Bar { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } +} diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index f7466aa32189..d3447f2e16b2 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -324,3 +324,39 @@ mod issue15778 { } } } + +pub mod issue16255 { + use std::fmt::Display; + use std::marker::PhantomData; + + pub struct Foo { + marker: PhantomData, + } + + impl Foo + where + T: Display, + { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } + + pub struct Bar { + marker: PhantomData, + } + + impl Bar { + pub fn new() -> Self + //~^ new_without_default + where + T: Clone, + { + Self { marker: PhantomData } + } + } +} diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 0593dbb00fb6..6c0f73d13185 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -250,5 +250,58 @@ LL + } LL + } | -error: aborting due to 13 previous errors +error: you should consider adding a `Default` implementation for `Foo` + --> tests/ui/new_without_default.rs:340:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Foo +LL + where +LL + T: Display, +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Foo + | + +error: you should consider adding a `Default` implementation for `Bar` + --> tests/ui/new_without_default.rs:354:9 + | +LL | / pub fn new() -> Self +LL | | +LL | | where +LL | | T: Clone, +LL | | { +LL | | Self { marker: PhantomData } +LL | | } + | |_________^ + | +help: try adding this + | +LL ~ impl Default for Bar +LL + where +LL + T: Clone, +LL + { +LL + fn default() -> Self { +LL + Self::new() +LL + } +LL + } +LL + +LL ~ impl Bar { + | + +error: aborting due to 15 previous errors From 4c4b2a1dbe8692196df6f4f117c2f074b410fa81 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 20 Dec 2025 18:53:58 +0000 Subject: [PATCH 013/340] fix: `str_to_string` wrongly unmangled macros --- clippy_lints/src/strings.rs | 5 +++-- tests/ui/str_to_string.fixed | 14 ++++++++++++++ tests/ui/str_to_string.rs | 14 ++++++++++++++ tests/ui/str_to_string.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1d0efa46a14c..609504ffc233 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeQPath}; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym, }; @@ -404,7 +404,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { "`to_string()` called on a `&str`", |diag| { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability); diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); }, ); diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed index 2941c4dbd33d..8713c4f9bc86 100644 --- a/tests/ui/str_to_string.fixed +++ b/tests/ui/str_to_string.fixed @@ -8,3 +8,17 @@ fn main() { msg.to_owned(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_owned(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs index 4c4d2bb18062..b81759e1037b 100644 --- a/tests/ui/str_to_string.rs +++ b/tests/ui/str_to_string.rs @@ -8,3 +8,17 @@ fn main() { msg.to_string(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_string(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index cb7b6b48843a..c0a38c8ebe46 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -13,5 +13,11 @@ error: `to_string()` called on a `&str` LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` -error: aborting due to 2 previous errors +error: `to_string()` called on a `&str` + --> tests/ui/str_to_string.rs:22:18 + | +LL | let _value = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` + +error: aborting due to 3 previous errors From 1377de0f0e7e25ee4c4869853456694fc8639363 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 21 Dec 2025 21:20:42 +0000 Subject: [PATCH 014/340] fix: `bool_assert_comparison` suggests wrongly for macros --- clippy_lints/src/bool_assert_comparison.rs | 33 ++++++++++++---------- tests/ui/bool_assert_comparison.fixed | 13 +++++++++ tests/ui/bool_assert_comparison.rs | 13 +++++++++ tests/ui/bool_assert_comparison.stderr | 26 ++++++++++++++++- 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index f31b67f470f9..165941a859f7 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::source::walk_span_to_context; use clippy_utils::sugg::Sugg; use clippy_utils::sym; use clippy_utils::ty::{implements_trait, is_copy}; @@ -130,22 +131,24 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())]; - if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) { - let sugg = if bool_value ^ eq_macro { - !sugg.maybe_paren() - } else if ty::Bool == *non_lit_ty.kind() { - sugg - } else { - !!sugg.maybe_paren() - }; - suggestions.push((non_lit_expr.span, sugg.to_string())); + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, non_lit_expr, macro_call.span.ctxt(), "..", &mut applicability); + let sugg = if bool_value ^ eq_macro { + !sugg.maybe_paren() + } else if ty::Bool == *non_lit_ty.kind() { + sugg + } else { + !!sugg.maybe_paren() + }; + let non_lit_expr_span = + walk_span_to_context(non_lit_expr.span, macro_call.span.ctxt()).unwrap_or(non_lit_expr.span); + suggestions.push((non_lit_expr_span, sugg.to_string())); - diag.multipart_suggestion( - format!("replace it with `{non_eq_mac}!(..)`"), - suggestions, - Applicability::MachineApplicable, - ); - } + diag.multipart_suggestion( + format!("replace it with `{non_eq_mac}!(..)`"), + suggestions, + applicability, + ); }, ); } diff --git a/tests/ui/bool_assert_comparison.fixed b/tests/ui/bool_assert_comparison.fixed index ec76abbef05a..cd390ce0db9d 100644 --- a/tests/ui/bool_assert_comparison.fixed +++ b/tests/ui/bool_assert_comparison.fixed @@ -216,3 +216,16 @@ fn main() { assert!(!(b + b)); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert!(!is_empty!("a")); + //~^ bool_assert_comparison + assert!(is_empty!("")); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.rs b/tests/ui/bool_assert_comparison.rs index 40824a23c82e..b2ea5b6ea540 100644 --- a/tests/ui/bool_assert_comparison.rs +++ b/tests/ui/bool_assert_comparison.rs @@ -216,3 +216,16 @@ fn main() { assert_eq!(b + b, false); //~^ bool_assert_comparison } + +fn issue16279() { + macro_rules! is_empty { + ($x:expr) => { + $x.is_empty() + }; + } + + assert_eq!(is_empty!("a"), false); + //~^ bool_assert_comparison + assert_eq!(is_empty!(""), true); + //~^ bool_assert_comparison +} diff --git a/tests/ui/bool_assert_comparison.stderr b/tests/ui/bool_assert_comparison.stderr index 72aa6303a202..b4e8fcf09bb6 100644 --- a/tests/ui/bool_assert_comparison.stderr +++ b/tests/ui/bool_assert_comparison.stderr @@ -444,5 +444,29 @@ LL - assert_eq!(b + b, false); LL + assert!(!(b + b)); | -error: aborting due to 37 previous errors +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:227:5 + | +LL | assert_eq!(is_empty!("a"), false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!("a"), false); +LL + assert!(!is_empty!("a")); + | + +error: used `assert_eq!` with a literal bool + --> tests/ui/bool_assert_comparison.rs:229:5 + | +LL | assert_eq!(is_empty!(""), true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: replace it with `assert!(..)` + | +LL - assert_eq!(is_empty!(""), true); +LL + assert!(is_empty!("")); + | + +error: aborting due to 39 previous errors From 22996d69599b39f5bbad9f1b85aaa7e9d1f3990f Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Mon, 22 Dec 2025 14:55:44 +0100 Subject: [PATCH 015/340] Remove inactive nvptx maintainer --- src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 36598982481b..56caf531a92e 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -7,7 +7,6 @@ platform. ## Target maintainers -[@RDambrosio016](https://github.com/RDambrosio016) [@kjetilkjeka](https://github.com/kjetilkjeka) ## Requirements From 27be5c2f682567a8825d6b50a04feda8f74ccf39 Mon Sep 17 00:00:00 2001 From: Soroush Mirzaei Date: Mon, 22 Dec 2025 10:14:57 -0500 Subject: [PATCH 016/340] docs(core): update `find()` and `rfind()` examples `find()` has a missing example. In the docs there was a mention of an example with double reference but it didn't exist. `rfind()` is also very similar to `find()`, however it had the double reference example and no owned value example like `find()` did. This commit adds the missing examples and making them look consistent. --- library/core/src/iter/traits/double_ended.rs | 12 +++++++++++- library/core/src/iter/traits/iterator.rs | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 7dabaece9556..da0b05063657 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -334,8 +334,18 @@ pub trait DoubleEndedIterator: Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); + /// assert_eq!(a.into_iter().rfind(|&x| x == 2), Some(2)); + /// assert_eq!(a.into_iter().rfind(|&x| x == 5), None); + /// ``` /// + /// Iterating over references: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// // `iter()` yields references i.e. `&i32` and `rfind()` takes a + /// // reference to each element. + /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); /// assert_eq!(a.iter().rfind(|&&x| x == 5), None); /// ``` /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 29230b166538..d99afbc6036d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2858,6 +2858,17 @@ pub trait Iterator { /// assert_eq!(a.into_iter().find(|&x| x == 5), None); /// ``` /// + /// Iterating over references: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// // `iter()` yields references i.e. `&i32` and `find()` takes a + /// // reference to each element. + /// assert_eq!(a.iter().find(|&&x| x == 2), Some(&2)); + /// assert_eq!(a.iter().find(|&&x| x == 5), None); + /// ``` + /// /// Stopping at the first `true`: /// /// ``` From 7afba2977d0d8a2a2148cbdc244a86258bb5d328 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 9 Dec 2025 09:49:50 +0100 Subject: [PATCH 017/340] Make attr path symbols rather than idents --- compiler/rustc_ast/src/attr/mod.rs | 42 +++++++++---------- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 8 +--- .../src/attributes/cfg_select.rs | 7 +--- .../rustc_attr_parsing/src/attributes/util.rs | 3 +- compiler/rustc_attr_parsing/src/parser.rs | 2 +- compiler/rustc_attr_parsing/src/safety.rs | 2 +- .../rustc_attr_parsing/src/target_checking.rs | 2 +- .../rustc_attr_parsing/src/validate_attr.rs | 2 +- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 5 +-- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 +- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_hir/src/hir.rs | 33 ++++++++------- compiler/rustc_hir_pretty/src/lib.rs | 8 +++- .../rustc_parse/src/parser/attr_wrapper.rs | 12 +++--- compiler/rustc_passes/src/check_attr.rs | 4 +- .../src/ich/impls_syntax.rs | 2 +- src/librustdoc/clean/cfg.rs | 4 +- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/passes/propagate_doc_cfg.rs | 4 +- .../src/attrs/allow_attributes.rs | 7 ++-- .../clippy/clippy_lints/src/attrs/mod.rs | 12 +++--- .../src/attrs/useless_attribute.rs | 2 +- .../clippy_lints/src/incompatible_msrv.rs | 2 +- .../clippy/clippy_lints/src/missing_doc.rs | 4 +- src/tools/clippy/clippy_utils/src/attrs.rs | 17 ++++---- .../clippy_utils/src/check_proc_macro.rs | 4 +- .../tests/ui/renamed_builtin_attr.stderr | 4 +- .../clippy/tests/ui/unknown_attribute.stderr | 4 +- src/tools/rustfmt/src/attr.rs | 4 +- 31 files changed, 103 insertions(+), 115 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c53188a22aed..c0ed6e24e222 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -96,11 +96,11 @@ impl AttributeExt for Attribute { } /// For a single-segment attribute, returns its name; otherwise, returns `None`. - fn ident(&self) -> Option { + fn name(&self) -> Option { match &self.kind { AttrKind::Normal(normal) => { if let [ident] = &*normal.item.path.segments { - Some(ident.ident) + Some(ident.ident.name) } else { None } @@ -109,9 +109,18 @@ impl AttributeExt for Attribute { } } - fn ident_path(&self) -> Option> { + fn symbol_path(&self) -> Option> { match &self.kind { - AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()), + AttrKind::Normal(p) => { + Some(p.item.path.segments.iter().map(|i| i.ident.name).collect()) + } + AttrKind::DocComment(_, _) => None, + } + } + + fn path_span(&self) -> Option { + match &self.kind { + AttrKind::Normal(attr) => Some(attr.item.path.span), AttrKind::DocComment(_, _) => None, } } @@ -794,9 +803,7 @@ pub trait AttributeExt: Debug { /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), /// return the name of the attribute; otherwise, returns `None`. - fn name(&self) -> Option { - self.ident().map(|ident| ident.name) - } + fn name(&self) -> Option; /// Get the meta item list, `#[attr(meta item list)]` fn meta_item_list(&self) -> Option>; @@ -807,9 +814,6 @@ pub trait AttributeExt: Debug { /// Gets the span of the value literal, as string, when using `#[attr = value]` fn value_span(&self) -> Option; - /// For a single-segment attribute, returns its ident; otherwise, returns `None`. - fn ident(&self) -> Option; - /// Checks whether the path of this attribute matches the name. /// /// Matches one segment of the path to each element in `name` @@ -822,7 +826,7 @@ pub trait AttributeExt: Debug { #[inline] fn has_name(&self, name: Symbol) -> bool { - self.ident().map(|x| x.name == name).unwrap_or(false) + self.name().map(|x| x == name).unwrap_or(false) } #[inline] @@ -836,13 +840,13 @@ pub trait AttributeExt: Debug { fn is_word(&self) -> bool; fn path(&self) -> SmallVec<[Symbol; 1]> { - self.ident_path() - .map(|i| i.into_iter().map(|i| i.name).collect()) - .unwrap_or(smallvec![sym::doc]) + self.symbol_path().unwrap_or(smallvec![sym::doc]) } + fn path_span(&self) -> Option; + /// Returns None for doc comments - fn ident_path(&self) -> Option>; + fn symbol_path(&self) -> Option>; /// Returns the documentation if this is a doc comment or a sugared doc comment. /// * `///doc` returns `Some("doc")`. @@ -903,10 +907,6 @@ impl Attribute { AttributeExt::value_span(self) } - pub fn ident(&self) -> Option { - AttributeExt::ident(self) - } - pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) } @@ -938,10 +938,6 @@ impl Attribute { AttributeExt::path(self) } - pub fn ident_path(&self) -> Option> { - AttributeExt::ident_path(self) - } - pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index dbbd3906b525..26eb8051df37 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -160,7 +160,7 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); // Check feature gates for built-in attributes. if let Some(BuiltinAttribute { gate: AttributeGate::Gated { feature, message, check, notes, .. }, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 798cc1076541..66f0f8d391f6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -371,13 +371,7 @@ fn parse_cfg_attr_internal<'a>( attribute.span, attribute.get_normal_item().span(), attribute.style, - AttrPath { - segments: attribute - .ident_path() - .expect("cfg_attr is not a doc comment") - .into_boxed_slice(), - span: attribute.span, - }, + AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span }, Some(attribute.get_normal_item().unsafety), ParsedDescription::Attribute, pred_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 00a2d12106e7..24b989e22a2b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_hir::attrs::CfgEntry; use rustc_parse::exp; use rustc_parse::parser::Parser; use rustc_session::Session; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{ErrorGuaranteed, Span, sym}; use crate::parser::MetaItemOrLitParser; use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; @@ -86,10 +86,7 @@ pub fn parse_cfg_select( cfg_span, cfg_span, AttrStyle::Inner, - AttrPath { - segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(), - span: cfg_span, - }, + AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span }, None, ParsedDescription::Macro, cfg_span, diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 431ba539b2ba..ebec8e8443fc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -28,8 +28,7 @@ pub fn parse_version(s: Symbol) -> Option { } pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { - attr.is_doc_comment().is_some() - || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) + attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name)) } /// Parse a single integer. diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 9551744d5ec5..9c0fbe92d71b 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -34,7 +34,7 @@ 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(), + segments: self.segments().map(|s| s.name).collect::>().into_boxed_slice(), span: self.span(), } } diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 817785108a1e..68aeca2bbda9 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -22,7 +22,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { return; } - let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name); + let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]); if let Some(name) = name && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) { diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 88efb910c160..e86ecb451fc2 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -104,7 +104,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { 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 + let lint = if name.segments[0] == sym::deprecated && ![ Target::Closure, Target::Expression, diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index e69ed0eea6b0..4879646a1107 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { return; } - let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); + let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); // Check input tokens for built-in and key-value attributes. match builtin_attr_info { diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 7bc9080ba022..557daa94b98e 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa use rustc_hir::AttrPath; use rustc_hir::attrs::CfgEntry; use rustc_parse::exp; -use rustc_span::{ErrorGuaranteed, Ident, Span}; +use rustc_span::{ErrorGuaranteed, Span, sym}; use crate::errors; @@ -47,7 +47,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result bool { impl<'ast> visit::Visitor<'ast> for CfgFinder { type Result = ControlFlow<()>; fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> { - if attr - .ident() - .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) - { + if attr.name().is_some_and(|name| name == sym::cfg || name == sym::cfg_attr) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8135fd43dd93..93043c69579a 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -18,7 +18,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, Instance, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::Os; use crate::errors; @@ -357,7 +357,7 @@ fn process_builtin_attrs( } } - let Some(Ident { name, .. }) = attr.ident() else { + let Some(name) = attr.name() else { continue; }; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6422779e13c9..52b7339e0140 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2110,7 +2110,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut attr_pos = None; for (pos, attr) in item.attrs().iter().enumerate() { if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) { - let name = attr.ident().map(|ident| ident.name); + let name = attr.name(); if name == Some(sym::cfg) || name == Some(sym::cfg_attr) { cfg_pos = Some(pos); // a cfg attr found, no need to search anymore break; @@ -2187,7 +2187,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } else if rustc_attr_parsing::is_builtin_attr(attr) && !AttributeParser::::is_parsed_attribute(&attr.path()) { - let attr_name = attr.ident().unwrap().name; + let attr_name = attr.name().unwrap(); // `#[cfg]` and `#[cfg_attr]` are special - they are // eagerly evaluated. if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c60471848c89..483e864f69d4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1182,7 +1182,7 @@ pub enum AttrArgs { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrPath { - pub segments: Box<[Ident]>, + pub segments: Box<[Symbol]>, pub span: Span, } @@ -1198,7 +1198,7 @@ impl AttrPath { segments: path .segments .iter() - .map(|i| Ident { name: i.ident.name, span: lower_span(i.ident.span) }) + .map(|i| i.ident.name) .collect::>() .into_boxed_slice(), span: lower_span(path.span), @@ -1208,7 +1208,11 @@ impl AttrPath { impl fmt::Display for AttrPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", join_path_idents(&self.segments)) + write!( + f, + "{}", + join_path_idents(self.segments.iter().map(|i| Ident { name: *i, span: DUMMY_SP })) + ) } } @@ -1313,7 +1317,7 @@ impl AttributeExt for Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. #[inline] - fn ident(&self) -> Option { + fn name(&self) -> Option { match &self { Attribute::Unparsed(n) => { if let [ident] = n.path.segments.as_ref() { @@ -1329,7 +1333,7 @@ impl AttributeExt for Attribute { #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { match &self { - Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name), + Attribute::Unparsed(n) => n.path.segments.iter().eq(name), _ => false, } } @@ -1365,13 +1369,20 @@ impl AttributeExt for Attribute { } #[inline] - fn ident_path(&self) -> Option> { + fn symbol_path(&self) -> Option> { match &self { Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()), _ => None, } } + fn path_span(&self) -> Option { + match &self { + Attribute::Unparsed(attr) => Some(attr.path.span), + Attribute::Parsed(_) => None, + } + } + #[inline] fn doc_str(&self) -> Option { match &self { @@ -1451,11 +1462,6 @@ impl Attribute { AttributeExt::value_span(self) } - #[inline] - pub fn ident(&self) -> Option { - AttributeExt::ident(self) - } - #[inline] pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) @@ -1491,11 +1497,6 @@ impl Attribute { AttributeExt::path(self) } - #[inline] - pub fn ident_path(&self) -> Option> { - AttributeExt::ident_path(self) - } - #[inline] pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3b416955230..80e8bcb9a93a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -22,7 +22,7 @@ use rustc_hir::{ TyPatKind, }; use rustc_span::source_map::SourceMap; -use rustc_span::{FileName, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use {rustc_ast as ast, rustc_hir as hir}; pub fn id_to_string(cx: &dyn rustc_hir::intravisit::HirTyCtxt<'_>, hir_id: HirId) -> String { @@ -136,7 +136,11 @@ impl<'a> State<'a> { .path .segments .iter() - .map(|i| ast::PathSegment { ident: *i, args: None, id: DUMMY_NODE_ID }) + .map(|i| ast::PathSegment { + ident: Ident { name: *i, span: DUMMY_SP }, + args: None, + id: DUMMY_NODE_ID, + }) .collect(), tokens: None, }; diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 44fdf146f9c7..e04178645fdd 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -86,9 +86,9 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // NOTE: Builtin attributes like `cfg` and `cfg_attr` cannot be renamed via imports. // Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that // we don't need to do any eager expansion. - attrs.iter().any(|attr| { - attr.ident().is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr) - }) + attrs + .iter() + .any(|attr| attr.name().is_some_and(|ident| ident == sym::cfg || ident == sym::cfg_attr)) } impl<'a> Parser<'a> { @@ -398,10 +398,8 @@ impl<'a> Parser<'a> { /// - any single-segment, non-builtin attributes are present, e.g. `derive`, /// `test`, `global_allocator`. fn needs_tokens(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| match attr.ident() { + attrs.iter().any(|attr| match attr.name() { None => !attr.is_doc_comment(), - Some(ident) => { - ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name) - } + Some(name) => name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(name), }) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7822614a05cb..eb551201b083 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -388,7 +388,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.path .segments .first() - .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + .and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)) { match attr.style { ast::AttrStyle::Outer => { @@ -425,7 +425,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Attribute::Unparsed(unparsed_attr) = attr && let Some(BuiltinAttribute { duplicates, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)) { check_duplicates( self.tcx, diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 118229ffc990..fe6fb3d65194 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -24,7 +24,7 @@ impl<'a> HashStable> for [hir::Attribute] { .filter(|attr| { attr.is_doc_comment().is_none() // FIXME(jdonszelmann) have a better way to handle ignored attrs - && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name)) + && !attr.name().is_some_and(|ident| hcx.is_ignored_attr(ident)) }) .collect(); diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 7ab2a72d75b5..61ebc73182c0 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -859,8 +859,8 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } continue; } else if !cfg_info.parent_is_doc_cfg - && let Some(ident) = attr.ident() - && matches!(ident.name, sym::cfg | sym::cfg_trace) + && let Some(name) = attr.name() + && matches!(name, sym::cfg | sym::cfg_trace) && let Some(attr) = single(attr.meta_item_list()?) && let Ok(new_cfg) = Cfg::parse(&attr) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 764b3a0acdb6..72996cc4f21e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2673,8 +2673,8 @@ fn add_without_unwanted_attributes<'hir>( import_parent, )); } - hir::Attribute::Unparsed(normal) if let [ident] = &*normal.path.segments => { - if is_inline || ident.name != sym::cfg_trace { + hir::Attribute::Unparsed(normal) if let [name] = &*normal.path.segments => { + if is_inline || *name != sym::cfg_trace { // If it's not a `cfg()` attribute, we keep it. attrs.push((Cow::Borrowed(attr), import_parent)); } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 95f5537f394c..d4bf74c29514 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -40,8 +40,8 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) new_attr.cfg = d.cfg.clone(); attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); } else if let Attribute::Unparsed(normal) = attr - && let [ident] = &*normal.path.segments - && ident.name == sym::cfg_trace + && let [name] = &*normal.path.segments + && *name == sym::cfg_trace { // If it's a `cfg()` attribute, we keep it. attrs.push(attr.clone()); diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index 53d9725703c3..84b65d3185e3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -4,18 +4,19 @@ use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; +use rustc_ast::attr::AttributeExt; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !attr.span.in_external_macro(cx.sess().source_map()) && let AttrStyle::Outer = attr.style - && let Some(ident) = attr.ident() + && let Some(path_span) = attr.path_span() && !is_from_proc_macro(cx, attr) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| { + span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| { diag.span_suggestion( - ident.span, + path_span, "replace it with", "expect", Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 91c2dc7f3dc6..679ccfb8de3a 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -574,16 +574,16 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { if let Some(items) = &attr.meta_item_list() - && let Some(ident) = attr.ident() + && let Some(name) = attr.name() { - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + if matches!(name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { allow_attributes::check(cx, attr); } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes_without_reason::check(cx, ident.name, items, attr); + if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes_without_reason::check(cx, name, items, attr); } - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); + if is_lint_level(name, attr.id) { + blanket_clippy_restriction_lints::check(cx, name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..aa9a6654bee3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() - && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) + && attr.name().is_some_and(|name| is_lint_level(name, attr.id)) { for lint in lint_list { match item.kind { diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index c3bc9048c23a..28ea2e4fa1f0 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -270,7 +270,7 @@ fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { cx.tcx.hir_attrs(id).iter().any(|attr| { matches!( - attr.ident().map(|ident| ident.name), + attr.name(), Some(sym::cfg_trace | sym::cfg_attr_trace) ) }) diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index ac221743cfd6..375b275cd113 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -287,8 +287,8 @@ 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 => + if let [name] = &*attr.path.segments + && *name == sym::doc => { matches!(attr.args, AttrArgs::Eq { .. }) }, diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 2fd773b06781..94e4ede14048 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -20,10 +20,11 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { - if let Some([clippy, segment2]) = attr.ident_path().as_deref() - && clippy.name == sym::clippy + if let [clippy, segment2] = &*attr.path() + && *clippy == sym::clippy { - let new_name = match segment2.name { + let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span"); + let new_name = match *segment2 { sym::cyclomatic_complexity => Some("cognitive_complexity"), sym::author | sym::version @@ -35,7 +36,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( | sym::has_significant_drop | sym::format_args => None, _ => { - sess.dcx().span_err(segment2.span, "usage of unknown attribute"); + sess.dcx().span_err(path_span, "usage of unknown attribute"); return false; }, }; @@ -43,17 +44,17 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( match new_name { Some(new_name) => { sess.dcx() - .struct_span_err(segment2.span, "usage of deprecated attribute") + .struct_span_err(path_span, "usage of deprecated attribute") .with_span_suggestion( - segment2.span, + path_span, "consider using", - new_name, + format!("clippy::{}", new_name), Applicability::MachineApplicable, ) .emit(); false }, - None => segment2.name == name, + None => *segment2 == name, } } else { false diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index d9254fca9453..7fb8616072a5 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -348,9 +348,9 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { match attr.kind { AttrKind::Normal(..) => { - if let Some(ident) = attr.ident() { + if let Some(name) = attr.name() { // NOTE: This will likely have false positives, like `allow = 1` - let ident_string = ident.to_string(); + let ident_string = name.to_string(); if attr.style == AttrStyle::Outer { ( Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]), diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr index fb51313dab69..0ebc43739d6b 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.stderr @@ -1,8 +1,8 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:11 + --> tests/ui/renamed_builtin_attr.rs:3:3 | LL | #[clippy::cyclomatic_complexity = "1"] - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity` error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/unknown_attribute.stderr b/src/tools/clippy/tests/ui/unknown_attribute.stderr index b306abe0a9d1..1d4d50ffc02a 100644 --- a/src/tools/clippy/tests/ui/unknown_attribute.stderr +++ b/src/tools/clippy/tests/ui/unknown_attribute.stderr @@ -1,8 +1,8 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:3:11 + --> tests/ui/unknown_attribute.rs:3:3 | LL | #[clippy::unknown] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs index 381c938ae806..d03d33514046 100644 --- a/src/tools/rustfmt/src/attr.rs +++ b/src/tools/rustfmt/src/attr.rs @@ -336,8 +336,8 @@ impl Rewrite for ast::Attribute { rewrite_doc_comment(snippet, shape.comment(context.config), context.config) } else { let should_skip = self - .ident() - .map(|s| context.skip_context.attributes.skip(s.name.as_str())) + .name() + .map(|s| context.skip_context.attributes.skip(s.as_str())) .unwrap_or(false); let prefix = attr_prefix(self); From 4d0dbee8362a6b2f46526a8050ca8b6e658bfc38 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 9 Dec 2025 09:49:50 +0100 Subject: [PATCH 018/340] Make attr path symbols rather than idents --- clippy_lints/src/attrs/allow_attributes.rs | 7 ++++--- clippy_lints/src/attrs/mod.rs | 12 ++++++------ clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/incompatible_msrv.rs | 2 +- clippy_lints/src/missing_doc.rs | 4 ++-- clippy_utils/src/attrs.rs | 17 +++++++++-------- clippy_utils/src/check_proc_macro.rs | 4 ++-- tests/ui/renamed_builtin_attr.stderr | 4 ++-- tests/ui/unknown_attribute.stderr | 4 ++-- 9 files changed, 29 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs index 53d9725703c3..84b65d3185e3 100644 --- a/clippy_lints/src/attrs/allow_attributes.rs +++ b/clippy_lints/src/attrs/allow_attributes.rs @@ -4,18 +4,19 @@ use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; +use rustc_ast::attr::AttributeExt; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !attr.span.in_external_macro(cx.sess().source_map()) && let AttrStyle::Outer = attr.style - && let Some(ident) = attr.ident() + && let Some(path_span) = attr.path_span() && !is_from_proc_macro(cx, attr) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| { + span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| { diag.span_suggestion( - ident.span, + path_span, "replace it with", "expect", Applicability::MachineApplicable, diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 91c2dc7f3dc6..679ccfb8de3a 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -574,16 +574,16 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { if let Some(items) = &attr.meta_item_list() - && let Some(ident) = attr.ident() + && let Some(name) = attr.name() { - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + if matches!(name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { allow_attributes::check(cx, attr); } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes_without_reason::check(cx, ident.name, items, attr); + if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes_without_reason::check(cx, name, items, attr); } - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); + if is_lint_level(name, attr.id) { + blanket_clippy_restriction_lints::check(cx, name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { return; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..aa9a6654bee3 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() - && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) + && attr.name().is_some_and(|name| is_lint_level(name, attr.id)) { for lint in lint_list { match item.kind { diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index c3bc9048c23a..28ea2e4fa1f0 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -270,7 +270,7 @@ fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { cx.tcx.hir_attrs(id).iter().any(|attr| { matches!( - attr.ident().map(|ident| ident.name), + attr.name(), Some(sym::cfg_trace | sym::cfg_attr_trace) ) }) diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index ac221743cfd6..375b275cd113 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -287,8 +287,8 @@ 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 => + if let [name] = &*attr.path.segments + && *name == sym::doc => { matches!(attr.args, AttrArgs::Eq { .. }) }, diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2fd773b06781..94e4ede14048 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -20,10 +20,11 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( name: Symbol, ) -> impl Iterator { attrs.iter().filter(move |attr| { - if let Some([clippy, segment2]) = attr.ident_path().as_deref() - && clippy.name == sym::clippy + if let [clippy, segment2] = &*attr.path() + && *clippy == sym::clippy { - let new_name = match segment2.name { + let path_span = attr.path_span().expect("Clippy attributes are unparsed and have a span"); + let new_name = match *segment2 { sym::cyclomatic_complexity => Some("cognitive_complexity"), sym::author | sym::version @@ -35,7 +36,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( | sym::has_significant_drop | sym::format_args => None, _ => { - sess.dcx().span_err(segment2.span, "usage of unknown attribute"); + sess.dcx().span_err(path_span, "usage of unknown attribute"); return false; }, }; @@ -43,17 +44,17 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>( match new_name { Some(new_name) => { sess.dcx() - .struct_span_err(segment2.span, "usage of deprecated attribute") + .struct_span_err(path_span, "usage of deprecated attribute") .with_span_suggestion( - segment2.span, + path_span, "consider using", - new_name, + format!("clippy::{}", new_name), Applicability::MachineApplicable, ) .emit(); false }, - None => segment2.name == name, + None => *segment2 == name, } } else { false diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index d9254fca9453..7fb8616072a5 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -348,9 +348,9 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { match attr.kind { AttrKind::Normal(..) => { - if let Some(ident) = attr.ident() { + if let Some(name) = attr.name() { // NOTE: This will likely have false positives, like `allow = 1` - let ident_string = ident.to_string(); + let ident_string = name.to_string(); if attr.style == AttrStyle::Outer { ( Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]), diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr index fb51313dab69..0ebc43739d6b 100644 --- a/tests/ui/renamed_builtin_attr.stderr +++ b/tests/ui/renamed_builtin_attr.stderr @@ -1,8 +1,8 @@ error: usage of deprecated attribute - --> tests/ui/renamed_builtin_attr.rs:3:11 + --> tests/ui/renamed_builtin_attr.rs:3:3 | LL | #[clippy::cyclomatic_complexity = "1"] - | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity` error: aborting due to 1 previous error diff --git a/tests/ui/unknown_attribute.stderr b/tests/ui/unknown_attribute.stderr index b306abe0a9d1..1d4d50ffc02a 100644 --- a/tests/ui/unknown_attribute.stderr +++ b/tests/ui/unknown_attribute.stderr @@ -1,8 +1,8 @@ error: usage of unknown attribute - --> tests/ui/unknown_attribute.rs:3:11 + --> tests/ui/unknown_attribute.rs:3:3 | LL | #[clippy::unknown] - | ^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From f186dadb0dee2a1065743e76bf0be99dd4046926 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:22:16 +0100 Subject: [PATCH 019/340] compiletest: Use `DirectiveLine` also for debuginfo (read: debugger) tests This not only reduces code duplication already, it also gives us revision parsing for free which we need in an upcoming commit. --- src/tools/compiletest/src/directives.rs | 3 +- src/tools/compiletest/src/runtest/debugger.rs | 28 +++++++------------ 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index d1e0c5d95001..5865954558d8 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -15,7 +15,7 @@ use crate::directives::directive_names::{ }; pub(crate) use crate::directives::file::FileDirectives; use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP; -use crate::directives::line::{DirectiveLine, line_directive}; +use crate::directives::line::DirectiveLine; use crate::directives::needs::CachedNeedsConditions; use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; @@ -29,6 +29,7 @@ mod directive_names; mod file; mod handlers; mod line; +pub(crate) use line::line_directive; mod line_number; pub(crate) use line_number::LineNumber; mod needs; diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index c83e00c1006e..64b969f11059 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,7 +4,7 @@ use std::io::{BufRead, BufReader}; use camino::{Utf8Path, Utf8PathBuf}; -use crate::directives::LineNumber; +use crate::directives::{LineNumber, line_directive}; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -37,15 +37,19 @@ impl DebuggerCommands { continue; } - let Some(line) = line.trim_start().strip_prefix("//@").map(str::trim_start) else { + let Some(directive) = line_directive(file, line_number, &line) else { continue; }; - if let Some(command) = parse_name_value(&line, &command_directive) { - commands.push(command); + if directive.name == command_directive + && let Some(command) = directive.value_after_colon() + { + commands.push(command.to_string()); } - if let Some(pattern) = parse_name_value(&line, &check_directive) { - check_lines.push((line_number, pattern)); + if directive.name == check_directive + && let Some(pattern) = directive.value_after_colon() + { + check_lines.push((line_number, pattern.to_string())); } } @@ -103,18 +107,6 @@ impl DebuggerCommands { } } -/// Split off from the main `parse_name_value_directive`, so that improvements -/// to directive handling aren't held back by debuginfo test commands. -fn parse_name_value(line: &str, name: &str) -> Option { - if let Some(after_name) = line.strip_prefix(name) - && let Some(value) = after_name.strip_prefix(':') - { - Some(value.to_owned()) - } else { - None - } -} - /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match. fn check_single_line(line: &str, check_line: &str) -> bool { // Allow check lines to leave parts unspecified (e.g., uninitialized From 4516daccb36711f2d4536561762ed49281c2a0e8 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:41:05 +0100 Subject: [PATCH 020/340] compiletest: Support revisions in debuginfo (read: debugger) tests --- src/tools/compiletest/src/runtest/debugger.rs | 26 ++++++++++++++++--- .../compiletest/src/runtest/debuginfo.rs | 6 ++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 64b969f11059..70996004a336 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -17,10 +17,16 @@ pub(super) struct DebuggerCommands { check_lines: Vec<(LineNumber, String)>, /// Source file name file: Utf8PathBuf, + /// The revision being tested, if any + revision: Option, } impl DebuggerCommands { - pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result { + pub fn parse_from( + file: &Utf8Path, + debugger_prefix: &str, + test_revision: Option<&str>, + ) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -41,6 +47,10 @@ impl DebuggerCommands { continue; }; + if !directive.applies_to_test_revision(test_revision) { + continue; + } + if directive.name == command_directive && let Some(command) = directive.value_after_colon() { @@ -53,7 +63,13 @@ impl DebuggerCommands { } } - Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() }) + Ok(Self { + commands, + breakpoint_lines, + check_lines, + file: file.to_path_buf(), + revision: test_revision.map(str::to_owned), + }) } /// Given debugger output and lines to check, ensure that every line is @@ -85,9 +101,11 @@ impl DebuggerCommands { Ok(()) } else { let fname = self.file.file_name().unwrap(); + let revision_suffix = + self.revision.as_ref().map_or(String::new(), |r| format!("#{}", r)); let mut msg = format!( - "check directive(s) from `{}` not found in debugger output. errors:", - self.file + "check directive(s) from `{}{}` not found in debugger output. errors:", + self.file, revision_suffix ); for (src_lineno, err_line) in missing { diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 83b61b9be57d..9d6edaddc1b7 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -46,7 +46,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands @@ -105,7 +105,7 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test(&self) { - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); @@ -366,7 +366,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: From 423a8dc4090a47589a61e30a139731eb500892db Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 11:49:04 +0100 Subject: [PATCH 021/340] tests/debuginfo/macro-stepping.rs: Add revisions `default-mir-passes`, `no-SingleUseConsts-mir-pass` To prevent the test from regressing both with and without `SingleUseConsts` MIR pass. --- tests/debuginfo/macro-stepping.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs index 0dff383be825..ba3a4452041a 100644 --- a/tests/debuginfo/macro-stepping.rs +++ b/tests/debuginfo/macro-stepping.rs @@ -14,8 +14,10 @@ #[macro_use] extern crate macro_stepping; // exports new_scope!() -//@ compile-flags:-g -Zmir-enable-passes=-SingleUseConsts -// SingleUseConsts shouldn't need to be disabled, see #128945 +//@ compile-flags: -g +// FIXME(#128945): SingleUseConsts shouldn't need to be disabled. +//@ revisions: default-mir-passes no-SingleUseConsts-mir-pass +//@ [no-SingleUseConsts-mir-pass] compile-flags: -Zmir-enable-passes=-SingleUseConsts // === GDB TESTS =================================================================================== @@ -48,7 +50,7 @@ extern crate macro_stepping; // exports new_scope!() //@ gdb-check:[...]#inc-loc2[...] //@ gdb-command:next //@ gdb-command:frame -//@ gdb-check:[...]#inc-loc3[...] +//@ [no-SingleUseConsts-mir-pass] gdb-check:[...]#inc-loc3[...] // === LLDB TESTS ================================================================================== From bc943aa8ea5aad5690eef4594ad50da949c181fb Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 22:55:19 +0000 Subject: [PATCH 022/340] fix: `checked_conversions` wrongly unmangled macros --- clippy_lints/src/checked_conversions.rs | 5 +-- tests/ui/checked_conversions.fixed | 16 ++++++++++ tests/ui/checked_conversions.rs | 16 ++++++++++ tests/ui/checked_conversions.stderr | 42 ++++++++++++++----------- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 9b3822f9d8f0..8303897d1294 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -1,7 +1,7 @@ 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::source::snippet_with_context; use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; @@ -80,7 +80,8 @@ impl LateLintPass<'_> for CheckedConversions { && self.msrv.meets(cx, msrvs::TRY_FROM) { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, cv.expr_to_cast.span, item.span.ctxt(), "_", &mut applicability); span_lint_and_sugg( cx, CHECKED_CONVERSIONS, diff --git a/tests/ui/checked_conversions.fixed b/tests/ui/checked_conversions.fixed index 6175275ef047..2309a053146f 100644 --- a/tests/ui/checked_conversions.fixed +++ b/tests/ui/checked_conversions.fixed @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + i32::try_from(dot_inner!(outer)).is_ok(); + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.rs b/tests/ui/checked_conversions.rs index 9ed0e8f660d0..dabb552eba27 100644 --- a/tests/ui/checked_conversions.rs +++ b/tests/ui/checked_conversions.rs @@ -1,6 +1,7 @@ #![allow( clippy::cast_lossless, clippy::legacy_numeric_constants, + clippy::no_effect, unused, // Int::max_value will be deprecated in the future deprecated, @@ -105,4 +106,19 @@ fn msrv_1_34() { //~^ checked_conversions } +fn issue16293() { + struct Outer { + inner: u32, + } + let outer = Outer { inner: 42 }; + macro_rules! dot_inner { + ($obj:expr) => { + $obj.inner + }; + } + + dot_inner!(outer) <= i32::MAX as u32; + //~^ checked_conversions +} + fn main() {} diff --git a/tests/ui/checked_conversions.stderr b/tests/ui/checked_conversions.stderr index 624876dacb26..6018dacace39 100644 --- a/tests/ui/checked_conversions.stderr +++ b/tests/ui/checked_conversions.stderr @@ -1,5 +1,5 @@ error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:15:13 + --> tests/ui/checked_conversions.rs:16:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` @@ -8,100 +8,106 @@ LL | let _ = value <= (u32::max_value() as i64) && value >= 0; = help: to override `-D warnings` add `#[allow(clippy::checked_conversions)]` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:17:13 + --> tests/ui/checked_conversions.rs:18:13 | LL | let _ = value <= (u32::MAX as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:22:13 + --> tests/ui/checked_conversions.rs:23:13 | LL | let _ = value <= i64::from(u16::max_value()) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:24:13 + --> tests/ui/checked_conversions.rs:25:13 | LL | let _ = value <= i64::from(u16::MAX) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:29:13 + --> tests/ui/checked_conversions.rs:30:13 | LL | let _ = value <= (u8::max_value() as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:31:13 + --> tests/ui/checked_conversions.rs:32:13 | LL | let _ = value <= (u8::MAX as isize) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:38:13 + --> tests/ui/checked_conversions.rs:39:13 | LL | let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:40:13 + --> tests/ui/checked_conversions.rs:41:13 | LL | let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:45:13 + --> tests/ui/checked_conversions.rs:46:13 | LL | let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:47:13 + --> tests/ui/checked_conversions.rs:48:13 | LL | let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:54:13 + --> tests/ui/checked_conversions.rs:55:13 | LL | let _ = value <= i32::max_value() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:56:13 + --> tests/ui/checked_conversions.rs:57:13 | LL | let _ = value <= i32::MAX as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:61:13 + --> tests/ui/checked_conversions.rs:62:13 | LL | let _ = value <= isize::max_value() as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:63:13 + --> tests/ui/checked_conversions.rs:64:13 | LL | let _ = value <= isize::MAX as usize && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:68:13 + --> tests/ui/checked_conversions.rs:69:13 | LL | let _ = value <= u16::max_value() as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:70:13 + --> tests/ui/checked_conversions.rs:71:13 | LL | let _ = value <= u16::MAX as u32 && value as i32 == 5; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()` error: checked cast can be simplified - --> tests/ui/checked_conversions.rs:104:13 + --> tests/ui/checked_conversions.rs:105:13 | LL | let _ = value <= (u32::max_value() as i64) && value >= 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()` -error: aborting due to 17 previous errors +error: checked cast can be simplified + --> tests/ui/checked_conversions.rs:120:5 + | +LL | dot_inner!(outer) <= i32::MAX as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(dot_inner!(outer)).is_ok()` + +error: aborting due to 18 previous errors From ffbdb578b0e6e9d4657abbd3d6454bde4bed1869 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:08:32 +0000 Subject: [PATCH 023/340] fix: `manual_ignore_case_cmp` wrongly unmangled macros --- clippy_lints/src/manual_ignore_case_cmp.rs | 10 ++++----- tests/ui/manual_ignore_case_cmp.fixed | 20 +++++++++++++++++ tests/ui/manual_ignore_case_cmp.rs | 20 +++++++++++++++++ tests/ui/manual_ignore_case_cmp.stderr | 26 +++++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs index 25057b4aeaa2..1c20a8f81efb 100644 --- a/clippy_lints/src/manual_ignore_case_cmp.rs +++ b/clippy_lints/src/manual_ignore_case_cmp.rs @@ -1,7 +1,7 @@ use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -111,14 +111,12 @@ impl LateLintPass<'_> for ManualIgnoreCaseCmp { "manual case-insensitive ASCII comparison", |diag| { let mut app = Applicability::MachineApplicable; + let (left_snip, _) = snippet_with_context(cx, left_span, expr.span.ctxt(), "..", &mut app); + let (right_snip, _) = snippet_with_context(cx, right_span, expr.span.ctxt(), "..", &mut app); diag.span_suggestion_verbose( expr.span, "consider using `.eq_ignore_ascii_case()` instead", - format!( - "{neg}{}.eq_ignore_ascii_case({deref}{})", - snippet_with_applicability(cx, left_span, "_", &mut app), - snippet_with_applicability(cx, right_span, "_", &mut app) - ), + format!("{neg}{left_snip}.eq_ignore_ascii_case({deref}{right_snip})"), app, ); }, diff --git a/tests/ui/manual_ignore_case_cmp.fixed b/tests/ui/manual_ignore_case_cmp.fixed index cd7adc20b127..f0e413aaec0d 100644 --- a/tests/ui/manual_ignore_case_cmp.fixed +++ b/tests/ui/manual_ignore_case_cmp.fixed @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.eq_ignore_ascii_case(a); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + //~^ manual_ignore_case_cmp + || dot_inner!(a).eq_ignore_ascii_case("abc") + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.rs b/tests/ui/manual_ignore_case_cmp.rs index 85f6719827c9..9802e87cd233 100644 --- a/tests/ui/manual_ignore_case_cmp.rs +++ b/tests/ui/manual_ignore_case_cmp.rs @@ -160,3 +160,23 @@ fn ref_osstring(a: OsString, b: &OsString) { b.to_ascii_lowercase() == a.to_ascii_lowercase(); //~^ manual_ignore_case_cmp } + +fn wrongly_unmangled_macros(a: &str, b: &str) -> bool { + struct S<'a> { + inner: &'a str, + } + + let a = S { inner: a }; + let b = S { inner: b }; + + macro_rules! dot_inner { + ($s:expr) => { + $s.inner + }; + } + + dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + //~^ manual_ignore_case_cmp + || dot_inner!(a).to_ascii_lowercase() == "abc" + //~^ manual_ignore_case_cmp +} diff --git a/tests/ui/manual_ignore_case_cmp.stderr b/tests/ui/manual_ignore_case_cmp.stderr index fa7fadd91076..2f698e076ed3 100644 --- a/tests/ui/manual_ignore_case_cmp.stderr +++ b/tests/ui/manual_ignore_case_cmp.stderr @@ -588,5 +588,29 @@ LL - b.to_ascii_lowercase() == a.to_ascii_lowercase(); LL + b.eq_ignore_ascii_case(a); | -error: aborting due to 49 previous errors +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:178:5 + | +LL | dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - dot_inner!(a).to_ascii_lowercase() == dot_inner!(b).to_ascii_lowercase() +LL + dot_inner!(a).eq_ignore_ascii_case(dot_inner!(b)) + | + +error: manual case-insensitive ASCII comparison + --> tests/ui/manual_ignore_case_cmp.rs:180:12 + | +LL | || dot_inner!(a).to_ascii_lowercase() == "abc" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using `.eq_ignore_ascii_case()` instead + | +LL - || dot_inner!(a).to_ascii_lowercase() == "abc" +LL + || dot_inner!(a).eq_ignore_ascii_case("abc") + | + +error: aborting due to 51 previous errors From d30647b7f2085dd073f756aca40cf965b060921a Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:13:13 +0000 Subject: [PATCH 024/340] fix: `manual_ilog2` wrongly unmangled macros --- clippy_lints/src/manual_ilog2.rs | 4 ++-- tests/ui/manual_ilog2.fixed | 17 +++++++++++++++++ tests/ui/manual_ilog2.rs | 17 +++++++++++++++++ tests/ui/manual_ilog2.stderr | 14 +++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/manual_ilog2.rs b/clippy_lints/src/manual_ilog2.rs index 1c61db530606..4b411a60f3bf 100644 --- a/clippy_lints/src/manual_ilog2.rs +++ b/clippy_lints/src/manual_ilog2.rs @@ -1,7 +1,7 @@ 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::source::snippet_with_context; use clippy_utils::{is_from_proc_macro, sym}; use rustc_ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -102,7 +102,7 @@ impl LateLintPass<'_> for ManualIlog2 { fn emit(cx: &LateContext<'_>, recv: &Expr<'_>, full_expr: &Expr<'_>) { let mut app = Applicability::MachineApplicable; - let recv = snippet_with_applicability(cx, recv.span, "_", &mut app); + let (recv, _) = snippet_with_context(cx, recv.span, full_expr.span.ctxt(), "_", &mut app); span_lint_and_sugg( cx, MANUAL_ILOG2, diff --git a/tests/ui/manual_ilog2.fixed b/tests/ui/manual_ilog2.fixed index a0f6d9392c30..ea86fc927c7c 100644 --- a/tests/ui/manual_ilog2.fixed +++ b/tests/ui/manual_ilog2.fixed @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = access!(x).ilog2(); + //~^ manual_ilog2 + let log = access!(x).ilog2(); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.rs b/tests/ui/manual_ilog2.rs index bd4b5d9d3c0d..8cb0e12d7361 100644 --- a/tests/ui/manual_ilog2.rs +++ b/tests/ui/manual_ilog2.rs @@ -30,3 +30,20 @@ fn foo(a: u32, b: u64) { external!($a.ilog(2)); with_span!(span; a.ilog(2)); } + +fn wrongly_unmangled_macros() { + struct S { + inner: u32, + } + + let x = S { inner: 42 }; + macro_rules! access { + ($s:expr) => { + $s.inner + }; + } + let log = 31 - access!(x).leading_zeros(); + //~^ manual_ilog2 + let log = access!(x).ilog(2); + //~^ manual_ilog2 +} diff --git a/tests/ui/manual_ilog2.stderr b/tests/ui/manual_ilog2.stderr index 7c9694f35330..d0ef8378081a 100644 --- a/tests/ui/manual_ilog2.stderr +++ b/tests/ui/manual_ilog2.stderr @@ -19,5 +19,17 @@ error: manually reimplementing `ilog2` LL | 63 - b.leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `b.ilog2()` -error: aborting due to 3 previous errors +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:45:15 + | +LL | let log = 31 - access!(x).leading_zeros(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: manually reimplementing `ilog2` + --> tests/ui/manual_ilog2.rs:47:15 + | +LL | let log = access!(x).ilog(2); + | ^^^^^^^^^^^^^^^^^^ help: try: `access!(x).ilog2()` + +error: aborting due to 5 previous errors From 01b39655df52597ddf31c0e243d3bfbdbf3a0be0 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 23 Dec 2025 23:53:17 +0000 Subject: [PATCH 025/340] fix: `needless_bool_assign` wrongly unmangled macros --- clippy_lints/src/needless_bool.rs | 6 +++--- tests/ui/needless_bool_assign.fixed | 19 +++++++++++++++++++ tests/ui/needless_bool_assign.rs | 23 +++++++++++++++++++++++ tests/ui/needless_bool_assign.stderr | 12 +++++++++++- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 854e927aa2f7..6b5db9dcf3e2 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_parent_stmt, is_receiver_of_method_call, @@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; - let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); - let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability); + let cond = Sugg::hir_with_context(cx, cond, e.span.ctxt(), "..", &mut applicability); + let (lhs, _) = snippet_with_context(cx, lhs_a.span, e.span.ctxt(), "..", &mut applicability); let mut sugg = if a == b { format!("{cond}; {lhs} = {a:?};") } else { diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed index d6fab4c51b53..8fd572038140 100644 --- a/tests/ui/needless_bool_assign.fixed +++ b/tests/ui/needless_bool_assign.fixed @@ -42,3 +42,22 @@ fn issue15063(x: bool, y: bool) { } else { z = x || y; } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + dot_0!(skip) = !invoke!(must_keep, x, y); + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs index c504f61f4dd1..4721ab433b32 100644 --- a/tests/ui/needless_bool_assign.rs +++ b/tests/ui/needless_bool_assign.rs @@ -58,3 +58,26 @@ fn issue15063(x: bool, y: bool) { } //~^^^^^ needless_bool_assign } + +fn wrongly_unmangled_macros(must_keep: fn(usize, usize) -> bool, x: usize, y: usize) { + struct Wrapper(T); + let mut skip = Wrapper(false); + + macro_rules! invoke { + ($func:expr, $a:expr, $b:expr) => { + $func($a, $b) + }; + } + macro_rules! dot_0 { + ($w:expr) => { + $w.0 + }; + } + + if invoke!(must_keep, x, y) { + dot_0!(skip) = false; + } else { + dot_0!(skip) = true; + } + //~^^^^^ needless_bool_assign +} diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr index 1d09b8b25a09..34ff782f34a3 100644 --- a/tests/ui/needless_bool_assign.stderr +++ b/tests/ui/needless_bool_assign.stderr @@ -62,5 +62,15 @@ LL | | z = false; LL | | } | |_____^ help: you can reduce it to: `{ z = x || y; }` -error: aborting due to 5 previous errors +error: this if-then-else expression assigns a bool literal + --> tests/ui/needless_bool_assign.rs:77:5 + | +LL | / if invoke!(must_keep, x, y) { +LL | | dot_0!(skip) = false; +LL | | } else { +LL | | dot_0!(skip) = true; +LL | | } + | |_____^ help: you can reduce it to: `dot_0!(skip) = !invoke!(must_keep, x, y);` + +error: aborting due to 6 previous errors From 21eaa04df821f0c716a9cbca2e502aef50e4d2e3 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 24 Dec 2025 00:09:43 +0000 Subject: [PATCH 026/340] fix: `needless_for_each` FN when `for_each` is in the expr of a block --- clippy_lints/src/needless_for_each.rs | 125 ++++++++++++---------- tests/ui/needless_for_each_fixable.fixed | 8 ++ tests/ui/needless_for_each_fixable.rs | 8 ++ tests/ui/needless_for_each_fixable.stderr | 19 +++- 4 files changed, 105 insertions(+), 55 deletions(-) diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index d03188f1d39b..55a5a16c0099 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -56,8 +56,20 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]); impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind + if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind { + check_expr(cx, expr, stmt.span); + } + } + + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + if let Some(expr) = block.expr { + check_expr(cx, expr, expr.span); + } + } +} + +fn check_expr(cx: &LateContext<'_>, expr: &Expr<'_>, outer_span: Span) { + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind && let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. @@ -76,69 +88,74 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}` // and suggesting `for … in … { unsafe { } }` is a little ugly. && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..)) + { + let mut applicability = Applicability::MachineApplicable; + + // If any closure parameter has an explicit type specified, applying the lint would necessarily + // remove that specification, possibly breaking type inference + if fn_decl + .inputs + .iter() + .any(|input| matches!(input.kind, TyKind::Infer(..))) { - let mut applicability = Applicability::MachineApplicable; + applicability = Applicability::MaybeIncorrect; + } - // If any closure parameter has an explicit type specified, applying the lint would necessarily - // remove that specification, possibly breaking type inference - if fn_decl - .inputs - .iter() - .any(|input| matches!(input.kind, TyKind::Infer(..))) - { - applicability = Applicability::MaybeIncorrect; - } + let mut ret_collector = RetCollector::default(); + ret_collector.visit_expr(body.value); - let mut ret_collector = RetCollector::default(); - ret_collector.visit_expr(body.value); + // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. + if ret_collector.ret_in_loop { + return; + } - // Skip the lint if `return` is used in `Loop` in order not to suggest using `'label`. - if ret_collector.ret_in_loop { - return; - } + let ret_suggs = if ret_collector.spans.is_empty() { + None + } else { + applicability = Applicability::MaybeIncorrect; + Some( + ret_collector + .spans + .into_iter() + .map(|span| (span, "continue".to_string())) + .collect(), + ) + }; - let ret_suggs = if ret_collector.spans.is_empty() { - None + let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); + let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); + let (body_value_sugg, is_macro_call) = + snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); + + let sugg = format!( + "for {} in {} {}", + body_param_sugg, + for_each_rev_sugg, + if is_macro_call { + format!("{{ {body_value_sugg}; }}") } else { - applicability = Applicability::MaybeIncorrect; - Some( - ret_collector - .spans - .into_iter() - .map(|span| (span, "continue".to_string())) - .collect(), - ) - }; - - let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability); - let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability); - let (body_value_sugg, is_macro_call) = - snippet_with_context(cx, body.value.span, for_each_recv.span.ctxt(), "..", &mut applicability); - - let sugg = format!( - "for {} in {} {}", - body_param_sugg, - for_each_rev_sugg, - if is_macro_call { - format!("{{ {body_value_sugg}; }}") - } else { - match body.value.kind { - ExprKind::Block(block, _) if is_let_desugar(block) => { - format!("{{ {body_value_sugg} }}") - }, - ExprKind::Block(_, _) => body_value_sugg.to_string(), - _ => format!("{{ {body_value_sugg}; }}"), - } + match body.value.kind { + ExprKind::Block(block, _) if is_let_desugar(block) => { + format!("{{ {body_value_sugg} }}") + }, + ExprKind::Block(_, _) => body_value_sugg.to_string(), + _ => format!("{{ {body_value_sugg}; }}"), } - ); + } + ); - span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| { - diag.span_suggestion(stmt.span, "try", sugg, applicability); + span_lint_and_then( + cx, + NEEDLESS_FOR_EACH, + outer_span, + "needless use of `for_each`", + |diag| { + diag.span_suggestion(outer_span, "try", sugg, applicability); if let Some(ret_suggs) = ret_suggs { diag.multipart_suggestion("...and replace `return` with `continue`", ret_suggs, applicability); } - }); - } + }, + ); } } diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed index a6d64d9afc1a..19b34f42af24 100644 --- a/tests/ui/needless_for_each_fixable.fixed +++ b/tests/ui/needless_for_each_fixable.fixed @@ -149,3 +149,11 @@ fn issue15256() { for v in vec.iter() { println!("{v}"); } //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + for elem in vec.iter() { + //~^ needless_for_each + println!("{elem}"); + } +} diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs index 7e74d2b428fd..f04e2555a370 100644 --- a/tests/ui/needless_for_each_fixable.rs +++ b/tests/ui/needless_for_each_fixable.rs @@ -149,3 +149,11 @@ fn issue15256() { vec.iter().for_each(|v| println!("{v}")); //~^ needless_for_each } + +fn issue16294() { + let vec: Vec = Vec::new(); + vec.iter().for_each(|elem| { + //~^ needless_for_each + println!("{elem}"); + }) +} diff --git a/tests/ui/needless_for_each_fixable.stderr b/tests/ui/needless_for_each_fixable.stderr index 204cfa36b022..121669d15072 100644 --- a/tests/ui/needless_for_each_fixable.stderr +++ b/tests/ui/needless_for_each_fixable.stderr @@ -154,5 +154,22 @@ error: needless use of `for_each` LL | vec.iter().for_each(|v| println!("{v}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for v in vec.iter() { println!("{v}"); }` -error: aborting due to 11 previous errors +error: needless use of `for_each` + --> tests/ui/needless_for_each_fixable.rs:155:5 + | +LL | / vec.iter().for_each(|elem| { +LL | | +LL | | println!("{elem}"); +LL | | }) + | |______^ + | +help: try + | +LL ~ for elem in vec.iter() { +LL + +LL + println!("{elem}"); +LL + } + | + +error: aborting due to 12 previous errors From 6bc65090756d6d81d3414fdc50f856ea45a24046 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 24 Dec 2025 00:21:23 +0000 Subject: [PATCH 027/340] fix: `manual_is_multiple_of` wrongly unmangled macros --- .../src/operators/manual_is_multiple_of.rs | 4 ++-- tests/ui/manual_is_multiple_of.fixed | 16 ++++++++++++++++ tests/ui/manual_is_multiple_of.rs | 16 ++++++++++++++++ tests/ui/manual_is_multiple_of.stderr | 8 +++++++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/operators/manual_is_multiple_of.rs b/clippy_lints/src/operators/manual_is_multiple_of.rs index 0b9bd4fb6d32..291d81097b51 100644 --- a/clippy_lints/src/operators/manual_is_multiple_of.rs +++ b/clippy_lints/src/operators/manual_is_multiple_of.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( { let mut app = Applicability::MachineApplicable; let divisor = deref_sugg( - Sugg::hir_with_applicability(cx, operand_right, "_", &mut app), + Sugg::hir_with_context(cx, operand_right, expr.span.ctxt(), "_", &mut app), cx.typeck_results().expr_ty_adjusted(operand_right), ); span_lint_and_sugg( @@ -47,7 +47,7 @@ pub(super) fn check<'tcx>( format!( "{}{}.is_multiple_of({divisor})", if op == BinOpKind::Eq { "" } else { "!" }, - Sugg::hir_with_applicability(cx, operand_left, "_", &mut app).maybe_paren() + Sugg::hir_with_context(cx, operand_left, expr.span.ctxt(), "_", &mut app).maybe_paren() ), app, ); diff --git a/tests/ui/manual_is_multiple_of.fixed b/tests/ui/manual_is_multiple_of.fixed index 03f75e725ed5..82e0684e5e57 100644 --- a/tests/ui/manual_is_multiple_of.fixed +++ b/tests/ui/manual_is_multiple_of.fixed @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a).is_multiple_of(dot_0!(b)) { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.rs b/tests/ui/manual_is_multiple_of.rs index 7b6fa64c843d..82a492e24092 100644 --- a/tests/ui/manual_is_multiple_of.rs +++ b/tests/ui/manual_is_multiple_of.rs @@ -101,3 +101,19 @@ mod issue15103 { (1..1_000).filter(|&i| i == d(d(i)) && i != d(i)).sum() } } + +fn wrongly_unmangled_macros(a: u32, b: u32) { + struct Wrapper(u32); + let a = Wrapper(a); + let b = Wrapper(b); + macro_rules! dot_0 { + ($x:expr) => { + $x.0 + }; + } + + if dot_0!(a) % dot_0!(b) == 0 { + //~^ manual_is_multiple_of + todo!() + } +} diff --git a/tests/ui/manual_is_multiple_of.stderr b/tests/ui/manual_is_multiple_of.stderr index 8523599ec402..3aba869c9111 100644 --- a/tests/ui/manual_is_multiple_of.stderr +++ b/tests/ui/manual_is_multiple_of.stderr @@ -67,5 +67,11 @@ error: manual implementation of `.is_multiple_of()` LL | let d = |n: u32| -> u32 { (1..=n / 2).filter(|i| n % i == 0).sum() }; | ^^^^^^^^^^ help: replace with: `n.is_multiple_of(*i)` -error: aborting due to 11 previous errors +error: manual implementation of `.is_multiple_of()` + --> tests/ui/manual_is_multiple_of.rs:115:8 + | +LL | if dot_0!(a) % dot_0!(b) == 0 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `dot_0!(a).is_multiple_of(dot_0!(b))` + +error: aborting due to 12 previous errors From 9f7dc2e474081a2a79c756abddf4dc367cc1d8cf Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 21 Dec 2025 20:49:36 +0000 Subject: [PATCH 028/340] Extract version check from ensure_version_or_cargo_install Define a new function ensure_version which is extracted (and modified) from ensure_version_or_cargo_install. --- src/tools/tidy/src/lib.rs | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 756f9790e04a..1bbea81ff0fb 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -158,6 +158,27 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } +/// Check if the given executable is installed and the version is expected. +pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Result { + let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); + + match Command::new(&bin_path).arg("--version").output() { + Ok(output) => { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() else { + return Err(io::Error::other("version check failed")); + }; + + if v != version { + eprintln!( + "warning: the tool `{bin_name}` is detected, but version {v} doesn't match with the expected version {version}" + ); + } + Ok(bin_path) + } + Err(e) => Err(e), + } +} + /// If the given executable is installed with the given version, use that, /// otherwise install via cargo. pub fn ensure_version_or_cargo_install( @@ -167,30 +188,16 @@ pub fn ensure_version_or_cargo_install( bin_name: &str, version: &str, ) -> io::Result { + if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { + return Ok(bin_path); + } + + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + let tool_root_dir = build_dir.join("misc-tools"); let tool_bin_dir = tool_root_dir.join("bin"); let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); - // ignore the process exit code here and instead just let the version number check fail. - // we also importantly don't return if the program wasn't installed, - // instead we want to continue to the fallback. - 'ck: { - // FIXME: rewrite as if-let chain once this crate is 2024 edition. - let Ok(output) = Command::new(&bin_path).arg("--version").output() else { - break 'ck; - }; - let Ok(s) = str::from_utf8(&output.stdout) else { - break 'ck; - }; - let Some(v) = s.trim().split_whitespace().last() else { - break 'ck; - }; - if v == version { - return Ok(bin_path); - } - } - - eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); // use --force to ensure that if the required version is bumped, we update it. // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. // modify PATH so that cargo doesn't print a warning telling the user to modify the path. From b305a98349e2d661bc6169b33cdc1699557de8df Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 21 Dec 2025 20:49:41 +0000 Subject: [PATCH 029/340] implpement if_installed for spellcheck for other extra checks, it is WIP. --- src/tools/tidy/src/extra_checks/mod.rs | 65 ++++++++++++++++++++++---- src/tools/tidy/src/lib.rs | 3 +- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index a45af7fcf158..1304de16874d 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -23,8 +23,8 @@ use std::process::Command; use std::str::FromStr; use std::{fmt, fs, io}; -use crate::CiInfo; use crate::diagnostics::TidyCtx; +use crate::{CiInfo, ensure_version}; mod rustdoc_js; @@ -43,6 +43,7 @@ const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"]; +const SPELLCHECK_VER: &str = "1.38.1"; pub fn check( root_path: &Path, @@ -120,6 +121,9 @@ fn check_impl( ck.is_non_auto_or_matches(path) }); } + if lint_args.iter().any(|ck| ck.if_installed) { + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(outdir)); + } macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -620,8 +624,13 @@ fn spellcheck_runner( cargo: &Path, args: &[&str], ) -> Result<(), Error> { - let bin_path = - crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.38.1")?; + let bin_path = crate::ensure_version_or_cargo_install( + outdir, + cargo, + "typos-cli", + "typos", + SPELLCHECK_VER, + )?; match Command::new(bin_path).current_dir(src_root).args(args).status() { Ok(status) => { if status.success() { @@ -736,10 +745,14 @@ enum ExtraCheckParseError { Empty, /// `auto` specified without lang part. AutoRequiresLang, + /// `if-installed` specified without lang part. + IfInsatlledRequiresLang, } struct ExtraCheckArg { auto: bool, + /// Only run the check if the requisite software is already installed. + if_installed: bool, lang: ExtraCheckLang, /// None = run all extra checks for the given lang kind: Option, @@ -750,6 +763,19 @@ impl ExtraCheckArg { self.lang == lang && self.kind.map(|k| k == kind).unwrap_or(true) } + fn is_non_if_installed_or_matches(&self, build_dir: &Path) -> bool { + if !self.if_installed { + return true; + } + + match self.lang { + ExtraCheckLang::Spellcheck => { + ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() + } + _ => todo!("implement other checks"), + } + } + /// Returns `false` if this is an auto arg and the passed filename does not trigger the auto rule fn is_non_auto_or_matches(&self, filepath: &str) -> bool { if !self.auto { @@ -792,22 +818,41 @@ impl FromStr for ExtraCheckArg { fn from_str(s: &str) -> Result { let mut auto = false; + let mut if_installed = false; let mut parts = s.split(':'); let Some(mut first) = parts.next() else { return Err(ExtraCheckParseError::Empty); }; - if first == "auto" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::AutoRequiresLang); - }; - auto = true; - first = part; + loop { + if !auto && first == "auto" { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::AutoRequiresLang); + }; + auto = true; + first = part; + continue; + } + + if !if_installed && first == "if-installed" { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::IfInsatlledRequiresLang); + }; + if_installed = true; + first = part; + continue; + } + break; } let second = parts.next(); if parts.next().is_some() { return Err(ExtraCheckParseError::TooManyParts); } - let arg = Self { auto, lang: first.parse()?, kind: second.map(|s| s.parse()).transpose()? }; + let arg = Self { + auto, + if_installed, + lang: first.parse()?, + kind: second.map(|s| s.parse()).transpose()?, + }; if !arg.has_supported_kind() { return Err(ExtraCheckParseError::UnsupportedKindForLang); } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 1bbea81ff0fb..62da0191da9e 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -164,7 +164,8 @@ pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Re match Command::new(&bin_path).arg("--version").output() { Ok(output) => { - let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() else { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() + else { return Err(io::Error::other("version check failed")); }; From 54e9e8cd3872be7ccf9e3b04559ea61441f258a8 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 25 Dec 2025 23:24:43 +0100 Subject: [PATCH 030/340] Merge commit '99edcadfd5f6f6e8da34b1ba62774b53f5ca3863' into clippy-subtree-update --- .github/workflows/clippy_dev.yml | 2 +- .github/workflows/clippy_pr.yml | 2 +- .github/workflows/remark.yml | 4 +- CHANGELOG.md | 1 + clippy_dev/Cargo.toml | 1 + clippy_dev/src/lib.rs | 1 - clippy_lints/src/assertions_on_constants.rs | 2 + clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/casts/cast_precision_loss.rs | 22 +- clippy_lints/src/casts/mod.rs | 2 +- clippy_lints/src/casts/needless_type_cast.rs | 66 ++- clippy_lints/src/casts/ref_as_ptr.rs | 16 +- clippy_lints/src/collapsible_if.rs | 18 +- clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/disallowed_methods.rs | 3 + clippy_lints/src/empty_with_brackets.rs | 202 ++++--- clippy_lints/src/entry.rs | 8 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/format_push_string.rs | 209 +++++-- clippy_lints/src/functions/mod.rs | 4 + clippy_lints/src/functions/result.rs | 43 +- clippy_lints/src/if_not_else.rs | 37 +- clippy_lints/src/if_then_some_else_none.rs | 32 +- clippy_lints/src/ifs/branches_sharing_code.rs | 75 ++- clippy_lints/src/implicit_hasher.rs | 23 +- clippy_lints/src/lib.rs | 7 +- clippy_lints/src/loops/for_kv_map.rs | 2 +- clippy_lints/src/loops/mod.rs | 46 +- clippy_lints/src/loops/never_loop.rs | 33 +- .../src/loops/unused_enumerate_index.rs | 12 +- clippy_lints/src/manual_let_else.rs | 2 +- .../src/matches/match_like_matches.rs | 18 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/methods/expect_fun_call.rs | 10 +- clippy_lints/src/methods/iter_count.rs | 31 +- clippy_lints/src/methods/iter_kv_map.rs | 2 +- .../src/methods/join_absolute_paths.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 12 +- clippy_lints/src/methods/needless_collect.rs | 4 +- .../src/methods/obfuscated_if_else.rs | 16 +- clippy_lints/src/methods/or_then_unwrap.rs | 38 +- clippy_lints/src/methods/unnecessary_fold.rs | 179 +++--- .../src/methods/unnecessary_get_then_check.rs | 4 +- .../src/methods/unwrap_expect_used.rs | 24 +- clippy_lints/src/missing_fields_in_debug.rs | 12 +- .../src/multiple_unsafe_ops_per_block.rs | 70 ++- clippy_lints/src/needless_pass_by_ref_mut.rs | 21 +- clippy_lints/src/ptr/cmp_null.rs | 7 +- clippy_lints/src/ptr/mod.rs | 4 +- clippy_lints/src/same_length_and_capacity.rs | 105 ++++ clippy_lints/src/set_contains_or_insert.rs | 21 +- clippy_lints/src/time_subtraction.rs | 65 +- .../src/transmute/transmuting_null.rs | 9 +- clippy_lints/src/use_self.rs | 36 +- clippy_lints/src/write/empty_string.rs | 42 +- clippy_lints/src/zero_sized_map_values.rs | 2 +- .../src/almost_standard_lint_formulation.rs | 35 +- clippy_lints_internal/src/internal_paths.rs | 1 + clippy_lints_internal/src/lib.rs | 2 + .../src/repeated_is_diagnostic_item.rs | 561 ++++++++++++++++++ clippy_utils/README.md | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/consts.rs | 14 +- clippy_utils/src/hir_utils.rs | 233 +++++++- clippy_utils/src/lib.rs | 3 +- clippy_utils/src/source.rs | 4 +- clippy_utils/src/sym.rs | 7 + rust-toolchain.toml | 2 +- .../repeated_is_diagnostic_item.fixed | 77 +++ .../repeated_is_diagnostic_item.rs | 77 +++ .../repeated_is_diagnostic_item.stderr | 82 +++ .../repeated_is_diagnostic_item_unfixable.rs | 213 +++++++ ...peated_is_diagnostic_item_unfixable.stderr | 374 ++++++++++++ .../collapsible_if/collapsible_else_if.fixed | 2 +- .../collapsible_if/collapsible_else_if.rs | 2 +- .../needless_pass_by_ref_mut.fixed | 2 +- .../needless_pass_by_ref_mut.rs | 2 +- .../needless_pass_by_ref_mut.stderr | 6 +- .../toml_disallowed_methods/clippy.toml | 2 + .../conf_disallowed_methods.rs | 16 + .../conf_disallowed_methods.stderr | 8 +- tests/ui/assertions_on_constants.rs | 5 + .../branches_sharing_code/shared_at_bottom.rs | 62 ++ .../shared_at_bottom.stderr | 70 ++- tests/ui/cast.stderr | 12 +- tests/ui/cast_size.r32bit.stderr | 12 +- tests/ui/cast_size.r64bit.stderr | 12 +- tests/ui/cmp_null.fixed | 20 + tests/ui/cmp_null.rs | 20 + tests/ui/cmp_null.stderr | 8 +- tests/ui/collapsible_else_if.fixed | 48 +- tests/ui/collapsible_else_if.rs | 50 +- tests/ui/collapsible_else_if.stderr | 24 +- tests/ui/crashes/ice-10148.stderr | 2 +- tests/ui/crashes/ice-7410.rs | 2 +- tests/ui/def_id_nocore.rs | 2 - tests/ui/def_id_nocore.stderr | 2 +- .../empty_enum_variants_with_brackets.fixed | 59 ++ tests/ui/empty_enum_variants_with_brackets.rs | 59 ++ .../empty_enum_variants_with_brackets.stderr | 67 ++- tests/ui/empty_loop_no_std.rs | 2 - tests/ui/empty_loop_no_std.stderr | 2 +- tests/ui/entry.fixed | 10 + tests/ui/entry.rs | 10 + tests/ui/entry.stderr | 23 +- tests/ui/format_push_string.fixed | 132 +++++ tests/ui/format_push_string.rs | 140 ++++- tests/ui/format_push_string.stderr | 205 +++++-- tests/ui/format_push_string_no_core.rs | 15 + tests/ui/format_push_string_no_std.fixed | 15 + tests/ui/format_push_string_no_std.rs | 15 + tests/ui/format_push_string_no_std.stderr | 17 + .../ui/format_push_string_no_std_unfixable.rs | 13 + ...format_push_string_no_std_unfixable.stderr | 17 + tests/ui/format_push_string_unfixable.rs | 144 +++++ tests/ui/format_push_string_unfixable.stderr | 233 ++++++++ tests/ui/if_not_else.fixed | 17 + tests/ui/if_not_else.rs | 17 + tests/ui/if_not_else.stderr | 44 +- tests/ui/if_then_some_else_none.fixed | 52 +- tests/ui/if_then_some_else_none.rs | 23 + tests/ui/if_then_some_else_none.stderr | 78 ++- tests/ui/manual_instant_elapsed.fixed | 16 + tests/ui/manual_instant_elapsed.rs | 16 + tests/ui/manual_instant_elapsed.stderr | 14 +- tests/ui/map_unwrap_or.stderr | 29 + tests/ui/match_like_matches_macro.fixed | 22 + tests/ui/match_like_matches_macro.rs | 25 + tests/ui/match_like_matches_macro.stderr | 62 +- tests/ui/multiple_unsafe_ops_per_block.rs | 133 +++++ tests/ui/multiple_unsafe_ops_per_block.stderr | 257 ++++++-- tests/ui/needless_collect.fixed | 5 + tests/ui/needless_collect.rs | 5 + tests/ui/needless_pass_by_ref_mut.stderr | 204 ++++--- tests/ui/needless_pass_by_ref_mut2.fixed | 6 + tests/ui/needless_pass_by_ref_mut2.rs | 6 + tests/ui/needless_pass_by_ref_mut2.stderr | 22 +- tests/ui/needless_type_cast.fixed | 87 +++ tests/ui/needless_type_cast.rs | 87 +++ tests/ui/needless_type_cast.stderr | 114 +++- tests/ui/needless_type_cast_unfixable.rs | 20 + tests/ui/needless_type_cast_unfixable.stderr | 17 + tests/ui/never_loop_iterator_reduction.rs | 17 + tests/ui/never_loop_iterator_reduction.stderr | 27 + tests/ui/obfuscated_if_else.fixed | 6 + tests/ui/obfuscated_if_else.rs | 6 + tests/ui/obfuscated_if_else.stderr | 8 +- tests/ui/println_empty_string.fixed | 20 + tests/ui/println_empty_string.rs | 24 + tests/ui/println_empty_string.stderr | 39 +- tests/ui/println_empty_string_unfixable.rs | 30 + .../ui/println_empty_string_unfixable.stderr | 85 +++ tests/ui/ref_as_ptr.fixed | 10 + tests/ui/ref_as_ptr.rs | 10 + tests/ui/ref_as_ptr.stderr | 60 +- tests/ui/result_large_err.rs | 9 + tests/ui/result_large_err.stderr | 18 +- tests/ui/same_length_and_capacity.rs | 27 + tests/ui/same_length_and_capacity.stderr | 20 + tests/ui/set_contains_or_insert.rs | 21 + tests/ui/set_contains_or_insert.stderr | 11 +- tests/ui/track-diagnostics.rs | 1 + tests/ui/transmuting_null.rs | 8 + tests/ui/transmuting_null.stderr | 8 +- tests/ui/unchecked_time_subtraction.fixed | 25 + tests/ui/unchecked_time_subtraction.rs | 25 + tests/ui/unchecked_time_subtraction.stderr | 26 +- tests/ui/unnecessary_fold.fixed | 85 +++ tests/ui/unnecessary_fold.rs | 85 +++ tests/ui/unnecessary_fold.stderr | 130 +++- tests/ui/use_self.fixed | 25 + tests/ui/use_self.rs | 25 + tests/ui/use_self.stderr | 84 +-- tests/ui/writeln_empty_string_unfixable.rs | 26 + .../ui/writeln_empty_string_unfixable.stderr | 47 ++ triagebot.toml | 1 + 177 files changed, 6336 insertions(+), 967 deletions(-) create mode 100644 clippy_lints/src/same_length_and_capacity.rs create mode 100644 clippy_lints_internal/src/repeated_is_diagnostic_item.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.fixed create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item.stderr create mode 100644 tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs create mode 100644 tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr create mode 100644 tests/ui/format_push_string.fixed create mode 100644 tests/ui/format_push_string_no_core.rs create mode 100644 tests/ui/format_push_string_no_std.fixed create mode 100644 tests/ui/format_push_string_no_std.rs create mode 100644 tests/ui/format_push_string_no_std.stderr create mode 100644 tests/ui/format_push_string_no_std_unfixable.rs create mode 100644 tests/ui/format_push_string_no_std_unfixable.stderr create mode 100644 tests/ui/format_push_string_unfixable.rs create mode 100644 tests/ui/format_push_string_unfixable.stderr create mode 100644 tests/ui/needless_type_cast_unfixable.rs create mode 100644 tests/ui/needless_type_cast_unfixable.stderr create mode 100644 tests/ui/never_loop_iterator_reduction.rs create mode 100644 tests/ui/never_loop_iterator_reduction.stderr create mode 100644 tests/ui/println_empty_string_unfixable.rs create mode 100644 tests/ui/println_empty_string_unfixable.stderr create mode 100644 tests/ui/same_length_and_capacity.rs create mode 100644 tests/ui/same_length_and_capacity.stderr create mode 100644 tests/ui/writeln_empty_string_unfixable.rs create mode 100644 tests/ui/writeln_empty_string_unfixable.stderr diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index d530eb6c73a3..3a99d65233d3 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -16,7 +16,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 diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml index d91c638a8fb5..f9e882d9757c 100644 --- a/.github/workflows/clippy_pr.yml +++ b/.github/workflows/clippy_pr.yml @@ -24,7 +24,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 diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml index 03641a9aa62f..d4dc80efe79d 100644 --- a/.github/workflows/remark.yml +++ b/.github/workflows/remark.yml @@ -20,9 +20,9 @@ jobs: persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: - node-version: '20.x' + node-version: '24.x' - name: Install remark run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f666caf306f..91d793489be2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6916,6 +6916,7 @@ Released 2018-09-13 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push +[`same_length_and_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_length_and_capacity [`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 10c08dba50b9..c2abbac37535 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -10,6 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" +rustc-literal-escaper = "0.0.5" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index dcca08aee7e6..cd103908be03 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -22,7 +22,6 @@ extern crate rustc_arena; #[expect(unused_extern_crates, reason = "required to link to rustc crates")] extern crate rustc_driver; extern crate rustc_lexer; -extern crate rustc_literal_escaper; pub mod deprecate_lint; pub mod dogfood; diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 2586c89bc868..4aa55e53445c 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -3,6 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::{find_assert_args, root_macro_call_first_node}; use clippy_utils::msrvs::Msrv; +use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{is_inside_always_const_context, msrvs}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -50,6 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, } && let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn) + && is_const_evaluatable(cx, condition) && let Some((Constant::Bool(assert_val), const_src)) = ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt()) && let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 902ba70577b9..a04a56d72bc0 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -433,7 +433,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio }, ExprKind::MethodCall(path, receiver, args, _) => { let type_of_receiver = cx.typeck_results().expr_ty(receiver); - if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) { + if !matches!(type_of_receiver.opt_diag_name(cx), Some(sym::Option | sym::Result)) { return None; } METHODS_WITH_NEGATION diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs index 712e38db499f..748ab3163496 100644 --- a/clippy_lints/src/casts/cast_precision_loss.rs +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -23,15 +23,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca let cast_to_f64 = to_nbits == 64; let mantissa_nbits = if cast_to_f64 { 52 } else { 23 }; - let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; - let arch_dependent_str = "on targets with 64-bit wide pointers "; - let from_nbits_str = if arch_dependent { - "64".to_owned() - } else if is_isize_or_usize(cast_from) { - // FIXME: handle 16 bits `usize` type - "32 or 64".to_owned() + + let has_width = if is_isize_or_usize(cast_from) { + "can be up to 64 bits wide depending on the target architecture".to_owned() } else { - from_nbits.to_string() + format!("is {from_nbits} bits wide") }; span_lint( @@ -39,13 +35,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca CAST_PRECISION_LOSS, expr.span, format!( - "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ - but `{1}`'s mantissa is only {4} bits wide)", - cast_from, - if cast_to_f64 { "f64" } else { "f32" }, - if arch_dependent { arch_dependent_str } else { "" }, - from_nbits_str, - mantissa_nbits + "casting `{cast_from}` to `{cast_to}` may cause a loss of precision \ + (`{cast_from}` {has_width}, \ + but `{cast_to}`'s mantissa is only {mantissa_nbits} bits wide)", ), ); } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 494d6180d3cb..7220a8a80066 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -836,7 +836,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.93.0"] pub NEEDLESS_TYPE_CAST, - pedantic, + nursery, "binding defined with one type but always cast to another" } diff --git a/clippy_lints/src/casts/needless_type_cast.rs b/clippy_lints/src/casts/needless_type_cast.rs index ca6aa0f87bbf..1d899a21c229 100644 --- a/clippy_lints/src/casts/needless_type_cast.rs +++ b/clippy_lints/src/casts/needless_type_cast.rs @@ -1,6 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sugg::Sugg; use clippy_utils::visitors::{Descend, for_each_expr, for_each_expr_without_closures}; use core::ops::ControlFlow; +use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -14,6 +16,7 @@ use super::NEEDLESS_TYPE_CAST; struct BindingInfo<'a> { source_ty: Ty<'a>, ty_span: Span, + init: Option<&'a Expr<'a>>, } struct UsageInfo<'a> { @@ -73,6 +76,7 @@ fn collect_binding_from_let<'a>( BindingInfo { source_ty: ty, ty_span: ty_hir.span, + init: Some(let_expr.init), }, ); } @@ -103,6 +107,7 @@ fn collect_binding_from_local<'a>( BindingInfo { source_ty: ty, ty_span: ty_hir.span, + init: let_stmt.init, }, ); } @@ -182,12 +187,7 @@ fn is_generic_res(cx: &LateContext<'_>, res: Res) -> bool { .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, - } + cx.tcx.res_generics_def_id(res).is_some_and(has_type_params) } fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> bool { @@ -234,6 +234,18 @@ fn is_cast_in_generic_context<'a>(cx: &LateContext<'a>, cast_expr: &Expr<'a>) -> } } +fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool { + match expr.kind { + ExprKind::Lit(lit) => matches!( + lit.node, + LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) + ), + ExprKind::Unary(rustc_hir::UnOp::Neg, inner) => can_coerce_to_target_type(inner), + ExprKind::Binary(_, lhs, rhs) => can_coerce_to_target_type(lhs) && can_coerce_to_target_type(rhs), + _ => false, + } +} + fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) { let mut usages = Vec::new(); @@ -274,7 +286,19 @@ fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId return; }; - span_lint_and_sugg( + // Don't lint if there's exactly one use and the initializer cannot be coerced to the + // target type (i.e., would require an explicit cast). In such cases, the fix would add + // a cast to the initializer rather than eliminating one - the cast isn't truly "needless." + // See: https://github.com/rust-lang/rust-clippy/issues/16240 + if usages.len() == 1 + && binding_info + .init + .is_some_and(|init| !can_coerce_to_target_type(init) && !init.span.from_expansion()) + { + return; + } + + span_lint_and_then( cx, NEEDLESS_TYPE_CAST, binding_info.ty_span, @@ -282,8 +306,28 @@ fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId "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, + |diag| { + if let Some(init) = binding_info + .init + .filter(|i| !can_coerce_to_target_type(i) && !i.span.from_expansion()) + { + let sugg = Sugg::hir(cx, init, "..").as_ty(first_target); + diag.multipart_suggestion( + format!("consider defining it as `{first_target}` and casting the initializer"), + vec![ + (binding_info.ty_span, first_target.to_string()), + (init.span, sugg.to_string()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.span_suggestion( + binding_info.ty_span, + "consider defining it as", + first_target.to_string(), + Applicability::MachineApplicable, + ); + } + }, ); } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index 592c820a25e1..b3805c678174 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core}; +use clippy_utils::{ExprUseNode, expr_use_ctxt, is_expr_temporary_value, std_or_core}; use rustc_errors::Applicability; -use rustc_hir::{Expr, Mutability, Ty, TyKind}; +use rustc_hir::{Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -23,10 +23,18 @@ pub(super) fn check<'tcx>( if matches!(cast_from.kind(), ty::Ref(..)) && let ty::RawPtr(_, to_mutbl) = cast_to.kind() && let use_cx = expr_use_ctxt(cx, expr) - // TODO: only block the lint if `cast_expr` is a temporary - && !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)) && let Some(std_or_core) = std_or_core(cx) { + if let ExprKind::AddrOf(_, _, addr_inner) = cast_expr.kind + && is_expr_temporary_value(cx, addr_inner) + && matches!( + use_cx.use_node(cx), + ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_) + ) + { + return; + } + let fn_name = match to_mutbl { Mutability::Not => "from_ref", Mutability::Mut => "from_mut", diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b13e307a3f9c..be07ce1272bd 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -76,7 +76,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.51.0"] pub COLLAPSIBLE_ELSE_IF, - style, + pedantic, "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)" } @@ -267,6 +267,9 @@ impl LateLintPass<'_> for CollapsibleIf { && !expr.span.from_expansion() { if let Some(else_) = else_ + // Short circuit if both `if` branches contain only a single `if {..} else {}`, as + // collapsing such blocks can lead to less readable code (#4971) + && !(single_inner_if_else(then) && single_inner_if_else(else_)) && let ExprKind::Block(else_, None) = else_.kind { self.check_collapsible_else_if(cx, then.span, else_); @@ -280,6 +283,19 @@ impl LateLintPass<'_> for CollapsibleIf { } } +/// Returns true if `expr` is a block that contains only one `if {..} else {}` statement +fn single_inner_if_else(expr: &Expr<'_>) -> bool { + if let ExprKind::Block(block, None) = expr.kind + && let Some(inner_expr) = expr_block(block) + && let ExprKind::If(_, _, else_) = inner_expr.kind + && else_.is_some() + { + true + } else { + false + } +} + /// If `block` is a block with either one expression or a statement containing an expression, /// return the expression. We don't peel blocks recursively, as extra blocks might be intentional. fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 87d75234ebc0..6b68940c6423 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -667,6 +667,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::returns::LET_AND_RETURN_INFO, crate::returns::NEEDLESS_RETURN_INFO, crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO, + crate::same_length_and_capacity::SAME_LENGTH_AND_CAPACITY_INFO, crate::same_name_method::SAME_NAME_METHOD_INFO, crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO, crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO, diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 8c067432cb4e..58403ad19235 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -88,6 +88,9 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if expr.span.desugaring_kind().is_some() { + return; + } let (id, span) = match &expr.kind { ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span), ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index e7230ebf8cba..7e335d5c9809 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -1,16 +1,18 @@ use clippy_utils::attrs::span_contains_cfg; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; -use rustc_data_structures::fx::FxIndexMap; +use clippy_utils::source::SpanRangeExt; +use clippy_utils::span_contains_non_whitespace; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_errors::Applicability; -use rustc_hir::def::CtorOf; use rustc_hir::def::DefKind::Ctor; use rustc_hir::def::Res::Def; +use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Path, QPath, Variant, VariantData}; +use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Pat, PatKind, Path, QPath, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -118,7 +120,6 @@ impl LateLintPass<'_> for EmptyWithBrackets { } fn check_variant(&mut self, cx: &LateContext<'_>, variant: &Variant<'_>) { - // FIXME: handle `$name {}` if !variant.span.from_expansion() && !variant.ident.span.from_expansion() && let span_after_ident = variant.span.with_lo(variant.ident.span.hi()) @@ -126,44 +127,14 @@ impl LateLintPass<'_> for EmptyWithBrackets { { match variant.data { VariantData::Struct { .. } => { - // Empty struct variants can be linted immediately - span_lint_and_then( - cx, - EMPTY_ENUM_VARIANTS_WITH_BRACKETS, - span_after_ident, - "enum variant has empty brackets", - |diagnostic| { - diagnostic.span_suggestion_hidden( - span_after_ident, - "remove the brackets", - "", - Applicability::MaybeIncorrect, - ); - }, - ); + self.add_enum_variant(variant.def_id); }, VariantData::Tuple(.., local_def_id) => { // Don't lint reachable tuple enums if cx.effective_visibilities.is_reachable(variant.def_id) { return; } - if let Some(entry) = self.empty_tuple_enum_variants.get_mut(&local_def_id) { - // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before the - // definition was encountered. Now that there's a definition, convert it - // to Usage::Unused. - if let Usage::NoDefinition { redundant_use_sites } = entry { - *entry = Usage::Unused { - redundant_use_sites: redundant_use_sites.clone(), - }; - } - } else { - self.empty_tuple_enum_variants.insert( - local_def_id, - Usage::Unused { - redundant_use_sites: vec![], - }, - ); - } + self.add_enum_variant(local_def_id); }, VariantData::Unit(..) => {}, } @@ -171,56 +142,58 @@ impl LateLintPass<'_> for EmptyWithBrackets { } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(def_id) = check_expr_for_enum_as_function(expr) { - if let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) { + if let Some((def_id, mut span)) = check_expr_for_enum_as_function(cx, expr) { + if span.is_empty() + && let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) + { + span = parentheses_span; + } + + if span.is_empty() { + // The parentheses are not redundant. + self.empty_tuple_enum_variants.insert(def_id, Usage::Used); + } else { // Do not count expressions from macro expansion as a redundant use site. if expr.span.from_expansion() { return; } - match self.empty_tuple_enum_variants.get_mut(&def_id) { - Some( - &mut (Usage::Unused { - ref mut redundant_use_sites, - } - | Usage::NoDefinition { - ref mut redundant_use_sites, - }), - ) => { - redundant_use_sites.push(parentheses_span); - }, - None => { - // The variant isn't in the IndexMap which means its definition wasn't encountered yet. - self.empty_tuple_enum_variants.insert( - def_id, - Usage::NoDefinition { - redundant_use_sites: vec![parentheses_span], - }, - ); - }, - _ => {}, - } - } else { - // The parentheses are not redundant. - self.empty_tuple_enum_variants.insert(def_id, Usage::Used); + self.update_enum_variant_usage(def_id, span); } } } + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { + if !pat.span.from_expansion() + && let Some((def_id, span)) = check_pat_for_enum_as_function(cx, pat) + { + self.update_enum_variant_usage(def_id, span); + } + } + fn check_crate_post(&mut self, cx: &LateContext<'_>) { - for (local_def_id, usage) in &self.empty_tuple_enum_variants { + for (&local_def_id, usage) in &self.empty_tuple_enum_variants { // Ignore all variants with Usage::Used or Usage::NoDefinition let Usage::Unused { redundant_use_sites } = usage else { continue; }; + // Attempt to fetch the Variant from LocalDefId. - let Node::Variant(variant) = cx.tcx.hir_node( - cx.tcx - .local_def_id_to_hir_id(cx.tcx.parent(local_def_id.to_def_id()).expect_local()), - ) else { + let variant = if let Node::Variant(variant) = cx.tcx.hir_node_by_def_id(local_def_id) { + variant + } else if let Node::Variant(variant) = cx.tcx.hir_node_by_def_id(cx.tcx.local_parent(local_def_id)) { + variant + } else { continue; }; + // Span of the parentheses in variant definition let span = variant.span.with_lo(variant.ident.span.hi()); + let span_inner = span + .with_lo(SpanRangeExt::trim_start(span, cx).start + BytePos(1)) + .with_hi(span.hi() - BytePos(1)); + if span_contains_non_whitespace(cx, span_inner, false) { + continue; + } span_lint_hir_and_then( cx, EMPTY_ENUM_VARIANTS_WITH_BRACKETS, @@ -252,6 +225,43 @@ impl LateLintPass<'_> for EmptyWithBrackets { } } +impl EmptyWithBrackets { + fn add_enum_variant(&mut self, local_def_id: LocalDefId) { + self.empty_tuple_enum_variants + .entry(local_def_id) + .and_modify(|entry| { + // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before + // the definition was encountered. Now that there's a + // definition, convert it to Usage::Unused. + if let Usage::NoDefinition { redundant_use_sites } = entry { + *entry = Usage::Unused { + redundant_use_sites: redundant_use_sites.clone(), + }; + } + }) + .or_insert_with(|| Usage::Unused { + redundant_use_sites: vec![], + }); + } + + fn update_enum_variant_usage(&mut self, def_id: LocalDefId, parentheses_span: Span) { + match self.empty_tuple_enum_variants.entry(def_id) { + IndexEntry::Occupied(mut e) => { + if let Usage::Unused { redundant_use_sites } | Usage::NoDefinition { redundant_use_sites } = e.get_mut() + { + redundant_use_sites.push(parentheses_span); + } + }, + IndexEntry::Vacant(e) => { + // The variant isn't in the IndexMap which means its definition wasn't encountered yet. + e.insert(Usage::NoDefinition { + redundant_use_sites: vec![parentheses_span], + }); + }, + } + } +} + fn has_brackets(var_data: &VariantData<'_>) -> bool { !matches!(var_data, VariantData::Unit(..)) } @@ -277,17 +287,47 @@ fn call_parentheses_span(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option { } // Returns the LocalDefId of the variant being called as a function if it exists. -fn check_expr_for_enum_as_function(expr: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved( - _, - Path { - res: Def(Ctor(CtorOf::Variant, _), def_id), - .. +fn check_expr_for_enum_as_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(LocalDefId, Span)> { + match expr.kind { + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Def(Ctor(CtorOf::Variant, _), def_id), + span, + .. + }, + )) => def_id.as_local().map(|id| (id, span.with_lo(expr.span.hi()))), + ExprKind::Struct(qpath, ..) + if let Def(DefKind::Variant, mut def_id) = cx.typeck_results().qpath_res(qpath, expr.hir_id) => + { + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let ty::FnDef(ctor_def_id, _) = ty.kind() { + def_id = *ctor_def_id; + } + + def_id.as_local().map(|id| (id, qpath.span().with_lo(expr.span.hi()))) }, - )) = expr.kind - { - def_id.as_local() - } else { - None + _ => None, + } +} + +fn check_pat_for_enum_as_function(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(LocalDefId, Span)> { + match pat.kind { + PatKind::TupleStruct(qpath, ..) + if let Def(Ctor(CtorOf::Variant, _), def_id) = cx.typeck_results().qpath_res(&qpath, pat.hir_id) => + { + def_id.as_local().map(|id| (id, qpath.span().with_lo(pat.span.hi()))) + }, + PatKind::Struct(qpath, ..) + if let Def(DefKind::Variant, mut def_id) = cx.typeck_results().qpath_res(&qpath, pat.hir_id) => + { + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let ty::FnDef(ctor_def_id, _) = ty.kind() { + def_id = *ctor_def_id; + } + + def_id.as_local().map(|id| (id, qpath.span().with_lo(pat.span.hi()))) + }, + _ => None, } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index bdfe2e49e66e..75ab890a8a7f 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -4,7 +4,7 @@ use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_expr; use clippy_utils::{ 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, + is_expr_used_or_unified, paths, peel_hir_expr_while, span_contains_non_whitespace, }; use core::fmt::{self, Write}; use rustc_errors::Applicability; @@ -167,7 +167,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { "if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}", map_ty.entry_path(), )) - } else if let Some(insertion) = then_search.as_single_insertion() { + } else if let Some(insertion) = then_search.as_single_insertion() + && let span_in_between = then_expr.span.shrink_to_lo().between(insertion.call.span) + && let span_in_between = span_in_between.split_at(1).1 + && !span_contains_non_whitespace(cx, span_in_between, true) + { let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0; if contains_expr.negated { if insertion.value.can_have_side_effects() { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index c42998ffc3f5..bd2bd6628464 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Sp // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) { let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); - if receiver_ty.is_diag_item(self.lcx, sym::Option) || receiver_ty.is_diag_item(self.lcx, sym::Result) { + if matches!(receiver_ty.opt_diag_name(self.lcx), Some(sym::Option | sym::Result)) { self.result.push(expr.span); } } diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index a23ba9ab837a..fea55f91bce7 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,10 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::higher; +use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node}; use clippy_utils::res::MaybeDef; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::std_or_core; +use rustc_errors::Applicability; use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_session::impl_lint_pass; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -38,7 +41,152 @@ declare_clippy_lint! { pedantic, "`format!(..)` appended to existing `String`" } -declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); +impl_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); + +pub(crate) struct FormatPushString { + format_args: FormatArgsStorage, +} + +enum FormatSearchResults { + /// The expression is itself a `format!()` invocation -- we can make a suggestion to replace it + Direct(Span), + /// The expression contains zero or more `format!()`s, e.g.: + /// ```ignore + /// if true { + /// format!("hello") + /// } else { + /// format!("world") + /// } + /// ``` + /// or + /// ```ignore + /// match true { + /// true => format!("hello"), + /// false => format!("world"), + /// } + Nested(Vec), +} + +impl FormatPushString { + pub(crate) fn new(format_args: FormatArgsStorage) -> Self { + Self { format_args } + } + + fn find_formats<'tcx>(&self, cx: &LateContext<'_>, e: &'tcx Expr<'tcx>) -> FormatSearchResults { + let expr_as_format = |e| { + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) + && let Some(format_args) = self.format_args.get(cx, e, macro_call.expn) + { + Some(format_args_inputs_span(format_args)) + } else { + None + } + }; + + let e = e.peel_blocks().peel_borrows(); + if let Some(fmt) = expr_as_format(e) { + FormatSearchResults::Direct(fmt) + } else { + fn inner<'tcx>( + e: &'tcx Expr<'tcx>, + expr_as_format: &impl Fn(&'tcx Expr<'tcx>) -> Option, + out: &mut Vec, + ) { + let e = e.peel_blocks().peel_borrows(); + + match e.kind { + _ if expr_as_format(e).is_some() => out.push(e.span), + ExprKind::Match(_, arms, MatchSource::Normal) => { + for arm in arms { + inner(arm.body, expr_as_format, out); + } + }, + ExprKind::If(_, then, els) => { + inner(then, expr_as_format, out); + if let Some(els) = els { + inner(els, expr_as_format, out); + } + }, + _ => {}, + } + } + let mut spans = vec![]; + inner(e, &expr_as_format, &mut spans); + FormatSearchResults::Nested(spans) + } + } +} + +impl<'tcx> LateLintPass<'tcx> for FormatPushString { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (recv, arg) = match expr.kind { + ExprKind::MethodCall(_, recv, [arg], _) => { + if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) + { + (recv, arg) + } else { + return; + } + }, + ExprKind::AssignOp(op, recv, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, recv) => { + (recv, arg) + }, + _ => return, + }; + let Some(std_or_core) = std_or_core(cx) else { + // not even `core` is available, so can't suggest `write!` + return; + }; + match self.find_formats(cx, arg) { + FormatSearchResults::Direct(format_args) => { + span_lint_and_then( + cx, + FORMAT_PUSH_STRING, + expr.span, + "`format!(..)` appended to existing `String`", + |diag| { + let mut app = Applicability::MaybeIncorrect; + let msg = "consider using `write!` to avoid the extra allocation"; + + let sugg = format!( + "let _ = write!({recv}, {format_args})", + recv = snippet_with_context(cx.sess(), recv.span, expr.span.ctxt(), "_", &mut app).0, + format_args = snippet_with_applicability(cx.sess(), format_args, "..", &mut app), + ); + diag.span_suggestion_verbose(expr.span, msg, sugg, app); + + // TODO: omit the note if the `Write` trait is imported at point + // Tip: `TyCtxt::in_scope_traits` isn't it -- it returns a non-empty list only when called on + // the `HirId` of a `ExprKind::MethodCall` that is a call of a _trait_ method. + diag.note(format!("you may need to import the `{std_or_core}::fmt::Write` trait")); + }, + ); + }, + FormatSearchResults::Nested(spans) => { + if !spans.is_empty() { + span_lint_and_then( + cx, + FORMAT_PUSH_STRING, + expr.span, + "`format!(..)` appended to existing `String`", + |diag| { + diag.help("consider using `write!` to avoid the extra allocation"); + diag.span_labels(spans, "`format!` used here"); + + // TODO: omit the note if the `Write` trait is imported at point + // Tip: `TyCtxt::in_scope_traits` isn't it -- it returns a non-empty list only when called + // on the `HirId` of a `ExprKind::MethodCall` that is a call of + // a _trait_ method. + diag.note(format!("you may need to import the `{std_or_core}::fmt::Write` trait")); + }, + ); + } + }, + } + } +} fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { cx.typeck_results() @@ -46,54 +194,3 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { .peel_refs() .is_lang_item(cx, LangItem::String) } -fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - let e = e.peel_blocks().peel_borrows(); - - if e.span.from_expansion() - && let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id - { - cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro) - } else if let Some(higher::If { then, r#else, .. }) = higher::If::hir(e) { - is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) - } else { - match higher::IfLetOrMatch::parse(cx, e) { - Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => { - arms.iter().any(|arm| is_format(cx, arm.body)) - }, - Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => { - is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) - }, - _ => false, - } - } -} - -impl<'tcx> LateLintPass<'tcx> for FormatPushString { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let arg = match expr.kind { - ExprKind::MethodCall(_, _, [arg], _) => { - if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) - { - arg - } else { - return; - } - }, - ExprKind::AssignOp(op, left, arg) if op.node == AssignOpKind::AddAssign && is_string(cx, left) => arg, - _ => return, - }; - if is_format(cx, arg) { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - FORMAT_PUSH_STRING, - expr.span, - "`format!(..)` appended to existing `String`", - |diag| { - diag.help("consider using `write!` to avoid the extra allocation"); - }, - ); - } - } -} diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index bdc366f6878a..9a7427ea1447 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -596,4 +596,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions { 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); } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + result::check_expr(cx, expr, self.large_error_threshold, &self.large_error_ignored); + } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index 04e15a1d8a0e..77fec9371425 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -50,7 +50,7 @@ pub(super) fn check_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, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } @@ -70,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, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } @@ -87,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, large_err_ignored); + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold, large_err_ignored, false); } } } @@ -111,12 +111,15 @@ fn check_result_large_err<'tcx>( hir_ty_span: Span, large_err_threshold: u64, large_err_ignored: &DefIdSet, + is_closure: bool, ) { if let ty::Adt(adt, _) = err_ty.kind() && large_err_ignored.contains(&adt.did()) { return; } + + let subject = if is_closure { "closure" } else { "function" }; 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) @@ -130,7 +133,7 @@ fn check_result_large_err<'tcx>( cx, RESULT_LARGE_ERR, hir_ty_span, - "the `Err`-variant returned from this function is very large", + format!("the `Err`-variant returned from this {subject} is very large"), |diag| { diag.span_label( def.variants[first_variant.ind].span, @@ -161,7 +164,7 @@ fn check_result_large_err<'tcx>( cx, RESULT_LARGE_ERR, hir_ty_span, - "the `Err`-variant returned from this function is very large", + format!("the `Err`-variant returned from this {subject} is very large"), |diag: &mut Diag<'_, ()>| { diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); @@ -170,3 +173,33 @@ fn check_result_large_err<'tcx>( } } } + +pub(super) fn check_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + large_err_threshold: u64, + large_err_ignored: &DefIdSet, +) { + if let hir::ExprKind::Closure(closure) = expr.kind + && let ty::Closure(_, args) = cx.typeck_results().expr_ty(expr).kind() + && let closure_sig = args.as_closure().sig() + && let Ok(err_binder) = closure_sig.output().try_map_bound(|output_ty| { + if let ty::Adt(adt, args) = output_ty.kind() + && let [_, err_arg] = args.as_slice() + && let Some(err_ty) = err_arg.as_type() + && adt.is_diag_item(cx, sym::Result) + { + return Ok(err_ty); + } + + Err(()) + }) + { + let err_ty = cx.tcx.instantiate_bound_regions_with_erased(err_binder); + let hir_ty_span = match closure.fn_decl.output { + hir::FnRetTy::Return(hir_ty) => hir_ty.span, + hir::FnRetTy::DefaultReturn(_) => expr.span, + }; + check_result_large_err(cx, err_ty, hir_ty_span, large_err_threshold, large_err_ignored, true); + } +} diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 54e9538fcb99..ff22ba4fcd0d 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -78,6 +78,7 @@ impl LateLintPass<'_> for IfNotElse { // } // ``` if !e.span.from_expansion() && !is_else_clause(cx.tcx, e) { + let mut applicability = Applicability::MachineApplicable; match cond.kind { ExprKind::Unary(UnOp::Not, _) | ExprKind::Binary(_, _, _) => span_lint_and_sugg( cx, @@ -85,8 +86,16 @@ impl LateLintPass<'_> for IfNotElse { e.span, msg, "try", - make_sugg(cx, &cond.kind, cond_inner.span, els.span, "..", Some(e.span)), - Applicability::MachineApplicable, + make_sugg( + cx, + e.span, + &cond.kind, + cond_inner.span, + els.span, + "..", + &mut applicability, + ), + applicability, ), _ => span_lint_and_help(cx, IF_NOT_ELSE, e.span, msg, None, help), } @@ -97,28 +106,26 @@ impl LateLintPass<'_> for IfNotElse { fn make_sugg<'a>( sess: &impl HasSession, + expr_span: Span, cond_kind: &'a ExprKind<'a>, cond_inner: Span, els_span: Span, default: &'a str, - indent_relative_to: Option, + applicability: &mut Applicability, ) -> String { - let cond_inner_snip = snippet(sess, cond_inner, default); - let els_snip = snippet(sess, els_span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let (cond_inner_snip, _) = snippet_with_context(sess, cond_inner, expr_span.ctxt(), default, applicability); + let (els_snip, _) = snippet_with_context(sess, els_span, expr_span.ctxt(), default, applicability); + let indent = indent_of(sess, expr_span); let suggestion = match cond_kind { ExprKind::Unary(UnOp::Not, cond_rest) => { - format!( - "if {} {} else {}", - snippet(sess, cond_rest.span, default), - els_snip, - cond_inner_snip - ) + let (cond_rest_snip, _) = + snippet_with_context(sess, cond_rest.span, expr_span.ctxt(), default, applicability); + format!("if {cond_rest_snip} {els_snip} else {cond_inner_snip}") }, ExprKind::Binary(_, lhs, rhs) => { - let lhs_snip = snippet(sess, lhs.span, default); - let rhs_snip = snippet(sess, rhs.span, default); + let (lhs_snip, _) = snippet_with_context(sess, lhs.span, expr_span.ctxt(), default, applicability); + let (rhs_snip, _) = snippet_with_context(sess, rhs.span, expr_span.ctxt(), default, applicability); format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") }, diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 7f3ef58c93d1..9e5e4fa58d2f 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -4,10 +4,12 @@ use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; use clippy_utils::sugg::Sugg; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ - as_some_expr, contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, - is_none_expr, peel_blocks, sym, + as_some_expr, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_none_expr, + peel_blocks, sym, }; +use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -76,8 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !is_else_clause(cx.tcx, expr) && !is_in_const_context(cx) && self.msrv.meets(cx, msrvs::BOOL_THEN) - && !contains_return(then_block.stmts) - && then_block.expr.is_none_or(|expr| !contains_return(expr)) + && for_each_expr_without_closures(then_block, |e| { + if matches!(e.kind, ExprKind::Ret(..) | ExprKind::Yield(..)) { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_none() { let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { sym::then_some @@ -101,13 +109,19 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { .maybe_paren() .to_string(); let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0; - let method_body = if let Some(first_stmt) = then_block.stmts.first() - && let Some(first_stmt_span) = walk_span_to_context(first_stmt.span, ctxt) + let method_body = if let Some(_) = then_block.stmts.first() + && let Some(then_span) = walk_span_to_context(then.span, ctxt) { - let block_snippet = - snippet_with_applicability(cx, first_stmt_span.until(then_expr.span), "..", &mut app); + let block_before_snippet = + snippet_with_applicability(cx, then_span.until(then_expr.span), "..", &mut app); + let block_after_snippet = snippet_with_applicability( + cx, + then_expr.span.shrink_to_hi().until(then_span.shrink_to_hi()), + "..", + &mut app, + ); let closure = if method_name == sym::then { "|| " } else { "" }; - format!("{closure} {{ {} {arg_snip} }}", block_snippet.trim_end()) + format!("{closure}{block_before_snippet}{arg_snip}{block_after_snippet}") } else if method_name == sym::then { (std::borrow::Cow::Borrowed("|| ") + arg_snip).into_owned() } else { diff --git a/clippy_lints/src/ifs/branches_sharing_code.rs b/clippy_lints/src/ifs/branches_sharing_code.rs index b3f597cc8736..b6e8d047c5cd 100644 --- a/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/clippy_lints/src/ifs/branches_sharing_code.rs @@ -9,7 +9,7 @@ use clippy_utils::{ use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Node, Stmt, StmtKind, intravisit}; +use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, ItemKind, LetStmt, Node, Stmt, StmtKind, UseKind, intravisit}; use rustc_lint::LateContext; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; @@ -108,6 +108,7 @@ struct BlockEq { /// The name and id of every local which can be moved at the beginning and the end. moved_locals: Vec<(HirId, Symbol)>, } + impl BlockEq { fn start_span(&self, b: &Block<'_>, sm: &SourceMap) -> Option { match &b.stmts[..self.start_end_eq] { @@ -129,20 +130,33 @@ impl BlockEq { } /// If the statement is a local, checks if the bound names match the expected list of names. -fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { - if let StmtKind::Let(l) = s.kind { - let mut i = 0usize; - let mut res = true; - l.pat.each_binding_or_first(&mut |_, _, _, name| { - if names.get(i).is_some_and(|&(_, n)| n == name.name) { - i += 1; - } else { - res = false; - } - }); - res && i == names.len() - } else { - false +fn eq_binding_names(cx: &LateContext<'_>, s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { + match s.kind { + StmtKind::Let(l) => { + let mut i = 0usize; + let mut res = true; + l.pat.each_binding_or_first(&mut |_, _, _, name| { + if names.get(i).is_some_and(|&(_, n)| n == name.name) { + i += 1; + } else { + res = false; + } + }); + res && i == names.len() + }, + StmtKind::Item(item_id) + if let [(_, name)] = names + && let item = cx.tcx.hir_item(item_id) + && let ItemKind::Static(_, ident, ..) + | ItemKind::Const(ident, ..) + | ItemKind::Fn { ident, .. } + | ItemKind::TyAlias(ident, ..) + | ItemKind::Use(_, UseKind::Single(ident)) + | ItemKind::Mod(ident, _) = item.kind => + { + *name == ident.name + }, + _ => false, } } @@ -164,6 +178,7 @@ fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: & /// Checks if the given statement should be considered equal to the statement in the same /// position for each block. fn eq_stmts( + cx: &LateContext<'_>, stmt: &Stmt<'_>, blocks: &[&Block<'_>], get_stmt: impl for<'a> Fn(&'a Block<'a>) -> Option<&'a Stmt<'a>>, @@ -178,7 +193,7 @@ fn eq_stmts( let new_bindings = &moved_bindings[old_count..]; blocks .iter() - .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(s, new_bindings))) + .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(cx, s, new_bindings))) } else { true }) && blocks.iter().all(|b| get_stmt(b).is_some_and(|s| eq.eq_stmt(s, stmt))) @@ -218,7 +233,7 @@ fn scan_block_for_eq<'tcx>( return true; } modifies_any_local(cx, stmt, &cond_locals) - || !eq_stmts(stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) + || !eq_stmts(cx, stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) }) .map_or(block.stmts.len(), |(i, stmt)| { adjust_by_closest_callsite(i, stmt, block.stmts[..i].iter().enumerate().rev()) @@ -279,6 +294,7 @@ fn scan_block_for_eq<'tcx>( })) .fold(end_search_start, |init, (stmt, offset)| { if eq_stmts( + cx, stmt, blocks, |b| b.stmts.get(b.stmts.len() - offset), @@ -290,11 +306,26 @@ fn scan_block_for_eq<'tcx>( // Clear out all locals seen at the end so far. None of them can be moved. let stmts = &blocks[0].stmts; for stmt in &stmts[stmts.len() - init..=stmts.len() - offset] { - if let StmtKind::Let(l) = stmt.kind { - l.pat.each_binding_or_first(&mut |_, id, _, _| { - // FIXME(rust/#120456) - is `swap_remove` correct? - eq.locals.swap_remove(&id); - }); + match stmt.kind { + StmtKind::Let(l) => { + l.pat.each_binding_or_first(&mut |_, id, _, _| { + // FIXME(rust/#120456) - is `swap_remove` correct? + eq.locals.swap_remove(&id); + }); + }, + StmtKind::Item(item_id) => { + let item = cx.tcx.hir_item(item_id); + if let ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Fn { .. } + | ItemKind::TyAlias(..) + | ItemKind::Use(..) + | ItemKind::Mod(..) = item.kind + { + eq.local_items.swap_remove(&item.owner_id.to_def_id()); + } + }, + _ => {}, } } moved_locals.truncate(moved_locals_at_start); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 638a08b096db..9dc74a157cbf 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -223,25 +223,20 @@ impl<'tcx> ImplicitHasherType<'tcx> { _ => None, }) .collect(); - let params_len = params.len(); let ty = lower_ty(cx.tcx, hir_ty); - if ty.is_diag_item(cx, sym::HashMap) && params_len == 2 { - Some(ImplicitHasherType::HashMap( + match (ty.opt_diag_name(cx), ¶ms[..]) { + (Some(sym::HashMap), [k, v]) => Some(ImplicitHasherType::HashMap( hir_ty.span, ty, - snippet(cx, params[0].span, "K"), - snippet(cx, params[1].span, "V"), - )) - } else if ty.is_diag_item(cx, sym::HashSet) && params_len == 1 { - Some(ImplicitHasherType::HashSet( - hir_ty.span, - ty, - snippet(cx, params[0].span, "T"), - )) - } else { - None + snippet(cx, k.span, "K"), + snippet(cx, v.span, "V"), + )), + (Some(sym::HashSet), [t]) => { + Some(ImplicitHasherType::HashSet(hir_ty.span, ty, snippet(cx, t.span, "T"))) + }, + _ => None, } } else { None diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 40487fe48f22..a957afdb1910 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -318,6 +318,7 @@ mod replace_box; mod reserve_after_initialization; mod return_self_not_must_use; mod returns; +mod same_length_and_capacity; mod same_name_method; mod self_named_constructors; mod semicolon_block; @@ -739,7 +740,10 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(move |_| Box::new(cargo::Cargo::new(conf))), Box::new(|_| Box::new(empty_with_brackets::EmptyWithBrackets::default())), Box::new(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)), - Box::new(|_| Box::new(format_push_string::FormatPushString)), + { + let format_args = format_args_storage.clone(); + Box::new(move |_| Box::new(format_push_string::FormatPushString::new(format_args.clone()))) + }, Box::new(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf))), Box::new(|_| Box::new(strings::TrimSplitWhitespace)), Box::new(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)), @@ -852,6 +856,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), + Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), // add late passes here, used by `cargo dev new_lint` ]; store.late_passes.extend(late_lints); diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index c6b650a1a88b..39b2391c98ec 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { span_lint_and_then( cx, FOR_KV_MAP, diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 21198c3c8bc2..ddc783069385 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -26,6 +26,7 @@ mod while_let_on_iterator; use clippy_config::Conf; use clippy_utils::msrvs::Msrv; +use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::{higher, sym}; use rustc_ast::Label; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; @@ -881,13 +882,44 @@ impl<'tcx> LateLintPass<'tcx> for Loops { manual_while_let_some::check(cx, condition, body, span); } - if let ExprKind::MethodCall(path, recv, [arg], _) = expr.kind - && matches!( - path.ident.name, - sym::all | sym::any | sym::filter_map | sym::find_map | sym::flat_map | sym::for_each | sym::map - ) - { - unused_enumerate_index::check_method(cx, expr, recv, arg); + if let ExprKind::MethodCall(path, recv, args, _) = expr.kind { + let name = path.ident.name; + + let is_iterator_method = || { + cx.ty_based_def(expr) + .assoc_fn_parent(cx) + .is_diag_item(cx, sym::Iterator) + }; + + // is_iterator_method is a bit expensive, so we call it last in each match arm + match (name, args) { + (sym::for_each | sym::all | sym::any, [arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + unused_enumerate_index::check_method(cx, recv, arg, closure); + never_loop::check_iterator_reduction(cx, expr, recv, closure); + } + }, + + (sym::filter_map | sym::find_map | sym::flat_map | sym::map, [arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + unused_enumerate_index::check_method(cx, recv, arg, closure); + } + }, + + (sym::try_for_each | sym::reduce, [arg]) | (sym::fold | sym::try_fold, [_, arg]) => { + if let ExprKind::Closure(closure) = arg.kind + && is_iterator_method() + { + never_loop::check_iterator_reduction(cx, expr, recv, closure); + } + }, + + _ => {}, + } } } } diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 0d37be17689a..a037af3433c3 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -3,14 +3,16 @@ use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::sym; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use rustc_errors::Applicability; use rustc_hir::{ - Block, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, StructTailExpr, + Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, + StructTailExpr, }; use rustc_lint::LateContext; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; use std::iter::once; use std::ops::ControlFlow; @@ -72,6 +74,31 @@ pub(super) fn check<'tcx>( } } +pub(super) fn check_iterator_reduction<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + closure: &'tcx Closure<'tcx>, +) { + let closure_body = cx.tcx.hir_body(closure.body).value; + let body_ty = cx.typeck_results().expr_ty(closure_body); + if body_ty.is_never() { + span_lint_and_then( + cx, + NEVER_LOOP, + expr.span, + "this iterator reduction never loops (closure always diverges)", + |diag| { + let mut app = Applicability::HasPlaceholders; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "", &mut app).0; + diag.note("if you only need one element, `if let Some(x) = iter.next()` is clearer"); + let sugg = format!("if let Some(x) = {recv_snip}.next() {{ ... }}"); + diag.span_suggestion_verbose(expr.span, "consider this pattern", sugg, app); + }, + ); + } +} + fn contains_any_break_or_continue(block: &Block<'_>) -> bool { for_each_expr_without_closures(block, |e| match e.kind { ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 82ded453616d..816273c7ba8b 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,10 +1,10 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::res::MaybeDef; use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; use clippy_utils::{expr_or_init, pat_is_wild}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Pat, PatKind, TyKind}; +use rustc_hir::{Closure, Expr, ExprKind, Pat, PatKind, TyKind}; use rustc_lint::LateContext; use rustc_span::{Span, SyntaxContext, sym}; @@ -60,14 +60,12 @@ pub(super) fn check<'tcx>( pub(super) fn check_method<'tcx>( cx: &LateContext<'tcx>, - e: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, arg: &'tcx Expr<'tcx>, + closure: &'tcx Closure<'tcx>, ) { - if let ExprKind::Closure(closure) = arg.kind - && let body = cx.tcx.hir_body(closure.body) - && let [param] = body.params - && cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Iterator) + let body = cx.tcx.hir_body(closure.body); + if let [param] = body.params && let [input] = closure.fn_decl.inputs && !arg.span.from_expansion() && !input.span.from_expansion() diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 0f3d8b336675..38ee4ce104a5 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -374,7 +374,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo } let ty = typeck_results.pat_ty(pat); // Option and Result are allowed, everything else isn't. - if !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) { + if !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) { has_disallowed = true; } }); diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 89411115f730..c26b2dbde7fc 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -3,7 +3,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::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -44,6 +44,8 @@ pub(crate) fn check_if_let<'tcx>( { ex_new = ex_inner; } + + let (snippet, _) = snippet_with_context(cx, ex_new.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, @@ -53,11 +55,7 @@ pub(crate) fn check_if_let<'tcx>( diag.span_suggestion_verbose( expr.span, "use `matches!` directly", - format!( - "{}matches!({}, {pat})", - if b0 { "" } else { "!" }, - snippet_with_applicability(cx, ex_new.span, "..", &mut applicability), - ), + format!("{}matches!({snippet}, {pat})", if b0 { "" } else { "!" }), applicability, ); }, @@ -178,6 +176,8 @@ pub(super) fn check_match<'tcx>( { ex_new = ex_inner; } + + let (snippet, _) = snippet_with_context(cx, ex_new.span, e.span.ctxt(), "..", &mut applicability); span_lint_and_then( cx, MATCH_LIKE_MATCHES_MACRO, @@ -187,11 +187,7 @@ pub(super) fn check_match<'tcx>( 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), - ), + format!("{}matches!({snippet}, {pat_and_guard})", if b0 { "" } else { "!" },), applicability, ); }, diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index fa44a56af182..00bd1c2ca698 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -16,7 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let ty = cx.typeck_results().expr_ty(ex).peel_refs(); let adt_def = match ty.kind() { ty::Adt(adt_def, _) - if adt_def.is_enum() && !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) => + if adt_def.is_enum() && !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) => { adt_def }, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 288f966991ac..e891b2ac6d64 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -26,12 +26,10 @@ pub(super) fn check<'tcx>( let arg_root = get_arg_root(cx, arg); if contains_call(cx, arg_root) && !contains_return(arg_root) { let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); - let closure_args = if receiver_type.is_diag_item(cx, sym::Option) { - "||" - } else if receiver_type.is_diag_item(cx, sym::Result) { - "|_|" - } else { - return; + let closure_args = match receiver_type.opt_diag_name(cx) { + Some(sym::Option) => "||", + Some(sym::Result) => "|_|", + _ => return, }; let span_replace_word = method_span.with_hi(expr.span.hi()); diff --git a/clippy_lints/src/methods/iter_count.rs b/clippy_lints/src/methods/iter_count.rs index ea2508cd7f38..8b303c0ca5b2 100644 --- a/clippy_lints/src/methods/iter_count.rs +++ b/clippy_lints/src/methods/iter_count.rs @@ -11,26 +11,17 @@ use super::ITER_COUNT; pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) { let ty = cx.typeck_results().expr_ty(recv); - let caller_type = if derefs_to_slice(cx, recv, ty).is_some() { - "slice" - } else if ty.is_diag_item(cx, sym::Vec) { - "Vec" - } else if ty.is_diag_item(cx, sym::VecDeque) { - "VecDeque" - } else if ty.is_diag_item(cx, sym::HashSet) { - "HashSet" - } else if ty.is_diag_item(cx, sym::HashMap) { - "HashMap" - } else if ty.is_diag_item(cx, sym::BTreeMap) { - "BTreeMap" - } else if ty.is_diag_item(cx, sym::BTreeSet) { - "BTreeSet" - } else if ty.is_diag_item(cx, sym::LinkedList) { - "LinkedList" - } else if ty.is_diag_item(cx, sym::BinaryHeap) { - "BinaryHeap" - } else { - return; + let caller_type = match ty.opt_diag_name(cx) { + _ if derefs_to_slice(cx, recv, ty).is_some() => "slice", + Some(sym::Vec) => "Vec", + Some(sym::VecDeque) => "VecDeque", + Some(sym::HashSet) => "HashSet", + Some(sym::HashMap) => "HashMap", + Some(sym::BTreeMap) => "BTreeMap", + Some(sym::BTreeSet) => "BTreeSet", + Some(sym::LinkedList) => "LinkedList", + Some(sym::BinaryHeap) => "BinaryHeap", + _ => return, }; let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 2d6bc36dc535..16db8663941e 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( _ => return, } && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() - && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap)) + && matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { let mut applicability = rustc_errors::Applicability::MachineApplicable; let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability); diff --git a/clippy_lints/src/methods/join_absolute_paths.rs b/clippy_lints/src/methods/join_absolute_paths.rs index e84b7452c758..905a58afa795 100644 --- a/clippy_lints/src/methods/join_absolute_paths.rs +++ b/clippy_lints/src/methods/join_absolute_paths.rs @@ -13,7 +13,7 @@ use super::JOIN_ABSOLUTE_PATHS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - if (ty.is_diag_item(cx, sym::Path) || ty.is_diag_item(cx, sym::PathBuf)) + if matches!(ty.opt_diag_name(cx), Some(sym::Path | sym::PathBuf)) && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind && let LitKind::Str(symbol, _) = spanned.node && let sym_str = symbol.as_str() diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index a1aac96ccf86..8a1cc664ac60 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -25,7 +25,7 @@ fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_parent_id: De } // We check if it's an `Option` or a `Result`. if let Some(ty) = method_parent_id.opt_impl_ty(cx) { - if !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result) { + if !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) { return false; } } else { diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 62bdc4a3e411..8eb26fb50747 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet; @@ -51,11 +51,8 @@ pub(super) fn check<'tcx>( // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_arg.span, ".."); let unwrap_snippet = snippet(cx, unwrap_arg.span, ".."); - // lint, with note if neither arg is > 1 line and both map() and - // unwrap_or_else() have the same span - let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); - if same_span && !multiline { + // lint, with note if both map() and unwrap_or_else() have the same span + if map_arg.span.eq_ctxt(unwrap_arg.span) { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( cx, @@ -67,9 +64,6 @@ pub(super) fn check<'tcx>( Applicability::MachineApplicable, ); return true; - } else if same_span && multiline { - span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); - return true; } } diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 055fdcabdd21..0e2012319147 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -81,7 +81,9 @@ pub(super) fn check<'tcx>( }, _ => return, }; - } else if let ExprKind::Index(_, index, _) = parent.kind { + } else if let ExprKind::Index(_, index, _) = parent.kind + && cx.typeck_results().expr_ty(index).is_usize() + { app = Applicability::MaybeIncorrect; let snip = snippet_with_applicability(cx, index.span, "_", &mut app); sugg = format!("nth({snip}).unwrap()"); diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs index b2466bbd982d..69d851e81600 100644 --- a/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,7 +1,7 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, sym}; use rustc_errors::Applicability; @@ -33,20 +33,22 @@ pub(super) fn check<'tcx>( let if_then = match then_method_name { sym::then if let ExprKind::Closure(closure) = then_arg.kind => { let body = cx.tcx.hir_body(closure.body); - snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + snippet_with_context(cx, body.value.span, expr.span.ctxt(), "..", &mut applicability).0 }, - sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), + sym::then_some => snippet_with_context(cx, then_arg.span, expr.span.ctxt(), "..", &mut applicability).0, _ => return, }; let els = match unwrap { - Unwrap::Or(arg) => snippet_with_applicability(cx, arg.span, "..", &mut applicability), + Unwrap::Or(arg) => snippet_with_context(cx, arg.span, expr.span.ctxt(), "..", &mut applicability).0, Unwrap::OrElse(arg) => match arg.kind { ExprKind::Closure(closure) => { let body = cx.tcx.hir_body(closure.body); - snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + snippet_with_context(cx, body.value.span, expr.span.ctxt(), "..", &mut applicability).0 + }, + ExprKind::Path(_) => { + snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut applicability).0 + "()" }, - ExprKind::Path(_) => snippet_with_applicability(cx, arg.span, "_", &mut applicability) + "()", _ => return, }, Unwrap::OrDefault => "Default::default()".into(), @@ -54,7 +56,7 @@ pub(super) fn check<'tcx>( let sugg = format!( "if {} {{ {} }} else {{ {} }}", - Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability), + Sugg::hir_with_context(cx, then_recv, expr.span.ctxt(), "..", &mut applicability), if_then, els ); diff --git a/clippy_lints/src/methods/or_then_unwrap.rs b/clippy_lints/src/methods/or_then_unwrap.rs index 07199b84f39e..448ab621a7ce 100644 --- a/clippy_lints/src/methods/or_then_unwrap.rs +++ b/clippy_lints/src/methods/or_then_unwrap.rs @@ -20,24 +20,28 @@ pub(super) fn check<'tcx>( let title; let or_arg_content: Span; - if ty.is_diag_item(cx, sym::Option) { - title = "found `.or(Some(…)).unwrap()`"; - if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) { - or_arg_content = content; - } else { + match ty.opt_diag_name(cx) { + Some(sym::Option) => { + title = "found `.or(Some(…)).unwrap()`"; + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) { + or_arg_content = content; + } else { + return; + } + }, + Some(sym::Result) => { + title = "found `.or(Ok(…)).unwrap()`"; + if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) { + or_arg_content = content; + } else { + return; + } + }, + _ => { + // Someone has implemented a struct with .or(...).unwrap() chaining, + // but it's not an Option or a Result, so bail return; - } - } else if ty.is_diag_item(cx, sym::Result) { - title = "found `.or(Ok(…)).unwrap()`"; - if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) { - or_arg_content = content; - } else { - return; - } - } else { - // Someone has implemented a struct with .or(...).unwrap() chaining, - // but it's not an Option or a Result, so bail - return; + }, } let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index bd471e0b18e3..9dae6fbb48dd 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,44 +1,52 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; +use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{peel_blocks, strip_pat_refs}; +use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; +use rustc_hir::def::{DefKind, Res}; use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::{Span, sym}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{Span, Symbol, sym}; use super::UNNECESSARY_FOLD; /// Do we need to suggest turbofish when suggesting a replacement method? /// Changing `fold` to `sum` needs it sometimes when the return type can't be /// inferred. This checks for some common cases where it can be safely omitted -fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let parent = cx.tcx.parent_hir_node(expr.hir_id); - - // some common cases where turbofish isn't needed: - // - assigned to a local variable with a type annotation - if let hir::Node::LetStmt(local) = parent - && local.ty.is_some() +fn needs_turbofish<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { + let use_cx = expr_use_ctxt(cx, expr); + if use_cx.same_ctxt + && let use_node = use_cx.use_node(cx) + && let Some(ty) = use_node.defined_ty(cx) { - return false; - } + // some common cases where turbofish isn't needed: + match (use_node, ty) { + // - assigned to a local variable with a type annotation + (ExprUseNode::LetStmt(_), _) => return false, - // - part of a function call argument, can be inferred from the function signature (provided that - // the parameter is not a generic type parameter) - if let hir::Node::Expr(parent_expr) = parent - && let hir::ExprKind::Call(recv, args) = parent_expr.kind - && let hir::ExprKind::Path(ref qpath) = recv.kind - && let Some(fn_def_id) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() - && let fn_sig = cx.tcx.fn_sig(fn_def_id).skip_binder().skip_binder() - && let Some(arg_pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) - && let Some(ty) = fn_sig.inputs().get(arg_pos) - && !matches!(ty.kind(), ty::Param(_)) - { - return false; + // - part of a function call argument, can be inferred from the function signature (provided that the + // parameter is not a generic type parameter) + (ExprUseNode::FnArg(..), DefinedTy::Mir { ty: arg_ty, .. }) + if !matches!(arg_ty.skip_binder().kind(), ty::Param(_)) => + { + return false; + }, + + // - the final expression in the body of a function with a simple return type + (ExprUseNode::Return(_), DefinedTy::Mir { ty: fn_return_ty, .. }) + if !fn_return_ty + .skip_binder() + .walk() + .any(|generic| generic.as_type().is_some_and(Ty::is_impl_trait)) => + { + return false; + }, + _ => {}, + } } // if it's neither of those, stay on the safe side and suggest turbofish, @@ -60,7 +68,7 @@ fn check_fold_with_op( fold_span: Span, op: hir::BinOpKind, replacement: Replacement, -) { +) -> bool { if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind // Extract the body of the closure passed to fold && let closure_body = cx.tcx.hir_body(body) @@ -93,7 +101,7 @@ fn check_fold_with_op( r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { - format!("{method}{turbofish}()", method = replacement.method_name,) + format!("{method}{turbofish}()", method = replacement.method_name) }; span_lint_and_sugg( @@ -105,12 +113,47 @@ fn check_fold_with_op( sugg, applicability, ); + return true; + } + false +} + +fn check_fold_with_method( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + acc: &hir::Expr<'_>, + fold_span: Span, + method: Symbol, + replacement: Replacement, +) { + // Extract the name of the function passed to `fold` + if let Res::Def(DefKind::AssocFn, fn_did) = acc.res_if_named(cx, method) + // Check if the function belongs to the operator + && cx.tcx.is_diagnostic_item(method, fn_did) + { + let applicability = Applicability::MachineApplicable; + + let turbofish = if replacement.has_generic_return { + format!("::<{}>", cx.typeck_results().expr_ty(expr)) + } else { + String::new() + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + "this `.fold` can be written more succinctly using another method", + "try", + format!("{method}{turbofish}()", method = replacement.method_name), + applicability, + ); } } -pub(super) fn check( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'tcx>, init: &hir::Expr<'_>, acc: &hir::Expr<'_>, fold_span: Span, @@ -124,60 +167,40 @@ pub(super) fn check( if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Or, - Replacement { - method_name: "any", - has_args: true, - has_generic_return: false, - }, - ); + let replacement = Replacement { + method_name: "any", + has_args: true, + has_generic_return: false, + }; + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement); }, ast::LitKind::Bool(true) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::And, - Replacement { - method_name: "all", - has_args: true, - has_generic_return: false, - }, - ); + let replacement = Replacement { + method_name: "all", + has_args: true, + has_generic_return: false, + }; + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement); }, ast::LitKind::Int(Pu128(0), _) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Add, - Replacement { - method_name: "sum", - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - }, - ); + let replacement = Replacement { + method_name: "sum", + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + }; + if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) { + check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement); + } }, ast::LitKind::Int(Pu128(1), _) => { - check_fold_with_op( - cx, - expr, - acc, - fold_span, - hir::BinOpKind::Mul, - Replacement { - method_name: "product", - has_args: false, - has_generic_return: needs_turbofish(cx, expr), - }, - ); + let replacement = Replacement { + method_name: "product", + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + }; + if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) { + check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement); + } }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 10ea0c0c3e23..3207c4207fc0 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -11,11 +11,11 @@ use rustc_span::{Span, sym}; use super::UNNECESSARY_GET_THEN_CHECK; fn is_a_std_set_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::HashSet) || ty.is_diag_item(cx, sym::BTreeSet) + matches!(ty.opt_diag_name(cx), Some(sym::HashSet | sym::BTreeSet)) } fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) + matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) } pub(super) fn check( diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 73a407be4f21..30db2a75df57 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -46,19 +46,19 @@ pub(super) fn check( ) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let (kind, none_value, none_prefix) = if ty.is_diag_item(cx, sym::Option) && !is_err { - ("an `Option`", "None", "") - } else if ty.is_diag_item(cx, sym::Result) - && let ty::Adt(_, substs) = ty.kind() - && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() - { - if is_never_like(t_or_e_ty) { - return; - } + let (kind, none_value, none_prefix) = match ty.opt_diag_name(cx) { + Some(sym::Option) if !is_err => ("an `Option`", "None", ""), + Some(sym::Result) + if let ty::Adt(_, substs) = ty.kind() + && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type() => + { + if is_never_like(t_or_e_ty) { + return; + } - ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ") - } else { - return; + ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ") + }, + _ => return, }; let method_suffix = if is_err { "_err" } else { "" }; diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 15b773c2c64f..a26f24d15247 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -112,10 +112,14 @@ fn should_lint<'tcx>( if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); - if path.ident.name == sym::debug_struct && recv_ty.is_diag_item(cx, sym::Formatter) { - has_debug_struct = true; - } else if path.ident.name == sym::finish_non_exhaustive && recv_ty.is_diag_item(cx, sym::DebugStruct) { - has_finish_non_exhaustive = true; + match (path.ident.name, recv_ty.opt_diag_name(cx)) { + (sym::debug_struct, Some(sym::Formatter)) => { + has_debug_struct = true; + }, + (sym::finish_non_exhaustive, Some(sym::DebugStruct)) => { + has_finish_non_exhaustive = true; + }, + _ => {}, } } ControlFlow::::Continue(()) diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 80cf081992cc..42dc9f2f1fa8 100644 --- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -3,13 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; use rustc_ast::{BorrowKind, Mutability}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -56,12 +57,16 @@ declare_clippy_lint! { /// } /// ``` /// - /// ### Note + /// ### Notes /// - /// 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). + /// - Unsafe operations only count towards the total for the innermost + /// enclosing `unsafe` block. + /// - Each call to a macro expanding to unsafe operations count for one + /// unsafe operation. + /// - 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, @@ -71,10 +76,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) - || block.span.in_external_macro(cx.tcx.sess.source_map()) - || block.span.is_desugaring(DesugaringKind::Await) - { + if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || block.span.from_expansion() { return; } let unsafe_ops = UnsafeExprCollector::collect_unsafe_exprs(cx, block); @@ -100,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { struct UnsafeExprCollector<'tcx> { tcx: TyCtxt<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>, - unsafe_ops: Vec<(&'static str, Span)>, + unsafe_ops: FxHashMap, } impl<'tcx> UnsafeExprCollector<'tcx> { @@ -108,10 +110,33 @@ impl<'tcx> UnsafeExprCollector<'tcx> { let mut collector = Self { tcx: cx.tcx, typeck_results: cx.typeck_results(), - unsafe_ops: vec![], + unsafe_ops: FxHashMap::default(), }; collector.visit_block(block); - collector.unsafe_ops + #[allow( + rustc::potential_query_instability, + reason = "span ordering only needed inside the one expression being walked" + )] + let mut unsafe_ops = collector + .unsafe_ops + .into_iter() + .map(|(span, msg)| (msg, span)) + .collect::>(); + unsafe_ops.sort_unstable(); + unsafe_ops + } +} + +impl UnsafeExprCollector<'_> { + fn insert_span(&mut self, span: Span, message: &'static str) { + if span.from_expansion() { + self.unsafe_ops.insert( + span.source_callsite(), + "this macro call expands into one or more unsafe operations", + ); + } else { + self.unsafe_ops.insert(span, message); + } } } @@ -126,7 +151,10 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { return self.visit_expr(e); }, - ExprKind::InlineAsm(_) => self.unsafe_ops.push(("inline assembly used here", expr.span)), + // Do not recurse inside an inner `unsafe` block, it will be checked on its own + ExprKind::Block(block, _) if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) => return, + + ExprKind::InlineAsm(_) => self.insert_span(expr.span, "inline assembly used here"), ExprKind::AddrOf(BorrowKind::Raw, _, mut inner) => { while let ExprKind::Field(prefix, _) = inner.kind @@ -139,7 +167,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { ExprKind::Field(e, _) => { if self.typeck_results.expr_ty(e).is_union() { - self.unsafe_ops.push(("union field access occurs here", expr.span)); + self.insert_span(expr.span, "union field access occurs here"); } }, @@ -157,12 +185,11 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { .. }, )) => { - self.unsafe_ops - .push(("access of a mutable static occurs here", expr.span)); + self.insert_span(expr.span, "access of a mutable static occurs here"); }, 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)); + self.insert_span(expr.span, "raw pointer dereference occurs here"); }, ExprKind::Call(path_expr, _) => { @@ -172,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { _ => None, }; if opt_sig.is_some_and(|sig| sig.safety().is_unsafe()) { - self.unsafe_ops.push(("unsafe function call occurs here", expr.span)); + self.insert_span(expr.span, "unsafe function call occurs here"); } }, @@ -182,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { .type_dependent_def_id(expr.hir_id) .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)); + self.insert_span(expr.span, "unsafe method call occurs here"); } }, @@ -203,8 +230,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { } )) ) { - self.unsafe_ops - .push(("modification of a mutable static occurs here", expr.span)); + self.insert_span(expr.span, "modification of a mutable static occurs here"); return self.visit_expr(rhs); } }, diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 3d2285efbe18..f3e42b1c58f8 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,7 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet; +use clippy_utils::source::HasSession as _; use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use core::ops::ControlFlow; @@ -18,9 +18,9 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; use rustc_session::impl_lint_pass; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -269,18 +269,27 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // If the argument is never used mutably, we emit the warning. let sp = input.span; if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind { + let Some(after_mut_span) = cx.sess().source_map().span_extend_to_prev_str( + inner_ty.ty.span.shrink_to_lo(), + "mut", + true, + true, + ) else { + return; + }; + let mut_span = after_mut_span.with_lo(after_mut_span.lo() - BytePos(3)); let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id)); span_lint_hir_and_then( cx, NEEDLESS_PASS_BY_REF_MUT, cx.tcx.local_def_id_to_hir_id(*fn_def_id), sp, - "this argument is a mutable reference, but not used mutably", + "this parameter is a mutable reference but is not used mutably", |diag| { diag.span_suggestion( - sp, - "consider changing to".to_string(), - format!("&{}", snippet(cx, cx.tcx.hir_span(inner_ty.ty.hir_id), "_"),), + mut_span, + "consider removing this `mut`", + "", Applicability::Unspecified, ); if cx.effective_visibilities.is_exported(*fn_def_id) { diff --git a/clippy_lints/src/ptr/cmp_null.rs b/clippy_lints/src/ptr/cmp_null.rs index 905b48e6d1d4..f2d1c855eddd 100644 --- a/clippy_lints/src/ptr/cmp_null.rs +++ b/clippy_lints/src/ptr/cmp_null.rs @@ -14,13 +14,14 @@ pub(super) fn check<'tcx>( l: &Expr<'_>, r: &Expr<'_>, ) -> bool { + let mut applicability = Applicability::MachineApplicable; let non_null_path_snippet = match ( is_lint_allowed(cx, CMP_NULL, expr.hir_id), is_null_path(cx, l), is_null_path(cx, r), ) { - (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_paren(), - (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(), + (false, true, false) => Sugg::hir_with_context(cx, r, expr.span.ctxt(), "..", &mut applicability).maybe_paren(), + (false, false, true) => Sugg::hir_with_context(cx, l, expr.span.ctxt(), "..", &mut applicability).maybe_paren(), _ => return false, }; let invert = if op == BinOpKind::Eq { "" } else { "!" }; @@ -32,7 +33,7 @@ pub(super) fn check<'tcx>( "comparing with null is better expressed by the `.is_null()` method", "try", format!("{invert}{non_null_path_snippet}.is_null()",), - Applicability::MachineApplicable, + applicability, ); true } diff --git a/clippy_lints/src/ptr/mod.rs b/clippy_lints/src/ptr/mod.rs index 6b2647e7b0a2..c4f40a7ffcaa 100644 --- a/clippy_lints/src/ptr/mod.rs +++ b/clippy_lints/src/ptr/mod.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// This lint checks for equality comparisons with `ptr::null` + /// This lint checks for equality comparisons with `ptr::null` or `ptr::null_mut` /// /// ### Why is this bad? /// It's easier and more readable to use the inherent @@ -56,7 +56,7 @@ declare_clippy_lint! { /// ```rust,ignore /// use std::ptr; /// - /// if x == ptr::null { + /// if x == ptr::null() { /// // .. /// } /// ``` diff --git a/clippy_lints/src/same_length_and_capacity.rs b/clippy_lints/src/same_length_and_capacity.rs new file mode 100644 index 000000000000..042dec35f7c9 --- /dev/null +++ b/clippy_lints/src/same_length_and_capacity.rs @@ -0,0 +1,105 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::res::MaybeDef; +use clippy_utils::{eq_expr_value, sym}; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::sym as rustc_sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usages of `Vec::from_raw_parts` and `String::from_raw_parts` + /// where the same expression is used for the length and the capacity. + /// + /// ### Why is this bad? + /// + /// If the same expression is being passed for the length and + /// capacity, it is most likely a semantic error. In the case of a + /// Vec, for example, the only way to end up with one that has + /// the same length and capacity is by going through a boxed slice, + /// e.g. `Box::from(some_vec)`, which shrinks the capacity to match + /// the length. + /// + /// ### Example + /// + /// ```no_run + /// #![feature(vec_into_raw_parts)] + /// let mut original: Vec:: = Vec::with_capacity(20); + /// original.extend([1, 2, 3, 4, 5]); + /// + /// let (ptr, mut len, cap) = original.into_raw_parts(); + /// + /// // I will add three more integers: + /// unsafe { + /// let ptr = ptr as *mut i32; + /// + /// for i in 6..9 { + /// *ptr.add(i - 1) = i as i32; + /// len += 1; + /// } + /// } + /// + /// // But I forgot the capacity was separate from the length: + /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, len) }; + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![feature(vec_into_raw_parts)] + /// let mut original: Vec:: = Vec::with_capacity(20); + /// original.extend([1, 2, 3, 4, 5]); + /// + /// let (ptr, mut len, cap) = original.into_raw_parts(); + /// + /// // I will add three more integers: + /// unsafe { + /// let ptr = ptr as *mut i32; + /// + /// for i in 6..9 { + /// *ptr.add(i - 1) = i as i32; + /// len += 1; + /// } + /// } + /// + /// // This time, leverage the previously saved capacity: + /// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, cap) }; + /// ``` + #[clippy::version = "1.93.0"] + pub SAME_LENGTH_AND_CAPACITY, + pedantic, + "`from_raw_parts` with same length and capacity" +} +declare_lint_pass!(SameLengthAndCapacity => [SAME_LENGTH_AND_CAPACITY]); + +impl<'tcx> LateLintPass<'tcx> for SameLengthAndCapacity { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Call(path_expr, args) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, fn_path)) = path_expr.kind + && fn_path.ident.name == sym::from_raw_parts + && args.len() >= 3 + && eq_expr_value(cx, &args[1], &args[2]) + { + let middle_ty = cx.typeck_results().node_type(ty.hir_id); + if middle_ty.is_diag_item(cx, rustc_sym::Vec) { + span_lint_and_help( + cx, + SAME_LENGTH_AND_CAPACITY, + expr.span, + "usage of `Vec::from_raw_parts` with the same expression for length and capacity", + None, + "try `Box::from(slice::from_raw_parts(...)).into::>()`", + ); + } else if middle_ty.is_lang_item(cx, LangItem::String) { + span_lint_and_help( + cx, + SAME_LENGTH_AND_CAPACITY, + expr.span, + "usage of `String::from_raw_parts` with the same expression for length and capacity", + None, + "try `String::from(str::from_utf8_unchecked(slice::from_raw_parts(...)))`", + ); + } + } + } +} diff --git a/clippy_lints/src/set_contains_or_insert.rs b/clippy_lints/src/set_contains_or_insert.rs index 688da33a1777..7482bac4c7b4 100644 --- a/clippy_lints/src/set_contains_or_insert.rs +++ b/clippy_lints/src/set_contains_or_insert.rs @@ -112,6 +112,16 @@ fn try_parse_op_call<'tcx>( None } +fn is_set_mutated<'tcx>(cx: &LateContext<'tcx>, contains_expr: &OpExpr<'tcx>, expr: &'tcx Expr<'_>) -> bool { + // Guard on type to avoid useless potentially expansive `SpanlessEq` checks + cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr() + && matches!( + cx.typeck_results().expr_ty(expr).peel_refs().opt_diag_name(cx), + Some(sym::HashSet | sym::BTreeSet) + ) + && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, expr.peel_borrows()) +} + fn find_insert_calls<'tcx>( cx: &LateContext<'tcx>, contains_expr: &OpExpr<'tcx>, @@ -122,9 +132,14 @@ fn find_insert_calls<'tcx>( && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver) && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value) { - ControlFlow::Break(insert_expr) - } else { - ControlFlow::Continue(()) + return ControlFlow::Break(Some(insert_expr)); } + + if is_set_mutated(cx, contains_expr, e) { + return ControlFlow::Break(None); + } + + ControlFlow::Continue(()) }) + .flatten() } diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index e0fdca97dbee..3ba59aefea06 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Spanned; use rustc_span::sym; declare_clippy_lint! { @@ -84,43 +83,38 @@ impl_lint_pass!(UncheckedTimeSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_T impl LateLintPass<'_> for UncheckedTimeSubtraction { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Binary( - Spanned { - node: BinOpKind::Sub, .. + let (lhs, rhs) = match expr.kind { + ExprKind::Binary(op, lhs, rhs) if matches!(op.node, BinOpKind::Sub,) => (lhs, rhs), + ExprKind::MethodCall(fn_name, lhs, [rhs], _) if cx.ty_based_def(expr).is_diag_item(cx, sym::sub) => { + (lhs, rhs) }, - lhs, - rhs, - ) = expr.kind - { - let typeck = cx.typeck_results(); - let lhs_ty = typeck.expr_ty(lhs); - let rhs_ty = typeck.expr_ty(rhs); + _ => return, + }; + let typeck = cx.typeck_results(); + let lhs_name = typeck.expr_ty(lhs).opt_diag_name(cx); + let rhs_name = typeck.expr_ty(rhs).opt_diag_name(cx); - if lhs_ty.is_diag_item(cx, sym::Instant) { - // Instant::now() - instant - if is_instant_now_call(cx, lhs) - && rhs_ty.is_diag_item(cx, sym::Instant) - && let Some(sugg) = Sugg::hir_opt(cx, rhs) - { - print_manual_instant_elapsed_sugg(cx, expr, sugg); - } - // instant - duration - else if rhs_ty.is_diag_item(cx, sym::Duration) - && !expr.span.from_expansion() - && self.msrv.meets(cx, msrvs::TRY_FROM) - { - print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); - } + if lhs_name == Some(sym::Instant) { + // Instant::now() - instant + if is_instant_now_call(cx, lhs) && rhs_name == Some(sym::Instant) { + print_manual_instant_elapsed_sugg(cx, expr, rhs); } - // duration - duration - else if lhs_ty.is_diag_item(cx, sym::Duration) - && rhs_ty.is_diag_item(cx, sym::Duration) + // instant - duration + else if rhs_name == Some(sym::Duration) && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } + // duration - duration + else if lhs_name == Some(sym::Duration) + && rhs_name == Some(sym::Duration) + && !expr.span.from_expansion() + && self.msrv.meets(cx, msrvs::TRY_FROM) + { + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); + } } } @@ -150,10 +144,12 @@ fn is_chained_time_subtraction(cx: &LateContext<'_>, lhs: &Expr<'_>) -> bool { /// Returns true if the type is Duration or Instant fn is_time_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - ty.is_diag_item(cx, sym::Duration) || ty.is_diag_item(cx, sym::Instant) + matches!(ty.opt_diag_name(cx), Some(sym::Duration | sym::Instant)) } -fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) { +fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, rhs: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "", &mut applicability); span_lint_and_sugg( cx, MANUAL_INSTANT_ELAPSED, @@ -161,7 +157,7 @@ fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg "manual implementation of `Instant::elapsed`", "try", format!("{}.elapsed()", sugg.maybe_paren()), - Applicability::MachineApplicable, + applicability, ); } @@ -181,8 +177,9 @@ fn print_unchecked_duration_subtraction_sugg( // 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); + let left_sugg = Sugg::hir_with_context(cx, left_expr, expr.span.ctxt(), "", &mut applicability); + let right_sugg = + Sugg::hir_with_context(cx, right_expr, expr.span.ctxt(), "", &mut applicability); diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index 1a6262f2ff76..31e770f421e1 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_integer_literal; +use clippy_utils::is_integer_const; use clippy_utils::res::{MaybeDef, MaybeResPath}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // Catching: // `std::mem::transmute(0 as *const i32)` if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind - && is_integer_literal(inner_expr, 0) + && is_integer_const(cx, inner_expr, 0) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; @@ -42,10 +42,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t return true; } - // FIXME: - // Also catch transmutations of variables which are known nulls. - // To do this, MIR const propagation seems to be the better tool. - // Whenever MIR const prop routines are more developed, this will - // become available. As of this writing (25/03/19) it is not yet. false } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index eba60501ae21..38ce9dc3f916 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -10,13 +10,14 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParamKind, HirId, Impl, - ImplItemImplKind, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind, + ImplItemImplKind, ImplItemKind, Item, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty as MiddleTy; use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; +use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -213,6 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { path.res, Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _) ) + && !ty_is_in_generic_args(cx, hir_ty) && !types_to_skip.contains(&hir_ty.hir_id) && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()) && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() @@ -312,6 +314,38 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) { } } +fn ty_is_in_generic_args<'tcx>(cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx, AmbigArg>) -> bool { + cx.tcx.hir_parent_iter(hir_ty.hir_id).any(|(_, parent)| { + matches!(parent, Node::ImplItem(impl_item) if impl_item.generics.params.iter().any(|param| { + let GenericParamKind::Const { ty: const_ty, .. } = ¶m.kind else { + return false; + }; + ty_contains_ty(const_ty, hir_ty) + })) + }) +} + +fn ty_contains_ty<'tcx>(outer: &Ty<'tcx>, inner: &Ty<'tcx, AmbigArg>) -> bool { + struct ContainsVisitor<'tcx> { + inner: &'tcx Ty<'tcx, AmbigArg>, + } + + impl<'tcx> Visitor<'tcx> for ContainsVisitor<'tcx> { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) -> Self::Result { + if t.hir_id == self.inner.hir_id { + return ControlFlow::Break(()); + } + + walk_ty(self, t) + } + } + + let mut visitor = ContainsVisitor { inner }; + visitor.visit_ty_unambig(outer).is_break() +} + /// Checks whether types `a` and `b` have the same lifetime parameters. /// /// This function does not check that types `a` and `b` are the same types. diff --git a/clippy_lints/src/write/empty_string.rs b/clippy_lints/src/write/empty_string.rs index e7eb99eb34ec..1291f2489a21 100644 --- a/clippy_lints/src/write/empty_string.rs +++ b/clippy_lints/src/write/empty_string.rs @@ -1,37 +1,43 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::MacroCall; use clippy_utils::source::expand_past_previous_comma; -use clippy_utils::sym; +use clippy_utils::{span_extract_comments, sym}; use rustc_ast::{FormatArgs, FormatArgsPiece}; use rustc_errors::Applicability; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use super::{PRINTLN_EMPTY_STRING, WRITELN_EMPTY_STRING}; pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] { - let mut span = format_args.span; - - let lint = if name == "writeln" { - span = expand_past_previous_comma(cx, span); - - WRITELN_EMPTY_STRING - } else { - PRINTLN_EMPTY_STRING - }; + let is_writeln = name == "writeln"; span_lint_and_then( cx, - lint, + if is_writeln { + WRITELN_EMPTY_STRING + } else { + PRINTLN_EMPTY_STRING + }, macro_call.span, format!("empty string literal in `{name}!`"), |diag| { - diag.span_suggestion( - span, - "remove the empty string", - String::new(), - Applicability::MachineApplicable, - ); + if span_extract_comments(cx.sess().source_map(), macro_call.span).is_empty() { + let closing_paren = cx.sess().source_map().span_extend_to_prev_char_before( + macro_call.span.shrink_to_hi(), + ')', + false, + ); + let mut span = format_args.span.with_hi(closing_paren.lo()); + if is_writeln { + span = expand_past_previous_comma(cx, span); + } + + diag.span_suggestion(span, "remove the empty string", "", Applicability::MachineApplicable); + } else { + // If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. + diag.span_note(format_args.span, "remove the empty string"); + } }, ); } diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs index bf133d26ed9d..94c2fb20d5f5 100644 --- a/clippy_lints/src/zero_sized_map_values.rs +++ b/clippy_lints/src/zero_sized_map_values.rs @@ -49,7 +49,7 @@ impl LateLintPass<'_> for ZeroSizedMapValues { && !in_trait_impl(cx, hir_ty.hir_id) // We don't care about infer vars && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()) - && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap)) + && matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) && let ty::Adt(_, args) = ty.kind() && let ty = args.type_at(1) // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case. diff --git a/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 7eeec84720f7..b5a12606fb3e 100644 --- a/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -1,9 +1,11 @@ use crate::lint_without_lint_pass::is_lint_ref_type; use clippy_utils::diagnostics::span_lint_and_help; use regex::Regex; +use rustc_ast::token::DocFragmentKind; use rustc_hir::{Attribute, Item, ItemKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::{Span, Symbol}; declare_tool_lint! { /// ### What it does @@ -46,28 +48,22 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut check_next = false; if let ItemKind::Static(Mutability::Not, _, ty, _) = item.kind { - let lines = cx - .tcx - .hir_attrs(item.hir_id()) - .iter() - .filter_map(|attr| Attribute::doc_str(attr).map(|sym| (sym, attr))); + let lines = cx.tcx.hir_attrs(item.hir_id()).iter().filter_map(doc_attr); if is_lint_ref_type(cx, ty) { - for (line, attr) in lines { + for (line, span) in lines { let cur_line = line.as_str().trim(); if check_next && !cur_line.is_empty() { for formulation in &self.standard_formulations { let starts_with_correct_formulation = cur_line.starts_with(formulation.correction); if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) { - if let Some(ident) = attr.ident() { - span_lint_and_help( - cx, - ALMOST_STANDARD_LINT_FORMULATION, - ident.span, - "non-standard lint formulation", - None, - format!("consider using `{}`", formulation.correction), - ); - } + span_lint_and_help( + cx, + ALMOST_STANDARD_LINT_FORMULATION, + span, + "non-standard lint formulation", + None, + format!("consider using `{}`", formulation.correction), + ); return; } } @@ -84,3 +80,10 @@ impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { } } } + +fn doc_attr(attr: &Attribute) -> Option<(Symbol, Span)> { + match Attribute::doc_str_and_fragment_kind(attr) { + Some((symbol, DocFragmentKind::Raw(span))) => Some((symbol, span)), + _ => None, + } +} diff --git a/clippy_lints_internal/src/internal_paths.rs b/clippy_lints_internal/src/internal_paths.rs index 95bdf27b019c..14d4139a0065 100644 --- a/clippy_lints_internal/src/internal_paths.rs +++ b/clippy_lints_internal/src/internal_paths.rs @@ -17,6 +17,7 @@ pub static TY_CTXT: PathLookup = type_path!(rustc_middle::ty::TyCtxt); // Paths in clippy itself pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym); +pub static MAYBE_DEF: PathLookup = type_path!(clippy_utils::res::MaybeDef); pub static MSRV_STACK: PathLookup = type_path!(clippy_utils::msrvs::MsrvStack); pub static PATH_LOOKUP_NEW: PathLookup = value_path!(clippy_utils::paths::PathLookup::new); pub static SPAN_LINT_AND_THEN: PathLookup = value_path!(clippy_utils::diagnostics::span_lint_and_then); diff --git a/clippy_lints_internal/src/lib.rs b/clippy_lints_internal/src/lib.rs index d686ba73387c..cca5608fa6be 100644 --- a/clippy_lints_internal/src/lib.rs +++ b/clippy_lints_internal/src/lib.rs @@ -38,6 +38,7 @@ mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; +mod repeated_is_diagnostic_item; mod symbols; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -77,4 +78,5 @@ pub fn register_lints(store: &mut LintStore) { store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl)); store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new())); store.register_late_pass(|_| Box::new(unusual_names::UnusualNames)); + store.register_late_pass(|_| Box::new(repeated_is_diagnostic_item::RepeatedIsDiagnosticItem)); } diff --git a/clippy_lints_internal/src/repeated_is_diagnostic_item.rs b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs new file mode 100644 index 000000000000..55fb78b1e296 --- /dev/null +++ b/clippy_lints_internal/src/repeated_is_diagnostic_item.rs @@ -0,0 +1,561 @@ +use std::iter; +use std::ops::ControlFlow; + +use crate::internal_paths::MAYBE_DEF; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; +use clippy_utils::source::{snippet_indent, snippet_with_applicability}; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{eq_expr_value, if_sequence, sym}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Node, StmtKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_tool_lint! { + /// ### What it does + /// Checks for repeated use of `MaybeDef::is_diag_item`/`TyCtxt::is_diagnostic_item`; + /// suggests to first call `MaybDef::opt_diag_name`/`TyCtxt::get_diagnostic_name` and then + /// compare the output with all the `Symbol`s. + /// + /// ### Why is this bad? + /// Each of such calls ultimately invokes the `diagnostic_items` query. + /// While the query is cached, it's still better to avoid calling it multiple times if possible. + /// + /// ### Example + /// ```no_run + /// ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result) + /// cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did) + /// + /// if ty.is_diag_item(cx, sym::Option) { + /// .. + /// } else if ty.is_diag_item(cx, sym::Result) { + /// .. + /// } else { + /// .. + /// } + /// + /// if cx.tcx.is_diagnostic_item(sym::Option, did) { + /// .. + /// } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + /// .. + /// } else { + /// .. + /// } + /// + /// { + /// if ty.is_diag_item(cx, sym::Option) { + /// .. + /// } + /// if ty.is_diag_item(cx, sym::Result) { + /// .. + /// } + /// } + /// + /// { + /// if cx.tcx.is_diagnostic_item(sym::Option, did) { + /// .. + /// } + /// if cx.tcx.is_diagnostic_item(sym::Result, did) { + /// .. + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)) + /// matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)) + /// + /// match ty.opt_diag_name(cx) { + /// Some(sym::Option) => { + /// .. + /// } + /// Some(sym::Result) => { + /// .. + /// } + /// _ => { + /// .. + /// } + /// } + /// + /// match cx.tcx.get_diagnostic_name(did) { + /// Some(sym::Option) => { + /// .. + /// } + /// Some(sym::Result) => { + /// .. + /// } + /// _ => { + /// .. + /// } + /// } + /// + /// { + /// let name = ty.opt_diag_name(cx); + /// if name == Some(sym::Option) { + /// .. + /// } + /// if name == Some(sym::Result) { + /// .. + /// } + /// } + /// + /// { + /// let name = cx.tcx.get_diagnostic_name(did); + /// if name == Some(sym::Option) { + /// .. + /// } + /// if name == Some(sym::Result) { + /// .. + /// } + /// } + /// ``` + pub clippy::REPEATED_IS_DIAGNOSTIC_ITEM, + Warn, + "repeated use of `MaybeDef::is_diag_item`/`TyCtxt::is_diagnostic_item`" +} +declare_lint_pass!(RepeatedIsDiagnosticItem => [REPEATED_IS_DIAGNOSTIC_ITEM]); + +const NOTE: &str = "each call performs the same compiler query -- it's faster to query once, and reuse the results"; + +impl<'tcx> LateLintPass<'tcx> for RepeatedIsDiagnosticItem { + #[expect(clippy::too_many_lines)] + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { + for [(cond1, stmt1_span), (cond2, stmt2_span)] in block + .stmts + .windows(2) + .filter_map(|pair| { + if let [if1, if2] = pair + && let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind + && let ExprKind::If(cond1, ..) = e1.kind + && let StmtKind::Expr(e2) | StmtKind::Semi(e2) = if2.kind + && let ExprKind::If(cond2, ..) = e2.kind + { + Some([(cond1, if1.span), (cond2, if2.span)]) + } else { + None + } + }) + .chain( + if let Some(if1) = block.stmts.last() + && let StmtKind::Expr(e1) | StmtKind::Semi(e1) = if1.kind + && let ExprKind::If(cond1, ..) = e1.kind + && let Some(e2) = block.expr + && let ExprKind::If(cond2, ..) = e2.kind + { + Some([(cond1, if1.span), (cond2, e2.span)]) + } else { + None + }, + ) + { + let lint_span = stmt1_span.to(stmt2_span); + + // if recv1.is_diag_item(cx, sym1) && .. { + // .. + // } + // if recv2.is_diag_item(cx, sym2) && .. { + // .. + // } + if let Some(first @ (span1, (cx1, recv1, _))) = extract_nested_is_diag_item(cx, cond1) + && let Some(second @ (span2, (cx2, recv2, _))) = extract_nested_is_diag_item(cx, cond2) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + lint_span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.span_labels([span1, span2], "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let indent = snippet_indent(cx, stmt1_span).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + stmt1_span.shrink_to_lo(), + format!("let /* name */ = {recv}.opt_diag_name({cx_str});\n{indent}"), + )) // call `opt_diag_name` once + .chain([first, second].into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + sugg, + app, + ); + }, + ); + return; + } + + // if cx.tcx.is_diagnostic_item(sym1, did) && .. { + // .. + // } + // if cx.tcx.is_diagnostic_item(sym2, did) && .. { + // .. + // } + if let Some(first @ (span1, (tcx1, did1, _))) = extract_nested_is_diagnostic_item(cx, cond1) + && let Some(second @ (span2, (tcx2, did2, _))) = extract_nested_is_diagnostic_item(cx, cond2) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + lint_span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.span_labels([span1, span2], "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let indent = snippet_indent(cx, stmt1_span).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + stmt1_span.shrink_to_lo(), + format!("let /* name */ = {tcx}.get_diagnostic_name({did});\n{indent}"), + )) // call `get_diagnostic_name` once + .chain([first, second].into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + sugg, + app, + ); + }, + ); + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Binary(op, left, right) = expr.kind { + if op.node == BinOpKind::Or { + check_ors(cx, expr.span, left, right); + } else if op.node == BinOpKind::And + && let ExprKind::Unary(UnOp::Not, left) = left.kind + && let ExprKind::Unary(UnOp::Not, right) = right.kind + { + check_ands(cx, expr.span, left, right); + } + } else if let (conds, _) = if_sequence(expr) + && !conds.is_empty() + { + check_if_chains(cx, expr, conds); + } + } +} + +fn check_ors(cx: &LateContext<'_>, span: Span, left: &Expr<'_>, right: &Expr<'_>) { + // recv1.is_diag_item(cx, sym1) || recv2.is_diag_item(cx, sym2) + if let Some((cx1, recv1, sym1)) = extract_is_diag_item(cx, left) + && let Some((cx2, recv2, sym2)) = extract_is_diag_item(cx, right) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + format!("matches!({recv}.opt_diag_name({cx_str}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + return; + } + + // cx.tcx.is_diagnostic_item(sym1, did) || cx.tcx.is_diagnostic_item(sym2, did) + if let Some((tcx1, did1, sym1)) = extract_is_diagnostic_item(cx, left) + && let Some((tcx2, did2, sym2)) = extract_is_diagnostic_item(cx, right) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + format!("matches!({tcx}.get_diagnostic_name({did}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + } +} + +fn check_ands(cx: &LateContext<'_>, span: Span, left: &Expr<'_>, right: &Expr<'_>) { + // !recv1.is_diag_item(cx, sym1) && !recv2.is_diag_item(cx, sym2) + if let Some((cx1, recv1, sym1)) = extract_is_diag_item(cx, left) + && let Some((cx2, recv2, sym2)) = extract_is_diag_item(cx, right) + && eq_expr_value(cx, cx1, cx2) + && eq_expr_value(cx, recv1, recv2) + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let cx_str = snippet_with_applicability(cx, cx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + format!("!matches!({recv}.opt_diag_name({cx_str}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + return; + } + + // !cx.tcx.is_diagnostic_item(sym1, did) && !cx.tcx.is_diagnostic_item(sym2, did) + if let Some((tcx1, did1, sym1)) = extract_is_diagnostic_item(cx, left) + && let Some((tcx2, did2, sym2)) = extract_is_diagnostic_item(cx, right) + && eq_expr_value(cx, tcx1, tcx2) + && eq_expr_value(cx, did1, did2) + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.note(NOTE); + + let mut app = Applicability::MachineApplicable; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let did = snippet_with_applicability(cx, did1.span, "_", &mut app); + let sym1 = snippet_with_applicability(cx, sym1.span, "_", &mut app); + let sym2 = snippet_with_applicability(cx, sym2.span, "_", &mut app); + diag.span_suggestion_verbose( + span, + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + format!("!matches!({tcx}.get_diagnostic_name({did}), Some({sym1} | {sym2}))"), + app, + ); + }, + ); + } +} + +fn check_if_chains<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, conds: Vec<&'tcx Expr<'_>>) { + // if ty.is_diag_item(cx, sym1) { + // .. + // } else if ty.is_diag_item(cx, sym2) { + // .. + // } else { + // .. + // } + let mut found = conds.iter().filter_map(|cond| extract_nested_is_diag_item(cx, cond)); + if let Some(first @ (_, (cx_1, recv1, _))) = found.next() + && let other = + found.filter(|(_, (cx_, recv, _))| eq_expr_value(cx, cx_, cx_1) && eq_expr_value(cx, recv, recv1)) + && let results = iter::once(first).chain(other).collect::>() + && results.len() > 1 + { + let recv_ty = + with_forced_trimmed_paths!(format!("{}", cx.typeck_results().expr_ty_adjusted(recv1).peel_refs())); + let recv_ty = recv_ty.trim_end_matches("<'_>"); + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + expr.span, + format!("repeated calls to `{recv_ty}::is_diag_item`"), + |diag| { + diag.span_labels(results.iter().map(|(span, _)| *span), "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let cx_str = snippet_with_applicability(cx, cx_1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, recv1.span, "_", &mut app); + let span_before = if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + let_stmt.span + } else { + expr.span + }; + let indent = snippet_indent(cx, span_before).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + span_before.shrink_to_lo(), + format!("let /* name */ = {recv}.opt_diag_name({cx_str});\n{indent}"), + )) // call `opt_diag_name` once + .chain(results.into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + format!("call `{recv_ty}::opt_diag_name`, and reuse the results"), + sugg, + app, + ); + }, + ); + } + + // if cx.tcx.is_diagnostic_item(sym1, did) { + // .. + // } else if cx.tcx.is_diagnostic_item(sym2, did) { + // .. + // } else { + // .. + // } + let mut found = conds + .into_iter() + .filter_map(|cond| extract_nested_is_diagnostic_item(cx, cond)); + if let Some(first @ (_, (tcx1, did1, _))) = found.next() + && let other = found.filter(|(_, (tcx, did, _))| eq_expr_value(cx, tcx, tcx1) && eq_expr_value(cx, did, did1)) + && let results = iter::once(first).chain(other).collect::>() + && results.len() > 1 + { + span_lint_and_then( + cx, + REPEATED_IS_DIAGNOSTIC_ITEM, + expr.span, + "repeated calls to `TyCtxt::is_diagnostic_item`", + |diag| { + diag.span_labels(results.iter().map(|(span, _)| *span), "called here"); + diag.note(NOTE); + + let mut app = Applicability::HasPlaceholders; + let tcx = snippet_with_applicability(cx, tcx1.span, "_", &mut app); + let recv = snippet_with_applicability(cx, did1.span, "_", &mut app); + let span_before = if let Node::LetStmt(let_stmt) = cx.tcx.parent_hir_node(expr.hir_id) { + let_stmt.span + } else { + expr.span + }; + let indent = snippet_indent(cx, span_before).unwrap_or_default(); + let sugg: Vec<_> = iter::once(( + span_before.shrink_to_lo(), + format!("let /* name */ = {tcx}.get_diagnostic_name({recv});\n{indent}"), + )) // call `get_diagnostic_name` once + .chain(results.into_iter().map(|(expr_span, (_, _, sym))| { + let sym = snippet_with_applicability(cx, sym.span, "_", &mut app); + (expr_span, format!("/* name */ == Some({sym})")) + })) + .collect(); + + diag.multipart_suggestion_verbose( + "call `TyCtxt::get_diagnostic_name`, and reuse the results", + sugg, + app, + ); + }, + ); + } +} + +fn extract_is_diag_item<'tcx>( + cx: &LateContext<'_>, + expr: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(is_diag_item, recv, [cx_, sym], _) = expr.kind + && is_diag_item.ident.name == sym::is_diag_item + // Whether this a method from the `MaybeDef` trait + && let Some(did) = cx.ty_based_def(expr).opt_parent(cx).opt_def_id() + && MAYBE_DEF.matches(cx, did) + { + Some((cx_, recv, sym)) + } else { + None + } +} + +fn extract_is_diagnostic_item<'tcx>( + cx: &LateContext<'_>, + expr: &'tcx Expr<'tcx>, +) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(is_diag_item, tcx, [sym, did], _) = expr.kind + && is_diag_item.ident.name == sym::is_diagnostic_item + // Whether this is an inherent method on `TyCtxt` + && cx + .ty_based_def(expr) + .opt_parent(cx) + .opt_impl_ty(cx) + .is_diag_item(cx, sym::TyCtxt) + { + Some((tcx, did, sym)) + } else { + None + } +} + +fn extract_nested_is_diag_item<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, +) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { + for_each_expr(cx, cond, |cond_part| { + if let Some(res) = extract_is_diag_item(cx, cond_part) { + ControlFlow::Break((cond_part.span, res)) + } else { + ControlFlow::Continue(()) + } + }) +} + +fn extract_nested_is_diagnostic_item<'tcx>( + cx: &LateContext<'tcx>, + cond: &'tcx Expr<'_>, +) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> { + for_each_expr(cx, cond, |cond_part| { + if let Some(res) = extract_is_diagnostic_item(cx, cond_part) { + ControlFlow::Break((cond_part.span, res)) + } else { + ControlFlow::Continue(()) + } + }) +} diff --git a/clippy_utils/README.md b/clippy_utils/README.md index dc8695fef9f5..01257c1a3059 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-12-11 +nightly-2025-12-25 ``` diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 2fd773b06781..8820801853e0 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -86,7 +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().any(|attr| attr.is_doc_hidden()) + attrs.iter().any(AttributeExt::is_doc_hidden) } /// Checks whether the given ADT, or any of its fields/variants, are marked as `#[non_exhaustive]` diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index e43b0b95d9f7..9574e6fa40b0 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -809,10 +809,12 @@ impl<'tcx> ConstEvalCtxt<'tcx> { | sym::i128_legacy_const_max ) ) || self.tcx.opt_parent(did).is_some_and(|parent| { - parent.is_diag_item(&self.tcx, sym::f16_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f32_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f64_consts_mod) - || parent.is_diag_item(&self.tcx, sym::f128_consts_mod) + matches!( + parent.opt_diag_name(&self.tcx), + Some( + sym::f16_consts_mod | sym::f32_consts_mod | sym::f64_consts_mod | sym::f128_consts_mod + ) + ) })) => { did @@ -1139,7 +1141,9 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, + ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + None + }, }, } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 5cadf5fbb869..055f6d03eff0 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -4,14 +4,17 @@ use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast; use rustc_ast::ast::InlineAsmTemplatePiece; -use rustc_data_structures::fx::FxHasher; +use rustc_data_structures::fx::{FxHasher, FxIndexMap}; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; use rustc_hir::{ - AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, Expr, - ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, - LifetimeKind, Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, - StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, + AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, ConstItemRhs, + Expr, ExprField, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericArgs, GenericBound, GenericBounds, + GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind, + LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind, + Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, + TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind, }; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; @@ -106,6 +109,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { left_ctxt: SyntaxContext::root(), right_ctxt: SyntaxContext::root(), locals: HirIdMap::default(), + local_items: FxIndexMap::default(), } } @@ -144,6 +148,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`, // these blocks are considered equal since `x` is mapped to `y`. pub locals: HirIdMap, + pub local_items: FxIndexMap, } impl HirEqInterExpr<'_, '_, '_> { @@ -168,6 +173,189 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_pat(l.pat, r.pat) }, (StmtKind::Expr(l), StmtKind::Expr(r)) | (StmtKind::Semi(l), StmtKind::Semi(r)) => self.eq_expr(l, r), + (StmtKind::Item(l), StmtKind::Item(r)) => self.eq_item(*l, *r), + _ => false, + } + } + + pub fn eq_item(&mut self, l: ItemId, r: ItemId) -> bool { + let left = self.inner.cx.tcx.hir_item(l); + let right = self.inner.cx.tcx.hir_item(r); + let eq = match (left.kind, right.kind) { + ( + ItemKind::Const(l_ident, l_generics, l_ty, ConstItemRhs::Body(l_body)), + ItemKind::Const(r_ident, r_generics, r_ty, ConstItemRhs::Body(r_body)), + ) => { + l_ident.name == r_ident.name + && self.eq_generics(l_generics, r_generics) + && self.eq_ty(l_ty, r_ty) + && self.eq_body(l_body, r_body) + }, + (ItemKind::Static(l_mut, l_ident, l_ty, l_body), ItemKind::Static(r_mut, r_ident, r_ty, r_body)) => { + l_mut == r_mut && l_ident.name == r_ident.name && self.eq_ty(l_ty, r_ty) && self.eq_body(l_body, r_body) + }, + ( + ItemKind::Fn { + sig: l_sig, + ident: l_ident, + generics: l_generics, + body: l_body, + has_body: l_has_body, + }, + ItemKind::Fn { + sig: r_sig, + ident: r_ident, + generics: r_generics, + body: r_body, + has_body: r_has_body, + }, + ) => { + l_ident.name == r_ident.name + && (l_has_body == r_has_body) + && self.eq_fn_sig(&l_sig, &r_sig) + && self.eq_generics(l_generics, r_generics) + && self.eq_body(l_body, r_body) + }, + (ItemKind::TyAlias(l_ident, l_generics, l_ty), ItemKind::TyAlias(r_ident, r_generics, r_ty)) => { + l_ident.name == r_ident.name && self.eq_generics(l_generics, r_generics) && self.eq_ty(l_ty, r_ty) + }, + (ItemKind::Use(l_path, l_kind), ItemKind::Use(r_path, r_kind)) => { + self.eq_path_segments(l_path.segments, r_path.segments) + && match (l_kind, r_kind) { + (UseKind::Single(l_ident), UseKind::Single(r_ident)) => l_ident.name == r_ident.name, + (UseKind::Glob, UseKind::Glob) | (UseKind::ListStem, UseKind::ListStem) => true, + _ => false, + } + }, + (ItemKind::Mod(l_ident, l_mod), ItemKind::Mod(r_ident, r_mod)) => { + l_ident.name == r_ident.name && over(l_mod.item_ids, r_mod.item_ids, |l, r| self.eq_item(*l, *r)) + }, + _ => false, + }; + if eq { + self.local_items.insert(l.owner_id.to_def_id(), r.owner_id.to_def_id()); + } + eq + } + + fn eq_fn_sig(&mut self, left: &FnSig<'_>, right: &FnSig<'_>) -> bool { + left.header.safety == right.header.safety + && left.header.constness == right.header.constness + && left.header.asyncness == right.header.asyncness + && left.header.abi == right.header.abi + && self.eq_fn_decl(left.decl, right.decl) + } + + fn eq_fn_decl(&mut self, left: &FnDecl<'_>, right: &FnDecl<'_>) -> bool { + over(left.inputs, right.inputs, |l, r| self.eq_ty(l, r)) + && (match (left.output, right.output) { + (FnRetTy::DefaultReturn(_), FnRetTy::DefaultReturn(_)) => true, + (FnRetTy::Return(l_ty), FnRetTy::Return(r_ty)) => self.eq_ty(l_ty, r_ty), + _ => false, + }) + && left.c_variadic == right.c_variadic + && left.implicit_self == right.implicit_self + && left.lifetime_elision_allowed == right.lifetime_elision_allowed + } + + fn eq_generics(&mut self, left: &Generics<'_>, right: &Generics<'_>) -> bool { + self.eq_generics_param(left.params, right.params) + && self.eq_generics_predicate(left.predicates, right.predicates) + } + + fn eq_generics_predicate(&mut self, left: &[WherePredicate<'_>], right: &[WherePredicate<'_>]) -> bool { + over(left, right, |l, r| match (l.kind, r.kind) { + (WherePredicateKind::BoundPredicate(l_bound), WherePredicateKind::BoundPredicate(r_bound)) => { + l_bound.origin == r_bound.origin + && self.eq_ty(l_bound.bounded_ty, r_bound.bounded_ty) + && self.eq_generics_param(l_bound.bound_generic_params, r_bound.bound_generic_params) + && self.eq_generics_bound(l_bound.bounds, r_bound.bounds) + }, + (WherePredicateKind::RegionPredicate(l_region), WherePredicateKind::RegionPredicate(r_region)) => { + Self::eq_lifetime(l_region.lifetime, r_region.lifetime) + && self.eq_generics_bound(l_region.bounds, r_region.bounds) + }, + (WherePredicateKind::EqPredicate(l_eq), WherePredicateKind::EqPredicate(r_eq)) => { + self.eq_ty(l_eq.lhs_ty, r_eq.lhs_ty) + }, + _ => false, + }) + } + + fn eq_generics_bound(&mut self, left: GenericBounds<'_>, right: GenericBounds<'_>) -> bool { + over(left, right, |l, r| match (l, r) { + (GenericBound::Trait(l_trait), GenericBound::Trait(r_trait)) => { + l_trait.modifiers == r_trait.modifiers + && self.eq_path(l_trait.trait_ref.path, r_trait.trait_ref.path) + && self.eq_generics_param(l_trait.bound_generic_params, r_trait.bound_generic_params) + }, + (GenericBound::Outlives(l_lifetime), GenericBound::Outlives(r_lifetime)) => { + Self::eq_lifetime(l_lifetime, r_lifetime) + }, + (GenericBound::Use(l_capture, _), GenericBound::Use(r_capture, _)) => { + over(l_capture, r_capture, |l, r| match (l, r) { + (PreciseCapturingArgKind::Lifetime(l_lifetime), PreciseCapturingArgKind::Lifetime(r_lifetime)) => { + Self::eq_lifetime(l_lifetime, r_lifetime) + }, + (PreciseCapturingArgKind::Param(l_param), PreciseCapturingArgKind::Param(r_param)) => { + l_param.ident == r_param.ident && l_param.res == r_param.res + }, + _ => false, + }) + }, + _ => false, + }) + } + + fn eq_generics_param(&mut self, left: &[GenericParam<'_>], right: &[GenericParam<'_>]) -> bool { + over(left, right, |l, r| { + (match (l.name, r.name) { + (ParamName::Plain(l_ident), ParamName::Plain(r_ident)) + | (ParamName::Error(l_ident), ParamName::Error(r_ident)) => l_ident.name == r_ident.name, + (ParamName::Fresh, ParamName::Fresh) => true, + _ => false, + }) && l.pure_wrt_drop == r.pure_wrt_drop + && self.eq_generics_param_kind(&l.kind, &r.kind) + && (matches!( + (l.source, r.source), + (GenericParamSource::Generics, GenericParamSource::Generics) + | (GenericParamSource::Binder, GenericParamSource::Binder) + )) + }) + } + + fn eq_generics_param_kind(&mut self, left: &GenericParamKind<'_>, right: &GenericParamKind<'_>) -> bool { + match (left, right) { + (GenericParamKind::Lifetime { kind: l_kind }, GenericParamKind::Lifetime { kind: r_kind }) => { + match (l_kind, r_kind) { + (LifetimeParamKind::Explicit, LifetimeParamKind::Explicit) + | (LifetimeParamKind::Error, LifetimeParamKind::Error) => true, + (LifetimeParamKind::Elided(l_lifetime_kind), LifetimeParamKind::Elided(r_lifetime_kind)) => { + l_lifetime_kind == r_lifetime_kind + }, + _ => false, + } + }, + ( + GenericParamKind::Type { + default: l_default, + synthetic: l_synthetic, + }, + GenericParamKind::Type { + default: r_default, + synthetic: r_synthetic, + }, + ) => both(*l_default, *r_default, |l, r| self.eq_ty(l, r)) && l_synthetic == r_synthetic, + ( + GenericParamKind::Const { + ty: l_ty, + default: l_default, + }, + GenericParamKind::Const { + ty: r_ty, + default: r_default, + }, + ) => self.eq_ty(l_ty, r_ty) && both(*l_default, *r_default, |l, r| self.eq_const_arg(l, r)), _ => false, } } @@ -479,16 +667,20 @@ impl HirEqInterExpr<'_, '_, '_> { (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, (ConstArgKind::Struct(path_a, inits_a), ConstArgKind::Struct(path_b, inits_b)) => { self.eq_qpath(path_a, path_b) - && inits_a.iter().zip(*inits_b).all(|(init_a, init_b)| { - self.eq_const_arg(init_a.expr, init_b.expr) - }) - } + && inits_a + .iter() + .zip(*inits_b) + .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) + }, // Use explicit match for now since ConstArg is undergoing flux. - (ConstArgKind::Path(..), _) - | (ConstArgKind::Anon(..), _) - | (ConstArgKind::Infer(..), _) - | (ConstArgKind::Struct(..), _) - | (ConstArgKind::Error(..), _) => false, + ( + ConstArgKind::Path(..) + | ConstArgKind::Anon(..) + | ConstArgKind::Infer(..) + | ConstArgKind::Struct(..) + | ConstArgKind::Error(..), + _, + ) => false, } } @@ -570,6 +762,17 @@ impl HirEqInterExpr<'_, '_, '_> { match (left.res, right.res) { (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r), (Res::Local(_), _) | (_, Res::Local(_)) => false, + (Res::Def(l_kind, l), Res::Def(r_kind, r)) + if l_kind == r_kind + && let DefKind::Const + | DefKind::Static { .. } + | DefKind::Fn + | DefKind::TyAlias + | DefKind::Use + | DefKind::Mod = l_kind => + { + (l == r || self.local_items.get(&l) == Some(&r)) && self.eq_path_segments(left.segments, right.segments) + }, _ => self.eq_path_segments(left.segments, right.segments), } } @@ -1344,7 +1547,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { for init in *inits { self.hash_const_arg(init.expr); } - } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 409f13013489..954c32687af6 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2490,7 +2490,7 @@ pub enum DefinedTy<'tcx> { /// in the context of its definition site. We also track the `def_id` of its /// definition site. /// - /// WARNING: As the `ty` in in the scope of the definition, not of the function + /// WARNING: As the `ty` is in the scope of the definition, not of the function /// using it, you must be very careful with how you use it. Using it in the wrong /// scope easily results in ICEs. Mir { @@ -2719,7 +2719,6 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtx moved_before_use, same_ctxt, }, - Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow"), None => ExprUseCtxt { node: Node::Crate(cx.tcx.hir_root_module()), child_id: HirId::INVALID, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index b48d17863aa3..f30f26f3a70b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -13,8 +13,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, DesugaringKind, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, - Span, SpanData, SyntaxContext, hygiene, + BytePos, DUMMY_SP, DesugaringKind, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, + SyntaxContext, hygiene, }; use std::borrow::Cow; use std::fmt; diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 00f4a9c7e586..a0d2e8673fe6 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -58,6 +58,7 @@ generate! { LowerHex, MAX, MIN, + MaybeDef, MsrvStack, Octal, OpenOptions, @@ -167,6 +168,7 @@ generate! { from_ne_bytes, from_ptr, from_raw, + from_raw_parts, from_str_radix, fs, fuse, @@ -192,6 +194,8 @@ generate! { io, is_ascii, is_char_boundary, + is_diag_item, + is_diagnostic_item, is_digit, is_empty, is_err, @@ -275,6 +279,7 @@ generate! { read_to_string, read_unaligned, read_volatile, + reduce, redundant_imports, redundant_pub_crate, regex, @@ -282,6 +287,7 @@ generate! { repeat, replace, replacen, + res, reserve, resize, restriction, @@ -364,6 +370,7 @@ generate! { trim_start, trim_start_matches, truncate, + try_fold, try_for_each, unreachable_pub, unsafe_removed_from_name, diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 1384f4078ebe..dbec79e111fb 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-12-11" +channel = "nightly-2025-12-25" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/tests/ui-internal/repeated_is_diagnostic_item.fixed b/tests/ui-internal/repeated_is_diagnostic_item.fixed new file mode 100644 index 000000000000..fcacf504804c --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.fixed @@ -0,0 +1,77 @@ +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn binops(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + let _ = !matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + //~^ repeated_is_diagnostic_item + + // Don't lint: `is_diagnostic_item` is called not on `TyCtxt` + struct FakeTyCtxt; + impl FakeTyCtxt { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let f = FakeTyCtxt; + let _ = f.is_diagnostic_item(sym::Option, did) || f.is_diagnostic_item(sym::Result, did); + + // Don't lint: `is_diagnostic_item` on `TyCtxt` comes from a(n unrelated) trait + trait IsDiagnosticItem { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool; + } + impl IsDiagnosticItem for TyCtxt<'_> { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let _ = IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Option, did) + || IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Result, did); + + // Don't lint: `is_diag_item` is an inherent method + struct DoesntImplMaybeDef; + impl DoesntImplMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let d = DoesntImplMaybeDef; + let _ = d.is_diag_item(cx, sym::Option) || d.is_diag_item(cx, sym::Result); + + // Don't lint: `is_diag_item` comes from a trait other than `MaybeDef` + trait FakeMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool; + } + struct Bar; + impl FakeMaybeDef for Bar { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let b = Bar; + let _ = b.is_diag_item(cx, sym::Option) || b.is_diag_item(cx, sym::Result); +} + +fn main() {} diff --git a/tests/ui-internal/repeated_is_diagnostic_item.rs b/tests/ui-internal/repeated_is_diagnostic_item.rs new file mode 100644 index 000000000000..7ccbbfd94029 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.rs @@ -0,0 +1,77 @@ +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn binops(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); + //~^ repeated_is_diagnostic_item + let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); + //~^ repeated_is_diagnostic_item + let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); + //~^ repeated_is_diagnostic_item + + // Don't lint: `is_diagnostic_item` is called not on `TyCtxt` + struct FakeTyCtxt; + impl FakeTyCtxt { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let f = FakeTyCtxt; + let _ = f.is_diagnostic_item(sym::Option, did) || f.is_diagnostic_item(sym::Result, did); + + // Don't lint: `is_diagnostic_item` on `TyCtxt` comes from a(n unrelated) trait + trait IsDiagnosticItem { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool; + } + impl IsDiagnosticItem for TyCtxt<'_> { + fn is_diagnostic_item(&self, sym: Symbol, did: DefId) -> bool { + unimplemented!() + } + } + let _ = IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Option, did) + || IsDiagnosticItem::is_diagnostic_item(&cx.tcx, sym::Result, did); + + // Don't lint: `is_diag_item` is an inherent method + struct DoesntImplMaybeDef; + impl DoesntImplMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let d = DoesntImplMaybeDef; + let _ = d.is_diag_item(cx, sym::Option) || d.is_diag_item(cx, sym::Result); + + // Don't lint: `is_diag_item` comes from a trait other than `MaybeDef` + trait FakeMaybeDef { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool; + } + struct Bar; + impl FakeMaybeDef for Bar { + fn is_diag_item(&self, cx: &LateContext, sym: Symbol) -> bool { + unimplemented!() + } + } + let b = Bar; + let _ = b.is_diag_item(cx, sym::Option) || b.is_diag_item(cx, sym::Result); +} + +fn main() {} diff --git a/tests/ui-internal/repeated_is_diagnostic_item.stderr b/tests/ui-internal/repeated_is_diagnostic_item.stderr new file mode 100644 index 000000000000..8c52ba561d79 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item.stderr @@ -0,0 +1,82 @@ +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:18:13 + | +LL | let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results + = note: `-D clippy::repeated-is-diagnostic-item` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeated_is_diagnostic_item)]` +help: call `Ty::opt_diag_name`, and reuse the results + | +LL - let _ = ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result); +LL + let _ = matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:20:13 + | +LL | let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL - let _ = !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result); +LL + let _ = !matches!(ty.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `AdtDef::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:22:13 + | +LL | let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `AdtDef::opt_diag_name`, and reuse the results + | +LL - let _ = adt_def.is_diag_item(cx, sym::Option) || adt_def.is_diag_item(cx, sym::Result); +LL + let _ = matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `AdtDef::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:24:13 + | +LL | let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `AdtDef::opt_diag_name`, and reuse the results + | +LL - let _ = !adt_def.is_diag_item(cx, sym::Option) && !adt_def.is_diag_item(cx, sym::Result); +LL + let _ = !matches!(adt_def.opt_diag_name(cx), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:26:13 + | +LL | let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL - let _ = cx.tcx.is_diagnostic_item(sym::Option, did) || cx.tcx.is_diagnostic_item(sym::Result, did); +LL + let _ = matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item.rs:28:13 + | +LL | let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL - let _ = !cx.tcx.is_diagnostic_item(sym::Option, did) && !cx.tcx.is_diagnostic_item(sym::Result, did); +LL + let _ = !matches!(cx.tcx.get_diagnostic_name(did), Some(sym::Option | sym::Result)); + | + +error: aborting due to 6 previous errors + diff --git a/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs new file mode 100644 index 000000000000..807da07ce8aa --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs @@ -0,0 +1,213 @@ +//@no-rustfix +#![feature(rustc_private)] + +extern crate rustc_hir; +extern crate rustc_lint; +extern crate rustc_middle; +extern crate rustc_span; + +use clippy_utils::res::MaybeDef; +use clippy_utils::sym; +use rustc_hir::def_id::DefId; +use rustc_lint::LateContext; +use rustc_middle::ty::{AdtDef, Ty, TyCtxt}; +use rustc_span::Symbol; + +fn main() {} + +// if-chains with repeated calls on the same `ty` +fn if_chains(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + let _ = if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + "Option" + } else if ty.is_diag_item(cx, sym::Result) { + "Result" + } else { + return; + }; + // should ideally suggest the following: + // let _ = match ty.opt_diag_name() { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => { + // return; + // } + // }; + + // same but in a stmt + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + eprintln!("Option"); + } else if ty.is_diag_item(cx, sym::Result) { + eprintln!("Result"); + } + // should ideally suggest the following: + // match ty.opt_diag_name() { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => {} + // }; + + // nested conditions + let _ = if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + "Option" + } else if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + "Result" + } else { + return; + }; + + let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + "Option" + } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + "Result" + } else { + return; + }; + // should ideally suggest the following: + // let _ = match cx.get_diagnostic_name(did) { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => { + // return; + // } + // }; + + // same but in a stmt + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + eprintln!("Option"); + } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + eprintln!("Result"); + } + // should ideally suggest the following: + // match cx.tcx.get_diagnostic_name(did) { + // Some(sym::Option) => { + // "Option" + // } + // Some(sym::Result) => { + // "Result" + // } + // _ => {} + // }; + + // nested conditions + let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + "Option" + } else if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + "Result" + } else { + return; + }; +} + +// if-chains with repeated calls on the same `ty` +fn consecutive_ifs(cx: &LateContext<'_>, ty: Ty<'_>, adt_def: &AdtDef<'_>) { + let did = ty.opt_def_id().unwrap(); + + { + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) { + println!("Result"); + } + println!("done!") + } + + // nested conditions + { + if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + println!("Result"); + } + println!("done!") + } + + { + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) { + println!("Result"); + } + println!("done!") + } + + // nested conditions + { + if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + println!("Result"); + } + println!("done!") + } + + // All the same, but the second if is the final expression + { + if ty.is_diag_item(cx, sym::Option) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) { + println!("Result"); + } + } + + // nested conditions + { + if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + println!("Result"); + } + } + + { + if cx.tcx.is_diagnostic_item(sym::Option, did) { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) { + println!("Result"); + } + } + + // nested conditions + { + if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + //~^ repeated_is_diagnostic_item + println!("Option"); + } + if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + println!("Result"); + } + } +} diff --git a/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr new file mode 100644 index 000000000000..890817da5235 --- /dev/null +++ b/tests/ui-internal/repeated_is_diagnostic_item_unfixable.stderr @@ -0,0 +1,374 @@ +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:22:13 + | +LL | let _ = if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results + = note: `-D clippy::repeated-is-diagnostic-item` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::repeated_is_diagnostic_item)]` +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ let _ = if /* name */ == Some(sym::Option) { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:44:5 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _____| + | | +LL | | +LL | | eprintln!("Option"); +LL | | } else if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | eprintln!("Result"); +LL | | } + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | eprintln!("Option"); +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:62:13 + | +LL | let _ = if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ let _ = if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:71:13 + | +LL | let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ let _ = if /* name */ == Some(sym::Option) { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:93:5 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _____| + | | +LL | | +LL | | eprintln!("Option"); +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | eprintln!("Result"); +LL | | } + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | eprintln!("Option"); +LL ~ } else if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:111:13 + | +LL | let _ = if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _____________| + | | +LL | | +LL | | "Option" +LL | | } else if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +... | +LL | | return; +LL | | }; + | |_____^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ let _ = if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | "Option" +LL ~ } else if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:126:9 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:138:9 + | +LL | if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:149:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:161:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:173:9 + | +LL | if ty.is_diag_item(cx, sym::Option) { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `Ty::is_diag_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:184:9 + | +LL | if ty.is_diag_item(cx, sym::Option) && 4 == 5 { + | ^ -------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if ty.is_diag_item(cx, sym::Result) && 4 == 5 { + | | -------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `Ty::opt_diag_name`, and reuse the results + | +LL ~ let /* name */ = ty.opt_diag_name(cx); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:194:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) { + | + +error: repeated calls to `TyCtxt::is_diagnostic_item` + --> tests/ui-internal/repeated_is_diagnostic_item_unfixable.rs:205:9 + | +LL | if cx.tcx.is_diagnostic_item(sym::Option, did) && 4 == 5 { + | ^ ------------------------------------------- called here + | _________| + | | +LL | | +LL | | println!("Option"); +LL | | } +LL | | if cx.tcx.is_diagnostic_item(sym::Result, did) && 4 == 5 { + | | ------------------------------------------- called here +LL | | println!("Result"); +LL | | } + | |_________^ + | + = note: each call performs the same compiler query -- it's faster to query once, and reuse the results +help: call `TyCtxt::get_diagnostic_name`, and reuse the results + | +LL ~ let /* name */ = cx.tcx.get_diagnostic_name(did); +LL ~ if /* name */ == Some(sym::Option) && 4 == 5 { +LL | +LL | println!("Option"); +LL | } +LL ~ if /* name */ == Some(sym::Result) && 4 == 5 { + | + +error: aborting due to 14 previous errors + diff --git a/tests/ui-toml/collapsible_if/collapsible_else_if.fixed b/tests/ui-toml/collapsible_if/collapsible_else_if.fixed index ec45dfd2033a..213b56b786b1 100644 --- a/tests/ui-toml/collapsible_if/collapsible_else_if.fixed +++ b/tests/ui-toml/collapsible_if/collapsible_else_if.fixed @@ -1,5 +1,5 @@ #![allow(clippy::eq_op, clippy::nonminimal_bool)] -#![warn(clippy::collapsible_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { diff --git a/tests/ui-toml/collapsible_if/collapsible_else_if.rs b/tests/ui-toml/collapsible_if/collapsible_else_if.rs index 54315a3c32bf..2d4c2c54031e 100644 --- a/tests/ui-toml/collapsible_if/collapsible_else_if.rs +++ b/tests/ui-toml/collapsible_if/collapsible_else_if.rs @@ -1,5 +1,5 @@ #![allow(clippy::eq_op, clippy::nonminimal_bool)] -#![warn(clippy::collapsible_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed index 40556ca5410f..962a4e00d86e 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.fixed @@ -3,7 +3,7 @@ // Should warn pub fn pub_foo(s: &Vec, b: &u32, x: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut *x += *b + s.len() as u32; } diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs index bbc63ceb15a3..5f584c6704f2 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs @@ -3,7 +3,7 @@ // Should warn pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut *x += *b + s.len() as u32; } diff --git a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr index c10607bf4bab..57137ab08d1e 100644 --- a/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr +++ b/tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.stderr @@ -1,8 +1,10 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui-toml/needless_pass_by_ref_mut/needless_pass_by_ref_mut.rs:5:19 | LL | pub fn pub_foo(s: &mut Vec, b: &u32, x: &mut u32) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` | = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` diff --git a/tests/ui-toml/toml_disallowed_methods/clippy.toml b/tests/ui-toml/toml_disallowed_methods/clippy.toml index c7a326f28295..2c54b73d72d7 100644 --- a/tests/ui-toml/toml_disallowed_methods/clippy.toml +++ b/tests/ui-toml/toml_disallowed_methods/clippy.toml @@ -17,4 +17,6 @@ disallowed-methods = [ # re-exports "conf_disallowed_methods::identity", "conf_disallowed_methods::renamed", + # also used in desugaring + "std::future::Future::poll", ] diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 2dac01649a0f..621317246d6d 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -80,3 +80,19 @@ fn main() { renamed(1); //~^ disallowed_methods } + +mod issue16185 { + use std::pin::Pin; + use std::task::Context; + + async fn test(f: impl Future) { + // Should not lint even though desugaring uses + // disallowed method `std::future::Future::poll()`. + f.await + } + + fn explicit>(f: Pin<&mut F>, cx: &mut Context<'_>) { + f.poll(cx); + //~^ disallowed_methods + } +} diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 20474ad6e927..8e7e112a93f3 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -99,5 +99,11 @@ error: use of a disallowed method `conf_disallowed_methods::renamed` LL | renamed(1); | ^^^^^^^ -error: aborting due to 16 previous errors +error: use of a disallowed method `std::future::Future::poll` + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:95:11 + | +LL | f.poll(cx); + | ^^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs index f467d4966aef..1c49b6e6b7b1 100644 --- a/tests/ui/assertions_on_constants.rs +++ b/tests/ui/assertions_on_constants.rs @@ -96,3 +96,8 @@ fn _f4() { assert!(C); //~^ assertions_on_constants } + +fn issue_16242(var: bool) { + // should not lint + assert!(cfg!(feature = "hey") && var); +} diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.rs b/tests/ui/branches_sharing_code/shared_at_bottom.rs index fa322dc28a78..a7f950b44caf 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -300,3 +300,65 @@ fn issue15004() { //~^ branches_sharing_code }; } + +pub fn issue15347() -> isize { + if false { + static A: isize = 4; + return A; + } else { + static A: isize = 5; + return A; + } + + if false { + //~^ branches_sharing_code + type ISize = isize; + return ISize::MAX; + } else { + type ISize = isize; + return ISize::MAX; + } + + if false { + //~^ branches_sharing_code + fn foo() -> isize { + 4 + } + return foo(); + } else { + fn foo() -> isize { + 4 + } + return foo(); + } + + if false { + //~^ branches_sharing_code + use std::num::NonZeroIsize; + return NonZeroIsize::new(4).unwrap().get(); + } else { + use std::num::NonZeroIsize; + return NonZeroIsize::new(4).unwrap().get(); + } + + if false { + //~^ branches_sharing_code + const B: isize = 5; + return B; + } else { + const B: isize = 5; + return B; + } + + // Should not lint! + const A: isize = 1; + if false { + const B: isize = A; + return B; + } else { + const C: isize = A; + return C; + } + + todo!() +} diff --git a/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 1c470fb0da5e..4ff3990232a5 100644 --- a/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -202,5 +202,73 @@ LL ~ } LL ~ 1; | -error: aborting due to 12 previous errors +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:313:5 + | +LL | / if false { +LL | | +LL | | type ISize = isize; +LL | | return ISize::MAX; + | |__________________________^ + | +help: consider moving these statements before the if + | +LL ~ type ISize = isize; +LL + return ISize::MAX; +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:322:5 + | +LL | / if false { +LL | | +LL | | fn foo() -> isize { +LL | | 4 +LL | | } +LL | | return foo(); + | |_____________________^ + | +help: consider moving these statements before the if + | +LL ~ fn foo() -> isize { +LL + 4 +LL + } +LL + return foo(); +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:335:5 + | +LL | / if false { +LL | | +LL | | use std::num::NonZeroIsize; +LL | | return NonZeroIsize::new(4).unwrap().get(); + | |___________________________________________________^ + | +help: consider moving these statements before the if + | +LL ~ use std::num::NonZeroIsize; +LL + return NonZeroIsize::new(4).unwrap().get(); +LL + if false { + | + +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:344:5 + | +LL | / if false { +LL | | +LL | | const B: isize = 5; +LL | | return B; + | |_________________^ + | +help: consider moving these statements before the if + | +LL ~ const B: isize = 5; +LL + return B; +LL + if false { + | + +error: aborting due to 16 previous errors diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 0ff1dc11c3ac..14b84b1ff1ef 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,4 +1,4 @@ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:23:5 | LL | x0 as f32; @@ -7,31 +7,31 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i64` to `f32` may cause a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:27:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `i64` to `f64` may cause a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ -error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `u32` to `f32` may cause a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ -error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `u64` to `f32` may cause a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast.rs:38:5 | LL | x3 as f32; | ^^^^^^^^^ -error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `u64` to `f64` may cause a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast.rs:41:5 | LL | x3 as f64; diff --git a/tests/ui/cast_size.r32bit.stderr b/tests/ui/cast_size.r32bit.stderr index 5811cb3607ba..2f7eeda385e5 100644 --- a/tests/ui/cast_size.r32bit.stderr +++ b/tests/ui/cast_size.r32bit.stderr @@ -13,7 +13,7 @@ LL - 1isize as i8; LL + i8::try_from(1isize); | -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `isize` to `f32` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; @@ -22,19 +22,19 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `usize` to `f32` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `isize` to `f64` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; @@ -165,13 +165,13 @@ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit LL | 1u32 as isize; | ^^^^^^^^^^^^^ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; diff --git a/tests/ui/cast_size.r64bit.stderr b/tests/ui/cast_size.r64bit.stderr index ba1419583aeb..8e5f38137602 100644 --- a/tests/ui/cast_size.r64bit.stderr +++ b/tests/ui/cast_size.r64bit.stderr @@ -13,7 +13,7 @@ LL - 1isize as i8; LL + i8::try_from(1isize); | -error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `isize` to `f32` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; @@ -22,19 +22,19 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` -error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `usize` to `f32` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ -error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `isize` to `f64` may cause a loss of precision (`isize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; @@ -165,13 +165,13 @@ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit LL | 1u32 as isize; | ^^^^^^^^^^^^^ -error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) +error: casting `i32` to `f32` may cause a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ -error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) +error: casting `usize` to `f64` may cause a loss of precision (`usize` can be up to 64 bits wide depending on the target architecture, but `f64`'s mantissa is only 52 bits wide) --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; diff --git a/tests/ui/cmp_null.fixed b/tests/ui/cmp_null.fixed index c12279cf12e6..4a0ee439e94a 100644 --- a/tests/ui/cmp_null.fixed +++ b/tests/ui/cmp_null.fixed @@ -38,3 +38,23 @@ fn issue15010() { debug_assert!(!f.is_null()); //~^ cmp_null } + +fn issue16281() { + use std::ptr; + + struct Container { + value: *const i32, + } + let x = Container { value: ptr::null() }; + + macro_rules! dot_value { + ($obj:expr) => { + $obj.value + }; + } + + if dot_value!(x).is_null() { + //~^ cmp_null + todo!() + } +} diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 2771a16e00c5..26ea8960e5fb 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -38,3 +38,23 @@ fn issue15010() { debug_assert!(f != std::ptr::null_mut()); //~^ cmp_null } + +fn issue16281() { + use std::ptr; + + struct Container { + value: *const i32, + } + let x = Container { value: ptr::null() }; + + macro_rules! dot_value { + ($obj:expr) => { + $obj.value + }; + } + + if dot_value!(x) == ptr::null() { + //~^ cmp_null + todo!() + } +} diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 381747cb3c65..51b98d2a2320 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -37,5 +37,11 @@ error: comparing with null is better expressed by the `.is_null()` method LL | debug_assert!(f != std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()` -error: aborting due to 6 previous errors +error: comparing with null is better expressed by the `.is_null()` method + --> tests/ui/cmp_null.rs:56:8 + | +LL | if dot_value!(x) == ptr::null() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dot_value!(x).is_null()` + +error: aborting due to 7 previous errors diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index e7439beef186..cd2d9be9f433 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_ifs)] -#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { @@ -70,6 +70,17 @@ fn main() { } //~^^^^^^^^ collapsible_else_if + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else if let Some(42) = Some(42) { + println!("42"); + } + //~^^^^^ collapsible_else_if + if x == "hello" { print!("Hello "); } else { @@ -78,6 +89,21 @@ fn main() { println!("world!") } } + + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } else { + println!("!"); + } + } + } #[rustfmt::skip] @@ -88,30 +114,12 @@ fn issue_7318() { } fn issue_13365() { - // all the `expect`s that we should fulfill + // ensure we fulfill `#[expect]` if true { } else { #[expect(clippy::collapsible_else_if)] if false {} } - - if true { - } else { - #[expect(clippy::style)] - if false {} - } - - if true { - } else { - #[expect(clippy::all)] - if false {} - } - - if true { - } else { - #[expect(warnings)] - if false {} - } } fn issue14799() { diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 434ba3654f98..75f204328538 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ #![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_ifs)] -#![warn(clippy::collapsible_if, clippy::collapsible_else_if)] +#![warn(clippy::collapsible_else_if)] #[rustfmt::skip] fn main() { @@ -84,6 +84,19 @@ fn main() { } //~^^^^^^^^ collapsible_else_if + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } + } + //~^^^^^ collapsible_else_if + if x == "hello" { print!("Hello "); } else { @@ -92,6 +105,21 @@ fn main() { println!("world!") } } + + if x == "hello" { + if y == "world" { + print!("Hello "); + } else { + println!("world"); + } + } else { + if let Some(42) = Some(42) { + println!("42"); + } else { + println!("!"); + } + } + } #[rustfmt::skip] @@ -104,30 +132,12 @@ fn issue_7318() { } fn issue_13365() { - // all the `expect`s that we should fulfill + // ensure we fulfill `#[expect]` if true { } else { #[expect(clippy::collapsible_else_if)] if false {} } - - if true { - } else { - #[expect(clippy::style)] - if false {} - } - - if true { - } else { - #[expect(clippy::all)] - if false {} - } - - if true { - } else { - #[expect(warnings)] - if false {} - } } fn issue14799() { diff --git a/tests/ui/collapsible_else_if.stderr b/tests/ui/collapsible_else_if.stderr index ce1da593a8e9..ebd78d2b1ffe 100644 --- a/tests/ui/collapsible_else_if.stderr +++ b/tests/ui/collapsible_else_if.stderr @@ -142,7 +142,25 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:100:10 + --> tests/ui/collapsible_else_if.rs:93:12 + | +LL | } else { + | ____________^ +LL | | if let Some(42) = Some(42) { +LL | | println!("42"); +LL | | } +LL | | } + | |_____^ + | +help: collapse nested if block + | +LL ~ } else if let Some(42) = Some(42) { +LL + println!("42"); +LL + } + | + +error: this `else { if .. }` block can be collapsed + --> tests/ui/collapsible_else_if.rs:128:10 | LL | }else{ | __________^ @@ -151,7 +169,7 @@ LL | | } | |_____^ help: collapse nested if block: `if false {}` error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:157:12 + --> tests/ui/collapsible_else_if.rs:167:12 | LL | } else { | ____________^ @@ -159,5 +177,5 @@ LL | | (if y == "world" { println!("world") } else { println!("!") }) LL | | } | |_____^ help: collapse nested if block: `if y == "world" { println!("world") } else { println!("!") }` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/crashes/ice-10148.stderr b/tests/ui/crashes/ice-10148.stderr index 639cf2dd442b..e91fb3778a31 100644 --- a/tests/ui/crashes/ice-10148.stderr +++ b/tests/ui/crashes/ice-10148.stderr @@ -2,7 +2,7 @@ error: empty string literal in `println!` --> tests/ui/crashes/ice-10148.rs:8:5 | LL | println!(with_span!(""something "")); - | ^^^^^^^^^^^^^^^^^^^^-----------^^^^^ + | ^^^^^^^^^^^^^^^^^^^^---------------^ | | | help: remove the empty string | diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index 71f00fb9aede..7b39f7ffc01a 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ //@ check-pass //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target: apple windows +//@ignore-target: windows #![crate_type = "lib"] #![no_std] diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 5c13d8622767..6aa023a8d450 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,5 +1,3 @@ -//@ignore-target: apple - #![feature(no_core, lang_items)] #![no_core] #![allow(clippy::missing_safety_doc)] diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 175dd0754081..bf022fb56a36 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/def_id_nocore.rs:33:19 + --> tests/ui/def_id_nocore.rs:31:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/empty_enum_variants_with_brackets.fixed b/tests/ui/empty_enum_variants_with_brackets.fixed index abdf6ca5cb61..caf34eaefab9 100644 --- a/tests/ui/empty_enum_variants_with_brackets.fixed +++ b/tests/ui/empty_enum_variants_with_brackets.fixed @@ -1,5 +1,6 @@ #![warn(clippy::empty_enum_variants_with_brackets)] #![allow(dead_code)] +#![feature(more_qualified_paths)] pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error @@ -102,4 +103,62 @@ pub enum PubFoo { Variant3(), } +fn issue16157() { + enum E { + V, + //~^ empty_enum_variants_with_brackets + } + + let E::V = E::V; + + ::V = E::V; + ::V = E::V; +} + +fn variant_with_braces() { + enum E { + V, + //~^ empty_enum_variants_with_brackets + } + E::V = E::V; + E::V = E::V; + ::V = ::V; + + enum F { + U, + //~^ empty_enum_variants_with_brackets + } + F::U = F::U; + ::U = F::U; +} + +fn variant_with_comments_and_cfg() { + enum E { + V( + // This is a comment + ), + } + E::V() = E::V(); + + enum F { + U { + // This is a comment + }, + } + F::U {} = F::U {}; + + enum G { + V(#[cfg(target_os = "cuda")] String), + } + G::V() = G::V(); + + enum H { + U { + #[cfg(target_os = "cuda")] + value: String, + }, + } + H::U {} = H::U {}; +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.rs b/tests/ui/empty_enum_variants_with_brackets.rs index 63a5a8e9143e..f7ab062edd1e 100644 --- a/tests/ui/empty_enum_variants_with_brackets.rs +++ b/tests/ui/empty_enum_variants_with_brackets.rs @@ -1,5 +1,6 @@ #![warn(clippy::empty_enum_variants_with_brackets)] #![allow(dead_code)] +#![feature(more_qualified_paths)] pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error @@ -102,4 +103,62 @@ pub enum PubFoo { Variant3(), } +fn issue16157() { + enum E { + V(), + //~^ empty_enum_variants_with_brackets + } + + let E::V() = E::V(); + + ::V() = E::V(); + ::V {} = E::V(); +} + +fn variant_with_braces() { + enum E { + V(), + //~^ empty_enum_variants_with_brackets + } + E::V() = E::V(); + E::V() = E::V {}; + ::V {} = ::V {}; + + enum F { + U {}, + //~^ empty_enum_variants_with_brackets + } + F::U {} = F::U {}; + ::U {} = F::U {}; +} + +fn variant_with_comments_and_cfg() { + enum E { + V( + // This is a comment + ), + } + E::V() = E::V(); + + enum F { + U { + // This is a comment + }, + } + F::U {} = F::U {}; + + enum G { + V(#[cfg(target_os = "cuda")] String), + } + G::V() = G::V(); + + enum H { + U { + #[cfg(target_os = "cuda")] + value: String, + }, + } + H::U {} = H::U {}; +} + fn main() {} diff --git a/tests/ui/empty_enum_variants_with_brackets.stderr b/tests/ui/empty_enum_variants_with_brackets.stderr index 7fe85e829a35..d50b07036a94 100644 --- a/tests/ui/empty_enum_variants_with_brackets.stderr +++ b/tests/ui/empty_enum_variants_with_brackets.stderr @@ -1,5 +1,5 @@ error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:7:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:8:16 | LL | EmptyBraces {}, | ^^^ @@ -9,7 +9,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:15:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:16:16 | LL | EmptyBraces {}, | ^^^ @@ -17,7 +17,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:17:21 + --> tests/ui/empty_enum_variants_with_brackets.rs:18:21 | LL | EmptyParentheses(), | ^^ @@ -25,7 +25,7 @@ LL | EmptyParentheses(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:28:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:29:16 | LL | Unknown(), | ^^ @@ -33,7 +33,7 @@ LL | Unknown(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:47:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:48:16 | LL | Unknown(), | ^^ @@ -41,7 +41,7 @@ LL | Unknown(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:53:20 + --> tests/ui/empty_enum_variants_with_brackets.rs:54:20 | LL | Parentheses(), | ^^ @@ -56,7 +56,7 @@ LL ~ RedundantParenthesesFunctionCall::Parentheses; | error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:76:20 + --> tests/ui/empty_enum_variants_with_brackets.rs:77:20 | LL | Parentheses(), | ^^ @@ -71,12 +71,61 @@ LL ~ Parentheses, | error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:95:13 + --> tests/ui/empty_enum_variants_with_brackets.rs:96:13 | LL | Variant3(), | ^^ | = help: remove the brackets -error: aborting due to 8 previous errors +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:108:10 + | +LL | V(), + | ^^ + | +help: remove the brackets + | +LL ~ V, +LL | +LL | } +LL | +LL ~ let E::V = E::V; +LL | +LL ~ ::V = E::V; +LL ~ ::V = E::V; + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:120:10 + | +LL | V(), + | ^^ + | +help: remove the brackets + | +LL ~ V, +LL | +LL | } +LL ~ E::V = E::V; +LL ~ E::V = E::V; +LL ~ ::V = ::V; + | + +error: enum variant has empty brackets + --> tests/ui/empty_enum_variants_with_brackets.rs:128:10 + | +LL | U {}, + | ^^^ + | +help: remove the brackets + | +LL ~ U, +LL | +LL | } +LL ~ F::U = F::U; +LL ~ ::U = F::U; + | + +error: aborting due to 11 previous errors diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 6407bd678f9c..1ea96abbcd8b 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,6 +1,4 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target: apple - #![warn(clippy::empty_loop)] #![crate_type = "lib"] #![no_std] diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index f36fb9d9e3f2..e34b50ed1aef 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop_no_std.rs:10:5 + --> tests/ui/empty_loop_no_std.rs:8:5 | LL | loop {} | ^^^^^^^ diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 1e36ca4f1f09..75e173b9a84d 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -273,3 +273,13 @@ mod issue_16173 { } fn main() {} + +fn issue15781(m: &mut std::collections::HashMap, k: i32, v: i32) { + fn very_important_fn() {} + m.entry(k).or_insert_with(|| { + //~^ map_entry + #[cfg(test)] + very_important_fn(); + v + }); +} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index b3da0ef3ffd6..7e3308c87356 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -279,3 +279,13 @@ mod issue_16173 { } fn main() {} + +fn issue15781(m: &mut std::collections::HashMap, k: i32, v: i32) { + fn very_important_fn() {} + if !m.contains_key(&k) { + //~^ map_entry + #[cfg(test)] + very_important_fn(); + m.insert(k, v); + } +} diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 009b78d29073..4a29b3860e89 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -246,5 +246,26 @@ LL + e.insert(42); LL + } | -error: aborting due to 11 previous errors +error: usage of `contains_key` followed by `insert` on a `HashMap` + --> tests/ui/entry.rs:285:5 + | +LL | / if !m.contains_key(&k) { +LL | | +LL | | #[cfg(test)] +LL | | very_important_fn(); +LL | | m.insert(k, v); +LL | | } + | |_____^ + | +help: try + | +LL ~ m.entry(k).or_insert_with(|| { +LL + +LL + #[cfg(test)] +LL + very_important_fn(); +LL + v +LL + }); + | + +error: aborting due to 12 previous errors diff --git a/tests/ui/format_push_string.fixed b/tests/ui/format_push_string.fixed new file mode 100644 index 000000000000..f6396d9982a3 --- /dev/null +++ b/tests/ui/format_push_string.fixed @@ -0,0 +1,132 @@ +#![warn(clippy::format_push_string)] + +fn main() { + use std::fmt::Write; + + let mut string = String::new(); + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + + let _ = write!(string, "{:?}", 5678); + //~^ format_push_string + + macro_rules! string { + () => { + String::new() + }; + } + let _ = write!(string!(), "{:?}", 5678); + //~^ format_push_string +} + +// TODO: recognize the already imported `fmt::Write`, and don't add a note suggesting to import it +// again +mod import_write { + mod push_str { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + } + + mod add_assign { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string + } + } + } +} diff --git a/tests/ui/format_push_string.rs b/tests/ui/format_push_string.rs index 056ef59ff0e2..1ed0f5b3ac59 100644 --- a/tests/ui/format_push_string.rs +++ b/tests/ui/format_push_string.rs @@ -1,44 +1,132 @@ #![warn(clippy::format_push_string)] fn main() { + use std::fmt::Write; + let mut string = String::new(); string += &format!("{:?}", 1234); //~^ format_push_string string.push_str(&format!("{:?}", 5678)); //~^ format_push_string + + macro_rules! string { + () => { + String::new() + }; + } + string!().push_str(&format!("{:?}", 5678)); + //~^ format_push_string } -mod issue9493 { - pub fn u8vec_to_hex(vector: &Vec, upper: bool) -> String { - let mut hex = String::with_capacity(vector.len() * 2); - for byte in vector { - hex += &(if upper { +// TODO: recognize the already imported `fmt::Write`, and don't add a note suggesting to import it +// again +mod import_write { + mod push_str { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; + + string.push_str(&format!("{:?}", 1234)); //~^ format_push_string - - format!("{byte:02X}") - } else { - format!("{byte:02x}") - }); + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } } - hex } - pub fn other_cases() { - let mut s = String::new(); - // if let - s += &(if let Some(_a) = Some(1234) { - //~^ format_push_string + mod add_assign { + mod imported_anonymously { + fn main(string: &mut String) { + use std::fmt::Write as _; - format!("{}", 1234) - } else { - format!("{}", 1234) - }); - // match - s += &(match Some(1234) { - //~^ format_push_string - Some(_) => format!("{}", 1234), - None => format!("{}", 1234), - }); + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported { + fn main(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_anonymously_in_module { + use std::fmt::Write as _; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_in_module { + use std::fmt::Write; + + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + mod imported_and_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } } } diff --git a/tests/ui/format_push_string.stderr b/tests/ui/format_push_string.stderr index bba2a8947c43..05e26fcbfc2b 100644 --- a/tests/ui/format_push_string.stderr +++ b/tests/ui/format_push_string.stderr @@ -1,60 +1,199 @@ error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:5:5 + --> tests/ui/format_push_string.rs:7:5 | LL | string += &format!("{:?}", 1234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait = note: `-D clippy::format-push-string` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string += &format!("{:?}", 1234); +LL + let _ = write!(string, "{:?}", 1234); + | error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:8:5 + --> tests/ui/format_push_string.rs:10:5 | LL | string.push_str(&format!("{:?}", 5678)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 5678)); +LL + let _ = write!(string, "{:?}", 5678); + | error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:16:13 + --> tests/ui/format_push_string.rs:18:5 | -LL | / hex += &(if upper { -LL | | -LL | | -LL | | format!("{byte:02X}") -LL | | } else { -LL | | format!("{byte:02x}") -LL | | }); - | |______________^ +LL | string!().push_str(&format!("{:?}", 5678)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string!().push_str(&format!("{:?}", 5678)); +LL + let _ = write!(string!(), "{:?}", 5678); | - = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:30:9 + --> tests/ui/format_push_string.rs:30:17 | -LL | / s += &(if let Some(_a) = Some(1234) { -LL | | -LL | | -LL | | format!("{}", 1234) -LL | | } else { -LL | | format!("{}", 1234) -LL | | }); - | |__________^ +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); | - = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:38:9 + --> tests/ui/format_push_string.rs:39:17 | -LL | / s += &(match Some(1234) { -LL | | -LL | | Some(_) => format!("{}", 1234), -LL | | None => format!("{}", 1234), -LL | | }); - | |__________^ +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); | - = help: consider using `write!` to avoid the extra allocation -error: aborting due to 5 previous errors +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:48:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:57:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:66:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:73:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:84:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:93:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:102:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:111:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:120:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string.rs:127:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/format_push_string_no_core.rs b/tests/ui/format_push_string_no_core.rs new file mode 100644 index 000000000000..4bc45906fa78 --- /dev/null +++ b/tests/ui/format_push_string_no_core.rs @@ -0,0 +1,15 @@ +//@check-pass +#![warn(clippy::format_push_string)] +#![no_std] +#![feature(no_core)] +#![no_core] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + // can't suggest even `core::fmt::Write` because of `#![no_core]` + string.push_str(&format!("{:?}", 1234)); +} diff --git a/tests/ui/format_push_string_no_std.fixed b/tests/ui/format_push_string_no_std.fixed new file mode 100644 index 000000000000..32d8659dcbd5 --- /dev/null +++ b/tests/ui/format_push_string_no_std.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + use core::fmt::Write; + + // TODO: recognize the already imported `fmt::Write`, and don't suggest importing it again + let _ = write!(string, "{:?}", 1234); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std.rs b/tests/ui/format_push_string_no_std.rs new file mode 100644 index 000000000000..a74189abe528 --- /dev/null +++ b/tests/ui/format_push_string_no_std.rs @@ -0,0 +1,15 @@ +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + use core::fmt::Write; + + // TODO: recognize the already imported `fmt::Write`, and don't suggest importing it again + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std.stderr b/tests/ui/format_push_string_no_std.stderr new file mode 100644 index 000000000000..30fd42ac71b2 --- /dev/null +++ b/tests/ui/format_push_string_no_std.stderr @@ -0,0 +1,17 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_no_std.rs:13:5 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `core::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/format_push_string_no_std_unfixable.rs b/tests/ui/format_push_string_no_std_unfixable.rs new file mode 100644 index 000000000000..f5ed5e435b5a --- /dev/null +++ b/tests/ui/format_push_string_no_std_unfixable.rs @@ -0,0 +1,13 @@ +//@no-rustfix +#![warn(clippy::format_push_string)] +#![no_std] + +extern crate alloc; + +use alloc::format; +use alloc::string::String; + +fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string +} diff --git a/tests/ui/format_push_string_no_std_unfixable.stderr b/tests/ui/format_push_string_no_std_unfixable.stderr new file mode 100644 index 000000000000..cc716c84efe2 --- /dev/null +++ b/tests/ui/format_push_string_no_std_unfixable.stderr @@ -0,0 +1,17 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_no_std_unfixable.rs:11:5 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `core::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/format_push_string_unfixable.rs b/tests/ui/format_push_string_unfixable.rs new file mode 100644 index 000000000000..ff6c13fe4a49 --- /dev/null +++ b/tests/ui/format_push_string_unfixable.rs @@ -0,0 +1,144 @@ +//@no-rustfix +#![warn(clippy::format_push_string)] + +mod issue9493 { + pub fn u8vec_to_hex(vector: &Vec, upper: bool) -> String { + let mut hex = String::with_capacity(vector.len() * 2); + for byte in vector { + hex += &(if upper { + format!("{byte:02X}") + //~^ format_push_string + } else { + format!("{byte:02x}") + }); + } + hex + } + + pub fn other_cases() { + let mut s = String::new(); + // if let + s += &(if let Some(_a) = Some(1234) { + format!("{}", 1234) + //~^ format_push_string + } else { + format!("{}", 1234) + }); + // match + s += &(match Some(1234) { + Some(_) => format!("{}", 1234), + //~^ format_push_string + None => format!("{}", 1234), + }); + } +} + +mod import_write { + mod push_str { + // TODO: suggest importing `std::fmt::Write`; + mod not_imported { + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_not_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing, but only for `bar` + mod imported_and_not_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + } + + mod add_assign { + // TODO: suggest importing `std::fmt::Write`; + mod not_imported { + fn main(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_not_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing the first time, but not again + mod not_imported_and_imported { + fn foo(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + + // TODO: suggest importing, but only for `bar` + mod imported_and_not_imported { + fn foo(string: &mut String) { + use std::fmt::Write; + + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + + fn bar(string: &mut String) { + string.push_str(&format!("{:?}", 1234)); + //~^ format_push_string + } + } + } +} + +fn main() {} diff --git a/tests/ui/format_push_string_unfixable.stderr b/tests/ui/format_push_string_unfixable.stderr new file mode 100644 index 000000000000..145e7fcc440d --- /dev/null +++ b/tests/ui/format_push_string_unfixable.stderr @@ -0,0 +1,233 @@ +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:8:13 + | +LL | / hex += &(if upper { +LL | | format!("{byte:02X}") + | | --------------------- `format!` used here +LL | | +LL | | } else { +LL | | format!("{byte:02x}") + | | --------------------- `format!` used here +LL | | }); + | |______________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + = note: `-D clippy::format-push-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:21:9 + | +LL | / s += &(if let Some(_a) = Some(1234) { +LL | | format!("{}", 1234) + | | ------------------- `format!` used here +LL | | +LL | | } else { +LL | | format!("{}", 1234) + | | ------------------- `format!` used here +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:28:9 + | +LL | / s += &(match Some(1234) { +LL | | Some(_) => format!("{}", 1234), + | | ------------------- `format!` used here +LL | | +LL | | None => format!("{}", 1234), + | | ------------------- `format!` used here +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + = note: you may need to import the `std::fmt::Write` trait + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:41:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:49:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:54:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:62:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:69:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:79:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:84:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:94:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:102:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:107:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:115:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:122:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:132:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: `format!(..)` appended to existing `String` + --> tests/ui/format_push_string_unfixable.rs:137:17 + | +LL | string.push_str(&format!("{:?}", 1234)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: you may need to import the `std::fmt::Write` trait +help: consider using `write!` to avoid the extra allocation + | +LL - string.push_str(&format!("{:?}", 1234)); +LL + let _ = write!(string, "{:?}", 1234); + | + +error: aborting due to 17 previous errors + diff --git a/tests/ui/if_not_else.fixed b/tests/ui/if_not_else.fixed index 4e6f43e5671e..a29847f0cf97 100644 --- a/tests/ui/if_not_else.fixed +++ b/tests/ui/if_not_else.fixed @@ -76,3 +76,20 @@ fn with_annotations() { println!("foo is false"); } } + +fn issue15924() { + let x = 0; + if matches!(x, 0..10) { + println!(":("); + } else { + //~^ if_not_else + println!(":)"); + } + + if dbg!(x) == 1 { + println!(":("); + } else { + //~^ if_not_else + println!(":)"); + } +} diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 6cd2e3bd63fe..4ae11d6ad90e 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -76,3 +76,20 @@ fn with_annotations() { println!("foo"); /* foo */ } } + +fn issue15924() { + let x = 0; + if !matches!(x, 0..10) { + //~^ if_not_else + println!(":)"); + } else { + println!(":("); + } + + if dbg!(x) != 1 { + //~^ if_not_else + println!(":)"); + } else { + println!(":("); + } +} diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index 824837bd52bb..0682bf80da55 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -147,5 +147,47 @@ LL + println!("foo is false"); LL + } | -error: aborting due to 6 previous errors +error: unnecessary boolean `not` operation + --> tests/ui/if_not_else.rs:82:5 + | +LL | / if !matches!(x, 0..10) { +LL | | +LL | | println!(":)"); +LL | | } else { +LL | | println!(":("); +LL | | } + | |_____^ + | +help: try + | +LL ~ if matches!(x, 0..10) { +LL + println!(":("); +LL + } else { +LL + +LL + println!(":)"); +LL + } + | + +error: unnecessary `!=` operation + --> tests/ui/if_not_else.rs:89:5 + | +LL | / if dbg!(x) != 1 { +LL | | +LL | | println!(":)"); +LL | | } else { +LL | | println!(":("); +LL | | } + | |_____^ + | +help: try + | +LL ~ if dbg!(x) == 1 { +LL + println!(":("); +LL + } else { +LL + +LL + println!(":)"); +LL + } + | + +error: aborting due to 8 previous errors diff --git a/tests/ui/if_then_some_else_none.fixed b/tests/ui/if_then_some_else_none.fixed index 7da9401a308f..ce122ac69b12 100644 --- a/tests/ui/if_then_some_else_none.fixed +++ b/tests/ui/if_then_some_else_none.fixed @@ -3,10 +3,20 @@ fn main() { // Should issue an error. - let _ = foo().then(|| { println!("true!"); "foo" }); + let _ = foo().then(|| { + //~^ if_then_some_else_none + + println!("true!"); + "foo" + }); // Should issue an error when macros are used. - let _ = matches!(true, true).then(|| { println!("true!"); matches!(true, false) }); + let _ = matches!(true, true).then(|| { + //~^ if_then_some_else_none + + println!("true!"); + matches!(true, false) + }); // Should issue an error. Binary expression `o < 32` should be parenthesized. let x = Some(5); @@ -71,7 +81,12 @@ fn _msrv_1_49() { #[clippy::msrv = "1.50"] fn _msrv_1_50() { - let _ = foo().then(|| { println!("true!"); 150 }); + let _ = foo().then(|| { + //~^ if_then_some_else_none + + println!("true!"); + 150 + }); } fn foo() -> bool { @@ -182,7 +197,10 @@ fn issue15005() { fn next(&mut self) -> Option { //~v if_then_some_else_none - (self.count < 5).then(|| { self.count += 1; self.count }) + (self.count < 5).then(|| { + self.count += 1; + self.count + }) } } } @@ -195,7 +213,10 @@ fn statements_from_macro() { }; } //~v if_then_some_else_none - let _ = true.then(|| { mac!(); 42 }); + let _ = true.then(|| { + mac!(); + 42 + }); } fn dont_lint_inside_macros() { @@ -218,3 +239,24 @@ mod issue15770 { Ok(()) } } + +mod issue16176 { + pub async fn foo() -> u32 { + todo!() + } + + pub async fn bar(cond: bool) -> Option { + if cond { Some(foo().await) } else { None } // OK + } +} + +fn issue16269() -> Option { + use std::cell::UnsafeCell; + + //~v if_then_some_else_none + (1 <= 3).then(|| { + let a = UnsafeCell::new(1); + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. + unsafe { *a.get() } + }) +} diff --git a/tests/ui/if_then_some_else_none.rs b/tests/ui/if_then_some_else_none.rs index 02962f83ce8a..1d6c86d94492 100644 --- a/tests/ui/if_then_some_else_none.rs +++ b/tests/ui/if_then_some_else_none.rs @@ -274,3 +274,26 @@ mod issue15770 { Ok(()) } } + +mod issue16176 { + pub async fn foo() -> u32 { + todo!() + } + + pub async fn bar(cond: bool) -> Option { + if cond { Some(foo().await) } else { None } // OK + } +} + +fn issue16269() -> Option { + use std::cell::UnsafeCell; + + //~v if_then_some_else_none + if 1 <= 3 { + let a = UnsafeCell::new(1); + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. + Some(unsafe { *a.get() }) + } else { + None + } +} diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index 58651a055942..eff5f8c82dcb 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -9,10 +9,19 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `foo().then(|| { println!("true!"); "foo" })` + | |_____^ | = note: `-D clippy::if-then-some-else-none` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]` +help: try + | +LL ~ let _ = foo().then(|| { +LL + +LL + +LL + println!("true!"); +LL + "foo" +LL ~ }); + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:16:13 @@ -25,7 +34,17 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `matches!(true, true).then(|| { println!("true!"); matches!(true, false) })` + | |_____^ + | +help: try + | +LL ~ let _ = matches!(true, true).then(|| { +LL + +LL + +LL + println!("true!"); +LL + matches!(true, false) +LL ~ }); + | error: this could be simplified with `bool::then_some` --> tests/ui/if_then_some_else_none.rs:27:28 @@ -50,7 +69,17 @@ LL | | println!("true!"); ... | LL | | None LL | | }; - | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` + | |_____^ + | +help: try + | +LL ~ let _ = foo().then(|| { +LL + +LL + +LL + println!("true!"); +LL + 150 +LL ~ }); + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:138:5 @@ -125,7 +154,15 @@ LL | | Some(self.count) LL | | } else { LL | | None LL | | } - | |_____________^ help: try: `(self.count < 5).then(|| { self.count += 1; self.count })` + | |_____________^ + | +help: try + | +LL ~ (self.count < 5).then(|| { +LL + self.count += 1; +LL + self.count +LL + }) + | error: this could be simplified with `bool::then` --> tests/ui/if_then_some_else_none.rs:249:13 @@ -137,7 +174,36 @@ LL | | Some(42) LL | | } else { LL | | None LL | | }; - | |_____^ help: try: `true.then(|| { mac!(); 42 })` + | |_____^ + | +help: try + | +LL ~ let _ = true.then(|| { +LL + mac!(); +LL + 42 +LL ~ }); + | -error: aborting due to 13 previous errors +error: this could be simplified with `bool::then` + --> tests/ui/if_then_some_else_none.rs:292:5 + | +LL | / if 1 <= 3 { +LL | | let a = UnsafeCell::new(1); +LL | | // SAFETY: `bytes` bytes starting at `new_end` were just reserved. +LL | | Some(unsafe { *a.get() }) +LL | | } else { +LL | | None +LL | | } + | |_____^ + | +help: try + | +LL ~ (1 <= 3).then(|| { +LL + let a = UnsafeCell::new(1); +LL + // SAFETY: `bytes` bytes starting at `new_end` were just reserved. +LL + unsafe { *a.get() } +LL + }) + | + +error: aborting due to 14 previous errors diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed index a04c601e08c1..2fa5702f8a04 100644 --- a/tests/ui/manual_instant_elapsed.fixed +++ b/tests/ui/manual_instant_elapsed.fixed @@ -28,3 +28,19 @@ fn main() { // //~^^ manual_instant_elapsed } + +fn issue16236() { + use std::ops::Sub as _; + macro_rules! deref { + ($e:expr) => { + *$e + }; + } + + let start = &Instant::now(); + let _ = deref!(start).elapsed(); + //~^ manual_instant_elapsed + + deref!(start).elapsed(); + //~^ manual_instant_elapsed +} diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs index 7c67f6acf85d..e7a0e6499e74 100644 --- a/tests/ui/manual_instant_elapsed.rs +++ b/tests/ui/manual_instant_elapsed.rs @@ -28,3 +28,19 @@ fn main() { // //~^^ manual_instant_elapsed } + +fn issue16236() { + use std::ops::Sub as _; + macro_rules! deref { + ($e:expr) => { + *$e + }; + } + + let start = &Instant::now(); + let _ = Instant::now().sub(deref!(start)); + //~^ manual_instant_elapsed + + Instant::now() - deref!(start); + //~^ manual_instant_elapsed +} diff --git a/tests/ui/manual_instant_elapsed.stderr b/tests/ui/manual_instant_elapsed.stderr index e84f3126f707..e42ac5739a29 100644 --- a/tests/ui/manual_instant_elapsed.stderr +++ b/tests/ui/manual_instant_elapsed.stderr @@ -13,5 +13,17 @@ error: manual implementation of `Instant::elapsed` LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` -error: aborting due to 2 previous errors +error: manual implementation of `Instant::elapsed` + --> tests/ui/manual_instant_elapsed.rs:41:13 + | +LL | let _ = Instant::now().sub(deref!(start)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()` + +error: manual implementation of `Instant::elapsed` + --> tests/ui/manual_instant_elapsed.rs:44:5 + | +LL | Instant::now() - deref!(start); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()` + +error: aborting due to 4 previous errors diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index b0b02f3f8d6b..df0207c420e6 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -127,6 +127,14 @@ LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ + | +help: try + | +LL ~ let _ = opt.map_or_else(|| 0, |x| { +LL + +LL + x + 1 +LL ~ }); + | error: called `map().unwrap_or_else()` on an `Option` value --> tests/ui/map_unwrap_or.rs:63:13 @@ -138,6 +146,12 @@ LL | | .unwrap_or_else(|| LL | | 0 LL | | ); | |_________^ + | +help: try + | +LL ~ let _ = opt.map_or_else(|| +LL ~ 0, |x| x + 1); + | error: called `map().unwrap_or(false)` on an `Option` value --> tests/ui/map_unwrap_or.rs:70:13 @@ -161,6 +175,14 @@ LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ + | +help: try + | +LL ~ let _ = res.map_or_else(|_e| 0, |x| { +LL + +LL + x + 1 +LL ~ }); + | error: called `map().unwrap_or_else()` on a `Result` value --> tests/ui/map_unwrap_or.rs:86:13 @@ -172,6 +194,13 @@ LL | | .unwrap_or_else(|_e| { LL | | 0 LL | | }); | |__________^ + | +help: try + | +LL ~ let _ = res.map_or_else(|_e| { +LL + 0 +LL ~ }, |x| x + 1); + | error: called `map().unwrap_or_else()` on a `Result` value --> tests/ui/map_unwrap_or.rs:111:13 diff --git a/tests/ui/match_like_matches_macro.fixed b/tests/ui/match_like_matches_macro.fixed index dad59c1ce6e4..045ee32bd8bb 100644 --- a/tests/ui/match_like_matches_macro.fixed +++ b/tests/ui/match_like_matches_macro.fixed @@ -1,6 +1,7 @@ #![warn(clippy::match_like_matches_macro)] #![allow( unreachable_patterns, + irrefutable_let_patterns, clippy::equatable_if_let, clippy::needless_borrowed_reference, clippy::redundant_guards @@ -230,3 +231,24 @@ fn issue15841(opt: Option>>, value: i32) { let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); //~^^^^ match_like_matches_macro } + +fn issue16015() -> bool { + use std::any::{TypeId, type_name}; + pub struct GetTypeId(T); + + impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); + } + + macro_rules! typeid { + ($t:ty) => { + GetTypeId::<$t>::VALUE + }; + } + + matches!(typeid!(T), _); + //~^^^^ match_like_matches_macro + + matches!(typeid!(U), _) + //~^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.rs b/tests/ui/match_like_matches_macro.rs index 94bc6433e5cb..231e1ae98f86 100644 --- a/tests/ui/match_like_matches_macro.rs +++ b/tests/ui/match_like_matches_macro.rs @@ -1,6 +1,7 @@ #![warn(clippy::match_like_matches_macro)] #![allow( unreachable_patterns, + irrefutable_let_patterns, clippy::equatable_if_let, clippy::needless_borrowed_reference, clippy::redundant_guards @@ -277,3 +278,27 @@ fn issue15841(opt: Option>>, value: i32) { }; //~^^^^ match_like_matches_macro } + +fn issue16015() -> bool { + use std::any::{TypeId, type_name}; + pub struct GetTypeId(T); + + impl GetTypeId { + pub const VALUE: TypeId = TypeId::of::(); + } + + macro_rules! typeid { + ($t:ty) => { + GetTypeId::<$t>::VALUE + }; + } + + match typeid!(T) { + _ => true, + _ => false, + }; + //~^^^^ match_like_matches_macro + + if let _ = typeid!(U) { true } else { false } + //~^ match_like_matches_macro +} diff --git a/tests/ui/match_like_matches_macro.stderr b/tests/ui/match_like_matches_macro.stderr index a8e352461dbb..bc3e3584938e 100644 --- a/tests/ui/match_like_matches_macro.stderr +++ b/tests/ui/match_like_matches_macro.stderr @@ -1,5 +1,5 @@ error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:13:14 + --> tests/ui/match_like_matches_macro.rs:14:14 | LL | let _y = match x { | ______________^ @@ -20,7 +20,7 @@ LL + let _y = matches!(x, Some(0)); | error: redundant pattern matching, consider using `is_some()` - --> tests/ui/match_like_matches_macro.rs:20:14 + --> tests/ui/match_like_matches_macro.rs:21:14 | LL | let _w = match x { | ______________^ @@ -33,7 +33,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_like_matches_macro.rs:27:14 + --> tests/ui/match_like_matches_macro.rs:28:14 | LL | let _z = match x { | ______________^ @@ -43,7 +43,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:34:15 + --> tests/ui/match_like_matches_macro.rs:35:15 | LL | let _zz = match x { | _______________^ @@ -62,7 +62,7 @@ LL + let _zz = !matches!(x, Some(r) if r == 0); | error: `if let .. else` expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:41:16 + --> tests/ui/match_like_matches_macro.rs:42:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL + let _zzz = matches!(x, Some(5)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:66:20 + --> tests/ui/match_like_matches_macro.rs:67:20 | LL | let _ans = match x { | ____________________^ @@ -95,7 +95,7 @@ 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 + --> tests/ui/match_like_matches_macro.rs:78:20 | LL | let _ans = match x { | ____________________^ @@ -119,7 +119,7 @@ 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 + --> tests/ui/match_like_matches_macro.rs:89:20 | LL | let _ans = match x { | ____________________^ @@ -140,7 +140,7 @@ 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 + --> tests/ui/match_like_matches_macro.rs:150:18 | LL | let _z = match &z { | __________________^ @@ -159,7 +159,7 @@ LL + let _z = matches!(z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:159:18 + --> tests/ui/match_like_matches_macro.rs:160:18 | LL | let _z = match &z { | __________________^ @@ -178,7 +178,7 @@ LL + let _z = matches!(&z, Some(3)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:177:21 + --> tests/ui/match_like_matches_macro.rs:178:21 | LL | let _ = match &z { | _____________________^ @@ -197,7 +197,7 @@ LL + let _ = matches!(&z, AnEnum::X); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:192:20 + --> tests/ui/match_like_matches_macro.rs:193:20 | LL | let _res = match &val { | ____________________^ @@ -216,7 +216,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:205:20 + --> tests/ui/match_like_matches_macro.rs:206:20 | LL | let _res = match &val { | ____________________^ @@ -235,7 +235,7 @@ LL + let _res = matches!(&val, &Some(ref _a)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:264:14 + --> tests/ui/match_like_matches_macro.rs:265:14 | LL | let _y = match Some(5) { | ______________^ @@ -254,7 +254,7 @@ LL + let _y = matches!(Some(5), Some(0)); | error: match expression looks like `matches!` macro - --> tests/ui/match_like_matches_macro.rs:274:13 + --> tests/ui/match_like_matches_macro.rs:275:13 | LL | let _ = match opt { | _____________^ @@ -272,5 +272,35 @@ LL - }; LL + let _ = matches!(opt, Some(first) if (if let Some(second) = first { true } else { todo!() })); | -error: aborting due to 15 previous errors +error: match expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:296:5 + | +LL | / match typeid!(T) { +LL | | _ => true, +LL | | _ => false, +LL | | }; + | |_____^ + | +help: use `matches!` directly + | +LL - match typeid!(T) { +LL - _ => true, +LL - _ => false, +LL - }; +LL + matches!(typeid!(T), _); + | + +error: `if let .. else` expression looks like `matches!` macro + --> tests/ui/match_like_matches_macro.rs:302:5 + | +LL | if let _ = typeid!(U) { true } else { false } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `matches!` directly + | +LL - if let _ = typeid!(U) { true } else { false } +LL + matches!(typeid!(U), _) + | + +error: aborting due to 17 previous errors diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index c1512ba3e269..0ff881472cbb 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -312,4 +312,137 @@ fn check_closures() { } } +fn issue16116() { + unsafe fn foo() -> u32 { + 0 + } + + // Do not lint even though `format!` expansion + // contains unsafe calls. + unsafe { + let _ = format!("{}", foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + let _ = format!("{}", foo()); + let _ = format!("{}", foo()); + } + + // Do not lint: only one `assert!()` argument is unsafe + unsafe { + assert_eq!(foo(), 0, "{}", 1 + 2); + } + + // Each argument of a macro call may count as an unsafe operation. + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + } + + macro_rules! twice { + ($e:expr) => {{ + $e; + $e; + }}; + } + + // Do not lint, a repeated argument used twice by a macro counts + // as at most one unsafe operation. + unsafe { + twice!(foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + twice!(foo()); + twice!(foo()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(foo(), 0, "{}", 1 + 2); + assert_eq!(foo(), 0, "{}", 1 + 2); + } + + macro_rules! unsafe_twice { + ($e:expr) => { + unsafe { + $e; + $e; + } + }; + }; + + // A macro whose expansion contains unsafe blocks will not + // check inside the blocks. + unsafe { + unsafe_twice!(foo()); + } + + macro_rules! double_non_arg_unsafe { + () => {{ + _ = str::from_utf8_unchecked(&[]); + _ = str::from_utf8_unchecked(&[]); + }}; + } + + // Do not lint: each unsafe expression contained in the + // macro expansion will count towards the macro call. + unsafe { + double_non_arg_unsafe!(); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + double_non_arg_unsafe!(); + double_non_arg_unsafe!(); + } + + // Do not lint: the inner macro call counts as one unsafe op. + unsafe { + assert_eq!(double_non_arg_unsafe!(), ()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!(double_non_arg_unsafe!(), ()); + assert_eq!(double_non_arg_unsafe!(), ()); + } + + unsafe { + //~^ multiple_unsafe_ops_per_block + assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + } + + macro_rules! unsafe_with_arg { + ($e:expr) => {{ + _ = str::from_utf8_unchecked(&[]); + $e; + }}; + } + + // A confusing situation: the macro call counts towards two unsafe calls, + // one coming from inside the macro itself, and one coming from its argument. + // The error message may seem a bit strange as both the macro call and its + // argument will be marked as counting as unsafe ops, but a short investigation + // in those rare situations should sort it out easily. + unsafe { + //~^ multiple_unsafe_ops_per_block + unsafe_with_arg!(foo()); + } + + macro_rules! ignore { + ($e: expr) => {}; + } + + // Another surprising case is when the macro argument is not + // used in the expansion, but in this case we won't see the + // unsafe operation at all. + unsafe { + ignore!(foo()); + ignore!(foo()); + } +} + fn main() {} diff --git a/tests/ui/multiple_unsafe_ops_per_block.stderr b/tests/ui/multiple_unsafe_ops_per_block.stderr index 63f7742b734b..185225bd28c8 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -31,16 +31,16 @@ LL | | *raw_ptr(); LL | | } | |_____^ | -note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 - | -LL | drop(u.u); - | ^^^ note: raw pointer dereference occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:51:9 | LL | *raw_ptr(); | ^^^^^^^^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 + | +LL | drop(u.u); + | ^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:56:5 @@ -58,16 +58,16 @@ note: inline assembly used here | LL | asm!("nop"); | ^^^^^^^^^^^ -note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 - | -LL | sample.not_very_safe(); - | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:60:9 | LL | STATIC = 0; | ^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:66:5 @@ -81,36 +81,36 @@ LL | | asm!("nop"); LL | | } | |_____^ | -note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 - | -LL | drop(u.u); - | ^^^ note: access of a mutable static occurs here --> tests/ui/multiple_unsafe_ops_per_block.rs:69:14 | LL | drop(STATIC); | ^^^^^^ -note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 - | -LL | sample.not_very_safe(); - | ^^^^^^^^^^^^^^^^^^^^^^ -note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 - | -LL | not_very_safe(); - | ^^^^^^^^^^^^^^^ -note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 - | -LL | *raw_ptr(); - | ^^^^^^^^^^ note: inline assembly used here --> tests/ui/multiple_unsafe_ops_per_block.rs:73:9 | LL | asm!("nop"); | ^^^^^^^^^^^ +note: raw pointer dereference occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 + | +LL | *raw_ptr(); + | ^^^^^^^^^^ +note: union field access occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 + | +LL | drop(u.u); + | ^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 + | +LL | sample.not_very_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:109:5 @@ -139,16 +139,16 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: unsafe function call occurs here - --> 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:118:43 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:118:18 + | +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:139:9 @@ -224,16 +224,16 @@ LL | | foo().await; LL | | } | |_____^ | -note: unsafe function call occurs here - --> 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:195:9 | LL | STATIC += 1; | ^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:194:9 + | +LL | not_very_safe(); + | ^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:207:5 @@ -265,16 +265,16 @@ LL | | Some(foo_unchecked()).unwrap_unchecked().await; LL | | } | |_____^ | -note: unsafe method call occurs here - --> 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:216:14 | LL | Some(foo_unchecked()).unwrap_unchecked().await; | ^^^^^^^^^^^^^^^ +note: unsafe method call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:216:9 + | +LL | Some(foo_unchecked()).unwrap_unchecked().await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:236:5 @@ -359,5 +359,170 @@ note: unsafe function call occurs here LL | apply(|| f(0)); | ^^^^ -error: aborting due to 16 previous errors +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:326:5 + | +LL | / unsafe { +LL | | +LL | | let _ = format!("{}", foo()); +LL | | let _ = format!("{}", foo()); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:328:31 + | +LL | let _ = format!("{}", foo()); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:329:31 + | +LL | let _ = format!("{}", foo()); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:338:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:340:20 + | +LL | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:340:36 + | +LL | assert_eq!(foo(), 0, "{}", foo()); // One unsafe operation + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:356:5 + | +LL | / unsafe { +LL | | +LL | | twice!(foo()); +LL | | twice!(foo()); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:358:16 + | +LL | twice!(foo()); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:359:16 + | +LL | twice!(foo()); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:362:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(foo(), 0, "{}", 1 + 2); +LL | | assert_eq!(foo(), 0, "{}", 1 + 2); +LL | | } + | |_____^ + | +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:364:20 + | +LL | assert_eq!(foo(), 0, "{}", 1 + 2); + | ^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:365:20 + | +LL | assert_eq!(foo(), 0, "{}", 1 + 2); + | ^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:396:5 + | +LL | / unsafe { +LL | | +LL | | double_non_arg_unsafe!(); +LL | | double_non_arg_unsafe!(); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:398:9 + | +LL | double_non_arg_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:399:9 + | +LL | double_non_arg_unsafe!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:407:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!(double_non_arg_unsafe!(), ()); +LL | | assert_eq!(double_non_arg_unsafe!(), ()); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:409:20 + | +LL | assert_eq!(double_non_arg_unsafe!(), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:410:20 + | +LL | assert_eq!(double_non_arg_unsafe!(), ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:413:5 + | +LL | / unsafe { +LL | | +LL | | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:415:21 + | +LL | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:415:47 + | +LL | assert_eq!((double_non_arg_unsafe!(), double_non_arg_unsafe!()), ((), ())); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this `unsafe` block contains 2 unsafe operations, expected only one + --> tests/ui/multiple_unsafe_ops_per_block.rs:430:5 + | +LL | / unsafe { +LL | | +LL | | unsafe_with_arg!(foo()); +LL | | } + | |_____^ + | +note: this macro call expands into one or more unsafe operations + --> tests/ui/multiple_unsafe_ops_per_block.rs:432:9 + | +LL | unsafe_with_arg!(foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: unsafe function call occurs here + --> tests/ui/multiple_unsafe_ops_per_block.rs:432:26 + | +LL | unsafe_with_arg!(foo()); + | ^^^^^ + +error: aborting due to 24 previous errors diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index ba1451bf9704..99027e79b664 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -214,3 +214,8 @@ mod issue8055_regression { .len(); } } + +fn issue16270() { + // Do not lint, `..` implements `Index` but is not `usize` + _ = &(1..3).collect::>()[..]; +} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index e054cd01e6f5..683cc49c9af3 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -214,3 +214,8 @@ mod issue8055_regression { .len(); } } + +fn issue16270() { + // Do not lint, `..` implements `Index` but is not `usize` + _ = &(1..3).collect::>()[..]; +} diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr index 94d98f0e9b12..c427f4c3e42c 100644 --- a/tests/ui/needless_pass_by_ref_mut.stderr +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -1,213 +1,281 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:12:11 | LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:38:12 | LL | fn foo6(s: &mut Vec) { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:49:12 | LL | fn bar(&mut self) {} - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:52:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { - | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | ^----^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:130:16 | LL | async fn a1(x: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:135:16 | LL | async fn a2(x: &mut i32, y: String) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:140:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:145:16 | LL | async fn a4(x: &mut i32, y: i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:150:24 | LL | async fn a5(x: i32, y: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:155:24 | LL | async fn a6(x: i32, y: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:160:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:165:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:165:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:201:16 | LL | fn cfg_warn(s: &mut u32) {} - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: this is cfg-gated and may require further changes -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:206:20 | LL | fn cfg_warn(s: &mut u32) {} - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: this is cfg-gated and may require further changes -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:219:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:228:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:248:30 | LL | async fn call_in_closure1(n: &mut str) { - | ^^^^^^^^ help: consider changing to: `&str` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:268:16 | LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - | ^^^^^^^^^^ help: consider changing to: `&usize` + | ^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:280:22 | LL | async fn closure4(n: &mut usize) { - | ^^^^^^^^^^ help: consider changing to: `&usize` + | ^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:335:12 | LL | fn bar(&mut self) {} - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:338:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^^ help: consider changing to: `&self` + | ^----^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:338:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:347:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:364:18 | LL | fn _empty_tup(x: &mut (())) {} - | ^^^^^^^^^ help: consider changing to: `&()` + | ^^----^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:366:19 | LL | fn _single_tup(x: &mut ((i32,))) {} - | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` + | ^^----^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:368:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} - | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` + | ^^----^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:370:11 | LL | fn _fn(x: &mut (fn())) {} - | ^^^^^^^^^^^ help: consider changing to: `&fn()` + | ^^----^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:373:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` + | ^----^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:375:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` + | ^----^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:377:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} - | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` + | ^----^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:379:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` + | ^----^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:381:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut.rs:383:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` + | ^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: consider removing this `mut` error: aborting due to 34 previous errors diff --git a/tests/ui/needless_pass_by_ref_mut2.fixed b/tests/ui/needless_pass_by_ref_mut2.fixed index 0e2ac0202364..c462f1cc8d87 100644 --- a/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/tests/ui/needless_pass_by_ref_mut2.fixed @@ -24,3 +24,9 @@ async fn inner_async4(u: &mut i32, v: &u32) { } fn main() {} + +//~v needless_pass_by_ref_mut +fn issue16267<'a>(msg: &str, slice: &'a [i32]) -> &'a [i32] { + println!("{msg}"); + &slice[0..5] +} diff --git a/tests/ui/needless_pass_by_ref_mut2.rs b/tests/ui/needless_pass_by_ref_mut2.rs index 9201d9a27298..b00f294c57f0 100644 --- a/tests/ui/needless_pass_by_ref_mut2.rs +++ b/tests/ui/needless_pass_by_ref_mut2.rs @@ -24,3 +24,9 @@ async fn inner_async4(u: &mut i32, v: &mut u32) { } fn main() {} + +//~v needless_pass_by_ref_mut +fn issue16267<'a>(msg: &str, slice: &'a mut [i32]) -> &'a [i32] { + println!("{msg}"); + &slice[0..5] +} diff --git a/tests/ui/needless_pass_by_ref_mut2.stderr b/tests/ui/needless_pass_by_ref_mut2.stderr index 9876a6b50718..aa5c412adb4d 100644 --- a/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/tests/ui/needless_pass_by_ref_mut2.stderr @@ -1,17 +1,29 @@ -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut2.rs:8:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&i32` + | ^----^^^ + | | + | help: consider removing this `mut` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` -error: this argument is a mutable reference, but not used mutably +error: this parameter is a mutable reference but is not used mutably --> tests/ui/needless_pass_by_ref_mut2.rs:17:39 | LL | async fn inner_async4(u: &mut i32, v: &mut u32) { - | ^^^^^^^^ help: consider changing to: `&u32` + | ^----^^^ + | | + | help: consider removing this `mut` -error: aborting due to 2 previous errors +error: this parameter is a mutable reference but is not used mutably + --> tests/ui/needless_pass_by_ref_mut2.rs:29:37 + | +LL | fn issue16267<'a>(msg: &str, slice: &'a mut [i32]) -> &'a [i32] { + | ^^^^----^^^^^ + | | + | help: consider removing this `mut` + +error: aborting due to 3 previous errors diff --git a/tests/ui/needless_type_cast.fixed b/tests/ui/needless_type_cast.fixed index 32c348d3ca3a..72eed32c4d73 100644 --- a/tests/ui/needless_type_cast.fixed +++ b/tests/ui/needless_type_cast.fixed @@ -9,6 +9,10 @@ fn generic(x: T) -> T { x } +fn returns_u8() -> u8 { + 10 +} + fn main() { let a: i32 = 10; //~^ needless_type_cast @@ -180,3 +184,86 @@ fn test_loop_with_generic() { }; let _ = x as i32; } + +fn test_size_of_cast() { + use std::mem::size_of; + // Should lint: suggest casting the initializer + let size: u64 = size_of::() as u64; + //~^ needless_type_cast + let _ = size as u64; + let _ = size as u64; +} + +fn test_suffixed_literal_cast() { + // Should lint: suggest casting the initializer + let a: i32 = 10u8 as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_negative_literal() { + // Negative literal - should just change type, not add cast + let a: i32 = -10; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_suffixed_negative_literal() { + // Suffixed negative - needs cast + let a: i32 = -10i8 as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_binary_op() { + // Binary op needs parens in cast + let a: i32 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_fn_return_as_init() { + let a: i32 = returns_u8() as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_method_as_init() { + let a: i32 = 2u8.saturating_add(3) as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_const_as_init() { + const X: u8 = 10; + let a: i32 = X as i32; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_single_use_fn_call() { + // Should not lint: only one use, and fixing would just move the cast + // to the initializer rather than eliminating it + let a: u8 = returns_u8(); + let _ = a as i32; +} + +fn test_single_use_suffixed_literal() { + // Should not lint: only one use with a suffixed literal + let a: u8 = 10u8; + let _ = a as i32; +} + +fn test_single_use_binary_op() { + // Should lint: binary op of unsuffixed literals can be coerced + let a: i32 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; +} diff --git a/tests/ui/needless_type_cast.rs b/tests/ui/needless_type_cast.rs index e28f620e035f..31337575fcc3 100644 --- a/tests/ui/needless_type_cast.rs +++ b/tests/ui/needless_type_cast.rs @@ -9,6 +9,10 @@ fn generic(x: T) -> T { x } +fn returns_u8() -> u8 { + 10 +} + fn main() { let a: u8 = 10; //~^ needless_type_cast @@ -180,3 +184,86 @@ fn test_loop_with_generic() { }; let _ = x as i32; } + +fn test_size_of_cast() { + use std::mem::size_of; + // Should lint: suggest casting the initializer + let size: usize = size_of::(); + //~^ needless_type_cast + let _ = size as u64; + let _ = size as u64; +} + +fn test_suffixed_literal_cast() { + // Should lint: suggest casting the initializer + let a: u8 = 10u8; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_negative_literal() { + // Negative literal - should just change type, not add cast + let a: i8 = -10; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_suffixed_negative_literal() { + // Suffixed negative - needs cast + let a: i8 = -10i8; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_binary_op() { + // Binary op needs parens in cast + let a: u8 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_fn_return_as_init() { + let a: u8 = returns_u8(); + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_method_as_init() { + let a: u8 = 2u8.saturating_add(3); + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_const_as_init() { + const X: u8 = 10; + let a: u8 = X; + //~^ needless_type_cast + let _ = a as i32; + let _ = a as i32; +} + +fn test_single_use_fn_call() { + // Should not lint: only one use, and fixing would just move the cast + // to the initializer rather than eliminating it + let a: u8 = returns_u8(); + let _ = a as i32; +} + +fn test_single_use_suffixed_literal() { + // Should not lint: only one use with a suffixed literal + let a: u8 = 10u8; + let _ = a as i32; +} + +fn test_single_use_binary_op() { + // Should lint: binary op of unsuffixed literals can be coerced + let a: u8 = 10 + 5; + //~^ needless_type_cast + let _ = a as i32; +} diff --git a/tests/ui/needless_type_cast.stderr b/tests/ui/needless_type_cast.stderr index 3ee9df1043e7..56d9e978d05c 100644 --- a/tests/ui/needless_type_cast.stderr +++ b/tests/ui/needless_type_cast.stderr @@ -1,5 +1,5 @@ error: this binding is defined as `u8` but is always cast to `i32` - --> tests/ui/needless_type_cast.rs:13:12 + --> tests/ui/needless_type_cast.rs:17:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` @@ -8,64 +8,154 @@ LL | let a: u8 = 10; = 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 + --> tests/ui/needless_type_cast.rs:37: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 + --> tests/ui/needless_type_cast.rs:43: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 + --> tests/ui/needless_type_cast.rs:56: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 + --> tests/ui/needless_type_cast.rs:63: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 + --> tests/ui/needless_type_cast.rs:70: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 + --> tests/ui/needless_type_cast.rs:81: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 + --> tests/ui/needless_type_cast.rs:103: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 + --> tests/ui/needless_type_cast.rs:111: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 + --> tests/ui/needless_type_cast.rs:120: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 + --> tests/ui/needless_type_cast.rs:126:12 | LL | let a: u8 = 10; | ^^ help: consider defining it as: `i32` -error: aborting due to 11 previous errors +error: this binding is defined as `usize` but is always cast to `u64` + --> tests/ui/needless_type_cast.rs:191:15 + | +LL | let size: usize = size_of::(); + | ^^^^^ + | +help: consider defining it as `u64` and casting the initializer + | +LL - let size: usize = size_of::(); +LL + let size: u64 = size_of::() as u64; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:199:12 + | +LL | let a: u8 = 10u8; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = 10u8; +LL + let a: i32 = 10u8 as i32; + | + +error: this binding is defined as `i8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:207:12 + | +LL | let a: i8 = -10; + | ^^ help: consider defining it as: `i32` + +error: this binding is defined as `i8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:215:12 + | +LL | let a: i8 = -10i8; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: i8 = -10i8; +LL + let a: i32 = -10i8 as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:223:12 + | +LL | let a: u8 = 10 + 5; + | ^^ 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:230:12 + | +LL | let a: u8 = returns_u8(); + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = returns_u8(); +LL + let a: i32 = returns_u8() as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:237:12 + | +LL | let a: u8 = 2u8.saturating_add(3); + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = 2u8.saturating_add(3); +LL + let a: i32 = 2u8.saturating_add(3) as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:245:12 + | +LL | let a: u8 = X; + | ^^ + | +help: consider defining it as `i32` and casting the initializer + | +LL - let a: u8 = X; +LL + let a: i32 = X as i32; + | + +error: this binding is defined as `u8` but is always cast to `i32` + --> tests/ui/needless_type_cast.rs:266:12 + | +LL | let a: u8 = 10 + 5; + | ^^ help: consider defining it as: `i32` + +error: aborting due to 20 previous errors diff --git a/tests/ui/needless_type_cast_unfixable.rs b/tests/ui/needless_type_cast_unfixable.rs new file mode 100644 index 000000000000..bbea9bd24296 --- /dev/null +++ b/tests/ui/needless_type_cast_unfixable.rs @@ -0,0 +1,20 @@ +//@no-rustfix +#![warn(clippy::needless_type_cast)] + +struct Foo(*mut core::ffi::c_void); + +enum Bar { + Variant(*mut core::ffi::c_void), +} + +// Suggestions will not compile directly, as `123` is a literal which +// is not compatible with the suggested `*mut core::ffi::c_void` type +fn issue_16243() { + let underlying: isize = 123; + //~^ needless_type_cast + let handle: Foo = Foo(underlying as _); + + let underlying: isize = 123; + //~^ needless_type_cast + let handle: Bar = Bar::Variant(underlying as _); +} diff --git a/tests/ui/needless_type_cast_unfixable.stderr b/tests/ui/needless_type_cast_unfixable.stderr new file mode 100644 index 000000000000..b71f8a09c40f --- /dev/null +++ b/tests/ui/needless_type_cast_unfixable.stderr @@ -0,0 +1,17 @@ +error: this binding is defined as `isize` but is always cast to `*mut std::ffi::c_void` + --> tests/ui/needless_type_cast_unfixable.rs:13:21 + | +LL | let underlying: isize = 123; + | ^^^^^ help: consider defining it as: `*mut std::ffi::c_void` + | + = 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 `isize` but is always cast to `*mut std::ffi::c_void` + --> tests/ui/needless_type_cast_unfixable.rs:17:21 + | +LL | let underlying: isize = 123; + | ^^^^^ help: consider defining it as: `*mut std::ffi::c_void` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/never_loop_iterator_reduction.rs b/tests/ui/never_loop_iterator_reduction.rs new file mode 100644 index 000000000000..6b07b91db29a --- /dev/null +++ b/tests/ui/never_loop_iterator_reduction.rs @@ -0,0 +1,17 @@ +//@no-rustfix +#![warn(clippy::never_loop)] + +fn main() { + // diverging closure: should trigger + [0, 1].into_iter().for_each(|x| { + //~^ never_loop + + let _ = x; + panic!("boom"); + }); + + // benign closure: should NOT trigger + [0, 1].into_iter().for_each(|x| { + let _ = x + 1; + }); +} diff --git a/tests/ui/never_loop_iterator_reduction.stderr b/tests/ui/never_loop_iterator_reduction.stderr new file mode 100644 index 000000000000..b76ee283146c --- /dev/null +++ b/tests/ui/never_loop_iterator_reduction.stderr @@ -0,0 +1,27 @@ +error: this iterator reduction never loops (closure always diverges) + --> tests/ui/never_loop_iterator_reduction.rs:6:5 + | +LL | / [0, 1].into_iter().for_each(|x| { +LL | | +LL | | +LL | | let _ = x; +LL | | panic!("boom"); +LL | | }); + | |______^ + | + = note: if you only need one element, `if let Some(x) = iter.next()` is clearer + = note: `-D clippy::never-loop` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::never_loop)]` +help: consider this pattern + | +LL - [0, 1].into_iter().for_each(|x| { +LL - +LL - +LL - let _ = x; +LL - panic!("boom"); +LL - }); +LL + if let Some(x) = [0, 1].into_iter().next() { ... }; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed index 70ae090626b9..6bdb170a4aa9 100644 --- a/tests/ui/obfuscated_if_else.fixed +++ b/tests/ui/obfuscated_if_else.fixed @@ -87,3 +87,9 @@ fn issue11141() { let _ = *if true { &42 } else { &17 } as u8; //~^ obfuscated_if_else } + +#[allow(clippy::useless_format)] +fn issue16288() { + if true { format!("this is a test") } else { Default::default() }; + //~^ obfuscated_if_else +} diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs index 8e1f57ca2c02..f7b5ea8c0135 100644 --- a/tests/ui/obfuscated_if_else.rs +++ b/tests/ui/obfuscated_if_else.rs @@ -87,3 +87,9 @@ fn issue11141() { let _ = *true.then_some(&42).unwrap_or(&17) as u8; //~^ obfuscated_if_else } + +#[allow(clippy::useless_format)] +fn issue16288() { + true.then(|| format!("this is a test")).unwrap_or_default(); + //~^ obfuscated_if_else +} diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr index 0de7259d8bb8..865dca56b97a 100644 --- a/tests/ui/obfuscated_if_else.stderr +++ b/tests/ui/obfuscated_if_else.stderr @@ -139,5 +139,11 @@ error: this method chain can be written more clearly with `if .. else ..` LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` -error: aborting due to 23 previous errors +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:93:5 + | +LL | true.then(|| format!("this is a test")).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { format!("this is a test") } else { Default::default() }` + +error: aborting due to 24 previous errors diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed index 05e262ec7786..6b1039ee8020 100644 --- a/tests/ui/println_empty_string.fixed +++ b/tests/ui/println_empty_string.fixed @@ -19,3 +19,23 @@ fn main() { //~^ println_empty_string } } + +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!( + ); + + match "a" { + _ => println!(), // there is a space between "" and comma + //~^ println_empty_string + } + + eprintln!(); // there is a tab between "" and comma + //~^ println_empty_string + + match "a" { + _ => eprintln!(), // tab and space between "" and comma + //~^ println_empty_string + } +} diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs index 028ddb60dbce..db3b8e1a0eac 100644 --- a/tests/ui/println_empty_string.rs +++ b/tests/ui/println_empty_string.rs @@ -19,3 +19,27 @@ fn main() { //~^ println_empty_string } } + +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!( + "\ + \ + " + , + ); + + match "a" { + _ => println!("" ,), // there is a space between "" and comma + //~^ println_empty_string + } + + eprintln!("" ,); // there is a tab between "" and comma + //~^ println_empty_string + + match "a" { + _ => eprintln!("" ,), // tab and space between "" and comma + //~^ println_empty_string + } +} diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 8b997aef9069..bdac1bb3b8ef 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -33,5 +33,42 @@ LL | _ => eprintln!(""), | | | help: remove the empty string -error: aborting due to 4 previous errors +error: empty string literal in `println!` + --> tests/ui/println_empty_string.rs:26:5 + | +LL | / println!( +LL | |/ "\ +LL | || \ +LL | || " +LL | || , +LL | || ); + | ||____-^ + | |____| + | help: remove the empty string + +error: empty string literal in `println!` + --> tests/ui/println_empty_string.rs:34:14 + | +LL | _ => println!("" ,), // there is a space between "" and comma + | ^^^^^^^^^----^ + | | + | help: remove the empty string + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string.rs:38:5 + | +LL | eprintln!("" ,); // there is a tab between "" and comma + | ^^^^^^^^^^-------^ + | | + | help: remove the empty string + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string.rs:42:14 + | +LL | _ => eprintln!("" ,), // tab and space between "" and comma + | ^^^^^^^^^^--------^ + | | + | help: remove the empty string + +error: aborting due to 8 previous errors diff --git a/tests/ui/println_empty_string_unfixable.rs b/tests/ui/println_empty_string_unfixable.rs new file mode 100644 index 000000000000..d6c30f627a58 --- /dev/null +++ b/tests/ui/println_empty_string_unfixable.rs @@ -0,0 +1,30 @@ +#![allow(clippy::match_single_binding)] + +// If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. +#[rustfmt::skip] +fn issue_16167() { + //~v println_empty_string + println!("" /* comment */); + //~v println_empty_string + eprintln!("" /* comment */); + + //~v println_empty_string + println!( // comment + ""); + //~v println_empty_string + eprintln!( // comment + ""); + + //~v println_empty_string + println!("", /* comment */); + + //~v println_empty_string + println!( + "\ + \ + ", + + // there is a comment in the macro span regardless of its position + + ); +} diff --git a/tests/ui/println_empty_string_unfixable.stderr b/tests/ui/println_empty_string_unfixable.stderr new file mode 100644 index 000000000000..648fd7cdbccd --- /dev/null +++ b/tests/ui/println_empty_string_unfixable.stderr @@ -0,0 +1,85 @@ +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:7:5 + | +LL | println!("" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:7:14 + | +LL | println!("" /* comment */); + | ^^ + = note: `-D clippy::println-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::println_empty_string)]` + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string_unfixable.rs:9:5 + | +LL | eprintln!("" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:9:15 + | +LL | eprintln!("" /* comment */); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:12:5 + | +LL | / println!( // comment +LL | | ""); + | |___________________^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:13:17 + | +LL | ""); + | ^^ + +error: empty string literal in `eprintln!` + --> tests/ui/println_empty_string_unfixable.rs:15:5 + | +LL | / eprintln!( // comment +LL | | ""); + | |___________________^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:16:17 + | +LL | ""); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:19:5 + | +LL | println!("", /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:19:14 + | +LL | println!("", /* comment */); + | ^^ + +error: empty string literal in `println!` + --> tests/ui/println_empty_string_unfixable.rs:22:5 + | +LL | / println!( +LL | | "\ +LL | | \ +LL | | ", +... | +LL | | ); + | |_____^ + | +note: remove the empty string + --> tests/ui/println_empty_string_unfixable.rs:23:9 + | +LL | / "\ +LL | | \ +LL | | ", + | |_____________^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/ref_as_ptr.fixed b/tests/ui/ref_as_ptr.fixed index ce144508581e..eadbb7c36415 100644 --- a/tests/ui/ref_as_ptr.fixed +++ b/tests/ui/ref_as_ptr.fixed @@ -86,6 +86,16 @@ fn main() { f(std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))); //~^ ref_as_ptr + let x = (10, 20); + let _ = std::ptr::from_ref(&x); + //~^ ref_as_ptr + let _ = std::ptr::from_ref(&x.0); + //~^ ref_as_ptr + + let x = Box::new(10); + let _ = std::ptr::from_ref(&*x); + //~^ ref_as_ptr + let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; const FOO: *const String = &String::new() as *const _; diff --git a/tests/ui/ref_as_ptr.rs b/tests/ui/ref_as_ptr.rs index acdff2c2ba29..ef96a3ff5693 100644 --- a/tests/ui/ref_as_ptr.rs +++ b/tests/ui/ref_as_ptr.rs @@ -86,6 +86,16 @@ fn main() { f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); //~^ ref_as_ptr + let x = (10, 20); + let _ = &x as *const _; + //~^ ref_as_ptr + let _ = &x.0 as *const _; + //~^ ref_as_ptr + + let x = Box::new(10); + let _ = &*x as *const _; + //~^ ref_as_ptr + let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; const FOO: *const String = &String::new() as *const _; diff --git a/tests/ui/ref_as_ptr.stderr b/tests/ui/ref_as_ptr.stderr index 79db29e596bd..587e4fb809cd 100644 --- a/tests/ui/ref_as_ptr.stderr +++ b/tests/ui/ref_as_ptr.stderr @@ -200,61 +200,67 @@ LL | f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:109:7 + --> tests/ui/ref_as_ptr.rs:90:13 + | +LL | let _ = &x as *const _; + | ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&x)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:92:13 + | +LL | let _ = &x.0 as *const _; + | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&x.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:96:13 + | +LL | let _ = &*x as *const _; + | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&*x)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:119:7 | LL | f(val as *const i32); | ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:111:7 + --> tests/ui/ref_as_ptr.rs:121:7 | LL | f(mut_val as *mut i32); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(mut_val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:116:7 + --> tests/ui/ref_as_ptr.rs:126:7 | LL | f(val as *const _); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:118:7 + --> tests/ui/ref_as_ptr.rs:128:7 | LL | f(val as *const [u8]); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[u8]>(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:123:7 + --> tests/ui/ref_as_ptr.rs:133:7 | LL | f(val as *mut _); | ^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:125:7 + --> tests/ui/ref_as_ptr.rs:135:7 | LL | f(val as *mut str); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:133:9 + --> tests/ui/ref_as_ptr.rs:143:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:138:9 - | -LL | self.0 as *const _ as *const _ - | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` - -error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:147:9 - | -LL | self.0 as *const _ as *const _ - | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` - -error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:152:9 + --> tests/ui/ref_as_ptr.rs:148:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` @@ -262,8 +268,20 @@ LL | self.0 as *const _ as *const _ error: reference as raw pointer --> tests/ui/ref_as_ptr.rs:157:9 | +LL | self.0 as *const _ as *const _ + | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:162:9 + | +LL | self.0 as *const _ as *const _ + | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` + +error: reference as raw pointer + --> tests/ui/ref_as_ptr.rs:167:9 + | LL | self.0 as *mut _ as *mut _ | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(self.0)` -error: aborting due to 44 previous errors +error: aborting due to 47 previous errors diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index fa57b3f553fc..b4ad050df3b7 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -141,3 +141,12 @@ fn _empty_error() -> Result<(), Empty> { } fn main() {} + +fn issue16249() { + type Large = [u8; 1024]; + + let closure = || -> Result<(), Large> { Ok(()) }; + //~^ result_large_err + let closure = || Ok::<(), Large>(()); + //~^ result_large_err +} diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index 72fbc3f58961..fd39179c61cb 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -104,5 +104,21 @@ LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { | = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box>` -error: aborting due to 12 previous errors +error: the `Err`-variant returned from this closure is very large + --> tests/ui/result_large_err.rs:148:25 + | +LL | let closure = || -> Result<(), Large> { Ok(()) }; + | ^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes + | + = help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>` + +error: the `Err`-variant returned from this closure is very large + --> tests/ui/result_large_err.rs:150:19 + | +LL | let closure = || Ok::<(), Large>(()); + | ^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 1024 bytes + | + = help: try reducing the size of `[u8; 1024]`, for example by boxing large elements or replacing it with `Box<[u8; 1024]>` + +error: aborting due to 14 previous errors diff --git a/tests/ui/same_length_and_capacity.rs b/tests/ui/same_length_and_capacity.rs new file mode 100644 index 000000000000..999fcf89881d --- /dev/null +++ b/tests/ui/same_length_and_capacity.rs @@ -0,0 +1,27 @@ +#![warn(clippy::same_length_and_capacity)] + +fn main() { + let mut my_vec: Vec = Vec::with_capacity(20); + my_vec.extend([1, 2, 3, 4, 5]); + let (ptr, mut len, cap) = my_vec.into_raw_parts(); + len = 8; + + let _reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, len) }; + //~^ same_length_and_capacity + + // Don't want to lint different expressions for len and cap + let _properly_reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, cap) }; + + // Don't want to lint if len and cap are distinct variables but happen to be equal + let len_from_cap = cap; + let _another_properly_reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len_from_cap, cap) }; + + let my_string = String::from("hello"); + let (string_ptr, string_len, string_cap) = my_string.into_raw_parts(); + + let _reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_len) }; + //~^ same_length_and_capacity + + // Don't want to lint different expressions for len and cap + let _properly_reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_cap) }; +} diff --git a/tests/ui/same_length_and_capacity.stderr b/tests/ui/same_length_and_capacity.stderr new file mode 100644 index 000000000000..6fc852831269 --- /dev/null +++ b/tests/ui/same_length_and_capacity.stderr @@ -0,0 +1,20 @@ +error: usage of `Vec::from_raw_parts` with the same expression for length and capacity + --> tests/ui/same_length_and_capacity.rs:9:39 + | +LL | let _reconstructed_vec = unsafe { Vec::from_raw_parts(ptr, len, len) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try `Box::from(slice::from_raw_parts(...)).into::>()` + = note: `-D clippy::same-length-and-capacity` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::same_length_and_capacity)]` + +error: usage of `String::from_raw_parts` with the same expression for length and capacity + --> tests/ui/same_length_and_capacity.rs:22:42 + | +LL | let _reconstructed_string = unsafe { String::from_raw_parts(string_ptr, string_len, string_len) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try `String::from(str::from_utf8_unchecked(slice::from_raw_parts(...)))` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/set_contains_or_insert.rs b/tests/ui/set_contains_or_insert.rs index 575cfda139a4..ac1d74f8afa4 100644 --- a/tests/ui/set_contains_or_insert.rs +++ b/tests/ui/set_contains_or_insert.rs @@ -164,3 +164,24 @@ fn main() { should_not_warn_hashset(); should_not_warn_btreeset(); } + +fn issue15990(s: &mut HashSet, v: usize) { + if !s.contains(&v) { + s.clear(); + s.insert(v); + } + + fn borrow_as_mut(v: usize, s: &mut HashSet) { + s.clear(); + } + if !s.contains(&v) { + borrow_as_mut(v, s); + s.insert(v); + } + + if !s.contains(&v) { + //~^ set_contains_or_insert + let _readonly_access = s.contains(&v); + s.insert(v); + } +} diff --git a/tests/ui/set_contains_or_insert.stderr b/tests/ui/set_contains_or_insert.stderr index 3152b1136458..3b06b63182ab 100644 --- a/tests/ui/set_contains_or_insert.stderr +++ b/tests/ui/set_contains_or_insert.stderr @@ -127,5 +127,14 @@ LL | LL | borrow_set.insert(value); | ^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: usage of `HashSet::insert` after `HashSet::contains` + --> tests/ui/set_contains_or_insert.rs:182:11 + | +LL | if !s.contains(&v) { + | ^^^^^^^^^^^^ +... +LL | s.insert(v); + | ^^^^^^^^^ + +error: aborting due to 15 previous errors diff --git a/tests/ui/track-diagnostics.rs b/tests/ui/track-diagnostics.rs index 0fbde867390d..1cd37e0570d7 100644 --- a/tests/ui/track-diagnostics.rs +++ b/tests/ui/track-diagnostics.rs @@ -3,6 +3,7 @@ // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. //@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: "/rustc-dev/[0-9a-f]+/" -> "" struct A; struct B; diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs index f3eb5060cd0d..0d3b26673452 100644 --- a/tests/ui/transmuting_null.rs +++ b/tests/ui/transmuting_null.rs @@ -30,7 +30,15 @@ fn transmute_const() { } } +fn transmute_const_int() { + unsafe { + let _: &u64 = std::mem::transmute(u64::MIN as *const u64); + //~^ transmuting_null + } +} + fn main() { one_liners(); transmute_const(); + transmute_const_int(); } diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr index c68e4102e405..ed7c3396a243 100644 --- a/tests/ui/transmuting_null.stderr +++ b/tests/ui/transmuting_null.stderr @@ -19,5 +19,11 @@ error: transmuting a known null pointer into a reference LL | let _: &u64 = std::mem::transmute(ZPTR); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: transmuting a known null pointer into a reference + --> tests/ui/transmuting_null.rs:35:23 + | +LL | let _: &u64 = std::mem::transmute(u64::MIN as *const u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/tests/ui/unchecked_time_subtraction.fixed b/tests/ui/unchecked_time_subtraction.fixed index 2f923fef4c25..830b737f18e7 100644 --- a/tests/ui/unchecked_time_subtraction.fixed +++ b/tests/ui/unchecked_time_subtraction.fixed @@ -35,3 +35,28 @@ fn main() { let _ = (2 * dur1).checked_sub(dur2).unwrap(); //~^ unchecked_time_subtraction } + +fn issue16230() { + use std::ops::Sub as _; + + Duration::ZERO.checked_sub(Duration::MAX).unwrap(); + //~^ unchecked_time_subtraction + + let _ = Duration::ZERO.checked_sub(Duration::MAX).unwrap(); + //~^ unchecked_time_subtraction +} + +fn issue16234() { + use std::ops::Sub as _; + + macro_rules! duration { + ($secs:expr) => { + Duration::from_secs($secs) + }; + } + + duration!(0).checked_sub(duration!(1)).unwrap(); + //~^ unchecked_time_subtraction + let _ = duration!(0).checked_sub(duration!(1)).unwrap(); + //~^ unchecked_time_subtraction +} diff --git a/tests/ui/unchecked_time_subtraction.rs b/tests/ui/unchecked_time_subtraction.rs index cf727f62aafa..e41860157c41 100644 --- a/tests/ui/unchecked_time_subtraction.rs +++ b/tests/ui/unchecked_time_subtraction.rs @@ -35,3 +35,28 @@ fn main() { let _ = 2 * dur1 - dur2; //~^ unchecked_time_subtraction } + +fn issue16230() { + use std::ops::Sub as _; + + Duration::ZERO.sub(Duration::MAX); + //~^ unchecked_time_subtraction + + let _ = Duration::ZERO - Duration::MAX; + //~^ unchecked_time_subtraction +} + +fn issue16234() { + use std::ops::Sub as _; + + macro_rules! duration { + ($secs:expr) => { + Duration::from_secs($secs) + }; + } + + duration!(0).sub(duration!(1)); + //~^ unchecked_time_subtraction + let _ = duration!(0) - duration!(1); + //~^ unchecked_time_subtraction +} diff --git a/tests/ui/unchecked_time_subtraction.stderr b/tests/ui/unchecked_time_subtraction.stderr index c129497447fc..fa4bd1db81ae 100644 --- a/tests/ui/unchecked_time_subtraction.stderr +++ b/tests/ui/unchecked_time_subtraction.stderr @@ -49,5 +49,29 @@ error: unchecked subtraction of a `Duration` LL | let _ = 2 * dur1 - dur2; | ^^^^^^^^^^^^^^^ help: try: `(2 * dur1).checked_sub(dur2).unwrap()` -error: aborting due to 8 previous errors +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:42:5 + | +LL | Duration::ZERO.sub(Duration::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:45:13 + | +LL | let _ = Duration::ZERO - Duration::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:58:5 + | +LL | duration!(0).sub(duration!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` + +error: unchecked subtraction of a `Duration` + --> tests/ui/unchecked_time_subtraction.rs:60:13 + | +LL | let _ = duration!(0) - duration!(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` + +error: aborting due to 12 previous errors diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 1c331be75094..c3eeafbc39cd 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -6,21 +6,35 @@ fn is_any(acc: bool, x: usize) -> bool { /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { + use std::ops::{Add, Mul}; + // Can be replaced by .any let _ = (0..3).any(|x| x > 2); //~^ unnecessary_fold + // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, is_any); //~^ redundant_closure + // Can be replaced by .all let _ = (0..3).all(|x| x > 2); //~^ unnecessary_fold + // Can be replaced by .sum let _: i32 = (0..3).sum(); //~^ unnecessary_fold + let _: i32 = (0..3).sum(); + //~^ unnecessary_fold + let _: i32 = (0..3).sum(); + //~^ unnecessary_fold + // Can be replaced by .product let _: i32 = (0..3).product(); //~^ unnecessary_fold + let _: i32 = (0..3).product(); + //~^ unnecessary_fold + let _: i32 = (0..3).product(); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` @@ -37,6 +51,43 @@ fn unnecessary_fold_should_ignore() { let _ = (0..3).fold(0, |acc, x| acc * x); let _ = (0..3).fold(0, |acc, x| 1 + acc + x); + struct Adder; + impl Adder { + fn add(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + fn mul(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + } + // `add`/`mul` are inherent methods + let _: i32 = (0..3).fold(0, Adder::add); + let _: i32 = (0..3).fold(1, Adder::mul); + + trait FakeAdd { + type Output; + fn add(self, other: Rhs) -> Self::Output; + } + impl FakeAdd for i32 { + type Output = Self; + fn add(self, other: i32) -> Self::Output { + self + other + } + } + trait FakeMul { + type Output; + fn mul(self, other: Rhs) -> Self::Output; + } + impl FakeMul for i32 { + type Output = Self; + fn mul(self, other: i32) -> Self::Output { + self * other + } + } + // `add`/`mul` come from an unrelated trait + let _: i32 = (0..3).fold(0, FakeAdd::add); + let _: i32 = (0..3).fold(1, FakeMul::mul); + // We only match against an accumulator on the left // hand side. We could lint for .sum and .product when // it's on the right, but don't for now (and this wouldn't @@ -63,6 +114,7 @@ fn unnecessary_fold_over_multiple_lines() { fn issue10000() { use std::collections::HashMap; use std::hash::BuildHasher; + use std::ops::{Add, Mul}; fn anything(_: T) {} fn num(_: i32) {} @@ -74,23 +126,56 @@ fn issue10000() { // more cases: let _ = map.values().sum::(); //~^ unnecessary_fold + let _ = map.values().sum::(); + //~^ unnecessary_fold let _ = map.values().product::(); //~^ unnecessary_fold + let _ = map.values().product::(); + //~^ unnecessary_fold + let _: i32 = map.values().sum(); + //~^ unnecessary_fold let _: i32 = map.values().sum(); //~^ unnecessary_fold let _: i32 = map.values().product(); //~^ unnecessary_fold + let _: i32 = map.values().product(); + //~^ unnecessary_fold + anything(map.values().sum::()); + //~^ unnecessary_fold anything(map.values().sum::()); //~^ unnecessary_fold anything(map.values().product::()); //~^ unnecessary_fold + anything(map.values().product::()); + //~^ unnecessary_fold num(map.values().sum()); //~^ unnecessary_fold + num(map.values().sum()); + //~^ unnecessary_fold + num(map.values().product()); + //~^ unnecessary_fold num(map.values().product()); //~^ unnecessary_fold } smoketest_map(HashMap::new()); + + fn add_turbofish_not_necessary() -> i32 { + (0..3).sum() + //~^ unnecessary_fold + } + fn mul_turbofish_not_necessary() -> i32 { + (0..3).product() + //~^ unnecessary_fold + } + fn add_turbofish_necessary() -> impl Add { + (0..3).sum::() + //~^ unnecessary_fold + } + fn mul_turbofish_necessary() -> impl Mul { + (0..3).product::() + //~^ unnecessary_fold + } } fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index e2050e37e3b1..6ab41a942625 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -6,21 +6,35 @@ fn is_any(acc: bool, x: usize) -> bool { /// Calls which should trigger the `UNNECESSARY_FOLD` lint fn unnecessary_fold() { + use std::ops::{Add, Mul}; + // Can be replaced by .any let _ = (0..3).fold(false, |acc, x| acc || x > 2); //~^ unnecessary_fold + // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); //~^ redundant_closure + // Can be replaced by .all let _ = (0..3).fold(true, |acc, x| acc && x > 2); //~^ unnecessary_fold + // Can be replaced by .sum let _: i32 = (0..3).fold(0, |acc, x| acc + x); //~^ unnecessary_fold + let _: i32 = (0..3).fold(0, Add::add); + //~^ unnecessary_fold + let _: i32 = (0..3).fold(0, i32::add); + //~^ unnecessary_fold + // Can be replaced by .product let _: i32 = (0..3).fold(1, |acc, x| acc * x); //~^ unnecessary_fold + let _: i32 = (0..3).fold(1, Mul::mul); + //~^ unnecessary_fold + let _: i32 = (0..3).fold(1, i32::mul); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` @@ -37,6 +51,43 @@ fn unnecessary_fold_should_ignore() { let _ = (0..3).fold(0, |acc, x| acc * x); let _ = (0..3).fold(0, |acc, x| 1 + acc + x); + struct Adder; + impl Adder { + fn add(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + fn mul(lhs: i32, rhs: i32) -> i32 { + unimplemented!() + } + } + // `add`/`mul` are inherent methods + let _: i32 = (0..3).fold(0, Adder::add); + let _: i32 = (0..3).fold(1, Adder::mul); + + trait FakeAdd { + type Output; + fn add(self, other: Rhs) -> Self::Output; + } + impl FakeAdd for i32 { + type Output = Self; + fn add(self, other: i32) -> Self::Output { + self + other + } + } + trait FakeMul { + type Output; + fn mul(self, other: Rhs) -> Self::Output; + } + impl FakeMul for i32 { + type Output = Self; + fn mul(self, other: i32) -> Self::Output { + self * other + } + } + // `add`/`mul` come from an unrelated trait + let _: i32 = (0..3).fold(0, FakeAdd::add); + let _: i32 = (0..3).fold(1, FakeMul::mul); + // We only match against an accumulator on the left // hand side. We could lint for .sum and .product when // it's on the right, but don't for now (and this wouldn't @@ -63,6 +114,7 @@ fn unnecessary_fold_over_multiple_lines() { fn issue10000() { use std::collections::HashMap; use std::hash::BuildHasher; + use std::ops::{Add, Mul}; fn anything(_: T) {} fn num(_: i32) {} @@ -74,23 +126,56 @@ fn issue10000() { // more cases: let _ = map.values().fold(0, |x, y| x + y); //~^ unnecessary_fold + let _ = map.values().fold(0, Add::add); + //~^ unnecessary_fold let _ = map.values().fold(1, |x, y| x * y); //~^ unnecessary_fold + let _ = map.values().fold(1, Mul::mul); + //~^ unnecessary_fold let _: i32 = map.values().fold(0, |x, y| x + y); //~^ unnecessary_fold + let _: i32 = map.values().fold(0, Add::add); + //~^ unnecessary_fold let _: i32 = map.values().fold(1, |x, y| x * y); //~^ unnecessary_fold + let _: i32 = map.values().fold(1, Mul::mul); + //~^ unnecessary_fold anything(map.values().fold(0, |x, y| x + y)); //~^ unnecessary_fold + anything(map.values().fold(0, Add::add)); + //~^ unnecessary_fold anything(map.values().fold(1, |x, y| x * y)); //~^ unnecessary_fold + anything(map.values().fold(1, Mul::mul)); + //~^ unnecessary_fold num(map.values().fold(0, |x, y| x + y)); //~^ unnecessary_fold + num(map.values().fold(0, Add::add)); + //~^ unnecessary_fold num(map.values().fold(1, |x, y| x * y)); //~^ unnecessary_fold + num(map.values().fold(1, Mul::mul)); + //~^ unnecessary_fold } smoketest_map(HashMap::new()); + + fn add_turbofish_not_necessary() -> i32 { + (0..3).fold(0, |acc, x| acc + x) + //~^ unnecessary_fold + } + fn mul_turbofish_not_necessary() -> i32 { + (0..3).fold(1, |acc, x| acc * x) + //~^ unnecessary_fold + } + fn add_turbofish_necessary() -> impl Add { + (0..3).fold(0, |acc, x| acc + x) + //~^ unnecessary_fold + } + fn mul_turbofish_necessary() -> impl Mul { + (0..3).fold(1, |acc, x| acc * x) + //~^ unnecessary_fold + } } fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index d82b1f39b48b..bb8aa7e18d34 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -1,5 +1,5 @@ error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:10:20 + --> tests/ui/unnecessary_fold.rs:12:20 | LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` @@ -8,7 +8,7 @@ LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` error: redundant closure - --> tests/ui/unnecessary_fold.rs:13:32 + --> tests/ui/unnecessary_fold.rs:16:32 | LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `is_any` @@ -17,88 +17,184 @@ LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:16:20 + --> tests/ui/unnecessary_fold.rs:20:20 | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:19:25 + --> tests/ui/unnecessary_fold.rs:24:25 | LL | let _: i32 = (0..3).fold(0, |acc, x| acc + x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:22:25 + --> tests/ui/unnecessary_fold.rs:26:25 + | +LL | let _: i32 = (0..3).fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:28:25 + | +LL | let _: i32 = (0..3).fold(0, i32::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:32:25 | LL | let _: i32 = (0..3).fold(1, |acc, x| acc * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:28:41 + --> tests/ui/unnecessary_fold.rs:34:25 + | +LL | let _: i32 = (0..3).fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:36:25 + | +LL | let _: i32 = (0..3).fold(1, i32::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:42:41 | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:59:10 + --> tests/ui/unnecessary_fold.rs:110:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:71:33 + --> tests/ui/unnecessary_fold.rs:123:33 | LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:75:30 + --> tests/ui/unnecessary_fold.rs:127:30 | LL | let _ = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:77:30 + --> tests/ui/unnecessary_fold.rs:129:30 + | +LL | let _ = map.values().fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:131:30 | LL | let _ = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:79:35 + --> tests/ui/unnecessary_fold.rs:133:30 + | +LL | let _ = map.values().fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:135:35 | LL | let _: i32 = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:81:35 + --> tests/ui/unnecessary_fold.rs:137:35 + | +LL | let _: i32 = map.values().fold(0, Add::add); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:139:35 | LL | let _: i32 = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:83:31 + --> tests/ui/unnecessary_fold.rs:141:35 + | +LL | let _: i32 = map.values().fold(1, Mul::mul); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:143:31 | LL | anything(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:85:31 + --> tests/ui/unnecessary_fold.rs:145:31 + | +LL | anything(map.values().fold(0, Add::add)); + | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:147:31 | LL | anything(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:87:26 + --> tests/ui/unnecessary_fold.rs:149:31 + | +LL | anything(map.values().fold(1, Mul::mul)); + | ^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:151:26 | LL | num(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:89:26 + --> tests/ui/unnecessary_fold.rs:153:26 + | +LL | num(map.values().fold(0, Add::add)); + | ^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:155:26 | LL | num(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` -error: aborting due to 16 previous errors +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:157:26 + | +LL | num(map.values().fold(1, Mul::mul)); + | ^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:164:16 + | +LL | (0..3).fold(0, |acc, x| acc + x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:168:16 + | +LL | (0..3).fold(1, |acc, x| acc * x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:172:16 + | +LL | (0..3).fold(0, |acc, x| acc + x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:176:16 + | +LL | (0..3).fold(1, |acc, x| acc * x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: aborting due to 32 previous errors diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 075e31d202b0..37559f9a2367 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -10,6 +10,9 @@ clippy::needless_lifetimes, clippy::missing_transmute_annotations )] +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] #[macro_use] extern crate proc_macro_derive; @@ -769,3 +772,25 @@ mod issue_13277 { type Item<'foo> = Option>; } } + +mod issue16164 { + trait Bits { + fn bit(self) -> bool; + } + + impl Bits for u8 { + fn bit(self) -> bool { + todo!() + } + } + + trait T { + fn f(self) -> bool; + } + + impl T for u8 { + fn f(self) -> bool { + todo!() + } + } +} diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 6fbba0bbc550..74abd2f61bf9 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -10,6 +10,9 @@ clippy::needless_lifetimes, clippy::missing_transmute_annotations )] +#![allow(incomplete_features)] +#![feature(adt_const_params)] +#![feature(unsized_const_params)] #[macro_use] extern crate proc_macro_derive; @@ -769,3 +772,25 @@ mod issue_13277 { type Item<'foo> = Option>; } } + +mod issue16164 { + trait Bits { + fn bit(self) -> bool; + } + + impl Bits for u8 { + fn bit(self) -> bool { + todo!() + } + } + + trait T { + fn f(self) -> bool; + } + + impl T for u8 { + fn f(self) -> bool { + todo!() + } + } +} diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index 5f65c53ea25c..8ce341d22d4f 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -1,5 +1,5 @@ error: unnecessary structure name repetition - --> tests/ui/use_self.rs:23:21 + --> tests/ui/use_self.rs:26:21 | LL | fn new() -> Foo { | ^^^ help: use the applicable keyword: `Self` @@ -8,247 +8,247 @@ LL | fn new() -> Foo { = help: to override `-D warnings` add `#[allow(clippy::use_self)]` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:25:13 + --> tests/ui/use_self.rs:28:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:28:22 + --> tests/ui/use_self.rs:31:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:30:13 + --> tests/ui/use_self.rs:33:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:36:25 + --> tests/ui/use_self.rs:39:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:38:13 + --> tests/ui/use_self.rs:41:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:80:28 + --> tests/ui/use_self.rs:83:28 | LL | fn clone(&self) -> Foo<'a> { | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:114:24 + --> tests/ui/use_self.rs:117:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:114:55 + --> tests/ui/use_self.rs:117:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:131:13 + --> tests/ui/use_self.rs:134:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:167:29 + --> tests/ui/use_self.rs:170:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:169:21 + --> tests/ui/use_self.rs:172:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:181:21 + --> tests/ui/use_self.rs:184:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:183:13 + --> tests/ui/use_self.rs:186:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:201:21 + --> tests/ui/use_self.rs:204:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:203:21 + --> tests/ui/use_self.rs:206:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:205:21 + --> tests/ui/use_self.rs:208:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:248:13 + --> tests/ui/use_self.rs:251:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:250:13 + --> tests/ui/use_self.rs:253:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:253:13 + --> tests/ui/use_self.rs:256:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:273:13 + --> tests/ui/use_self.rs:276:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:288:25 + --> tests/ui/use_self.rs:291:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:290:13 + --> tests/ui/use_self.rs:293:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:16 + --> tests/ui/use_self.rs:298:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:22 + --> tests/ui/use_self.rs:298:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:320:29 + --> tests/ui/use_self.rs:323:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:322:13 + --> tests/ui/use_self.rs:325:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:495:13 + --> tests/ui/use_self.rs:498:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:571:17 + --> tests/ui/use_self.rs:574:17 | LL | Foo::Bar => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:573:17 + --> tests/ui/use_self.rs:576:17 | LL | Foo::Baz => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:580:20 + --> tests/ui/use_self.rs:583:20 | LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:605:17 + --> tests/ui/use_self.rs:608:17 | LL | Something::Num(n) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:607:17 + --> tests/ui/use_self.rs:610:17 | LL | Something::TupleNums(n, _m) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:609:17 + --> tests/ui/use_self.rs:612:17 | LL | Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:616:17 + --> tests/ui/use_self.rs:619:17 | LL | crate::issue8845::Something::Num(n) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:618:17 + --> tests/ui/use_self.rs:621:17 | LL | crate::issue8845::Something::TupleNums(n, _m) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:620:17 + --> tests/ui/use_self.rs:623:17 | LL | crate::issue8845::Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:637:17 + --> tests/ui/use_self.rs:640:17 | LL | let Foo(x) = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:643:17 + --> tests/ui/use_self.rs:646:17 | LL | let crate::issue8845::Foo(x) = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:651:17 + --> tests/ui/use_self.rs:654:17 | LL | let Bar { x, .. } = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:657:17 + --> tests/ui/use_self.rs:660:17 | LL | let crate::issue8845::Bar { x, .. } = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:697:17 + --> tests/ui/use_self.rs:700:17 | LL | E::A => {}, | ^ help: use the applicable keyword: `Self` diff --git a/tests/ui/writeln_empty_string_unfixable.rs b/tests/ui/writeln_empty_string_unfixable.rs new file mode 100644 index 000000000000..ca570fd1fc7b --- /dev/null +++ b/tests/ui/writeln_empty_string_unfixable.rs @@ -0,0 +1,26 @@ +#![allow(unused_must_use)] +#![warn(clippy::writeln_empty_string)] + +use std::io::Write; + +// If there is a comment in the span of macro call, we don't provide an auto-fix suggestion. +#[rustfmt::skip] +fn issue_16251() { + let mut v = Vec::new(); + + writeln!(v, /* comment */ ""); + //~^ writeln_empty_string + + writeln!(v, "" /* comment */); + //~^ writeln_empty_string + + //~v writeln_empty_string + writeln!(v, + "\ + \ + " + + // there is a comment in the macro span regardless of its position + + ); +} diff --git a/tests/ui/writeln_empty_string_unfixable.stderr b/tests/ui/writeln_empty_string_unfixable.stderr new file mode 100644 index 000000000000..0ed802ba84ba --- /dev/null +++ b/tests/ui/writeln_empty_string_unfixable.stderr @@ -0,0 +1,47 @@ +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:11:5 + | +LL | writeln!(v, /* comment */ ""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:11:31 + | +LL | writeln!(v, /* comment */ ""); + | ^^ + = note: `-D clippy::writeln-empty-string` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::writeln_empty_string)]` + +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:14:5 + | +LL | writeln!(v, "" /* comment */); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:14:17 + | +LL | writeln!(v, "" /* comment */); + | ^^ + +error: empty string literal in `writeln!` + --> tests/ui/writeln_empty_string_unfixable.rs:18:5 + | +LL | / writeln!(v, +LL | | "\ +LL | | \ +LL | | " +... | +LL | | ); + | |_____^ + | +note: remove the empty string + --> tests/ui/writeln_empty_string_unfixable.rs:19:9 + | +LL | / "\ +LL | | \ +LL | | " + | |_____________^ + +error: aborting due to 3 previous errors + diff --git a/triagebot.toml b/triagebot.toml index 09dec7675e7e..5f637205fa65 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,6 +63,7 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", + "samueltardieu", ] [assign.owners] From 70d8c6163b81d354b2ee8fcf1fc54aa11e358085 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 25 Dec 2025 13:04:23 +0000 Subject: [PATCH 031/340] implement shellcheck --- src/tools/tidy/src/extra_checks/mod.rs | 21 ++++++++++++++++--- src/tools/tidy/src/extra_checks/rustdoc_js.rs | 5 +++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 1304de16874d..1997adeda6f1 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -595,10 +595,9 @@ fn install_requirements( Ok(()) } -/// Check that shellcheck is installed then run it at the given path -fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { +fn has_shellcheck() -> Result<(), Error> { match Command::new("shellcheck").arg("--version").status() { - Ok(_) => (), + Ok(_) => Ok(()), Err(e) if e.kind() == io::ErrorKind::NotFound => { return Err(Error::MissingReq( "shellcheck", @@ -612,6 +611,13 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { } Err(e) => return Err(e.into()), } +} + +/// Check that shellcheck is installed then run it at the given path +fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { + if let Err(err) = has_shellcheck() { + return Err(err); + } let status = Command::new("shellcheck").args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } @@ -772,6 +778,15 @@ impl ExtraCheckArg { ExtraCheckLang::Spellcheck => { ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() } + ExtraCheckLang::Shell => { + has_shellcheck().is_ok() + } + ExtraCheckLang::Js => { + // implement detailed check + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "jslint") + && rustdoc_js::has_tool(build_dir, "tsc") + } _ => todo!("implement other checks"), } } diff --git a/src/tools/tidy/src/extra_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs index 944d8a44112f..6ad5a6665071 100644 --- a/src/tools/tidy/src/extra_checks/rustdoc_js.rs +++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs @@ -21,6 +21,11 @@ fn spawn_cmd(cmd: &mut Command) -> Result { }) } +pub(super) fn has_tool(outdir: &Path, name: &str) -> bool { + let bin_path = node_module_bin(outdir, name); + Command::new(bin_path).arg("--version").status().is_ok() +} + /// install all js dependencies from package.json. pub(super) fn npm_install(root_path: &Path, outdir: &Path, npm: &Path) -> Result<(), super::Error> { npm::install(root_path, outdir, npm)?; From 258708fa6d1fc680ff06124cbf4455e3c3d83edd Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 25 Dec 2025 23:41:37 +0000 Subject: [PATCH 032/340] implement js check --- src/tools/tidy/src/extra_checks/mod.rs | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 1997adeda6f1..5c83a12e1e5c 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -322,7 +322,7 @@ fn check_impl( } let res = spellcheck_runner(root_path, &outdir, &cargo, &args); if res.is_err() { - rerun_with_bless("spellcheck", "fix typos"); + rerun_with_bless("spellcheck", "fix typechecktypos"); } res?; } @@ -778,14 +778,27 @@ impl ExtraCheckArg { ExtraCheckLang::Spellcheck => { ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() } - ExtraCheckLang::Shell => { - has_shellcheck().is_ok() - } + ExtraCheckLang::Shell => has_shellcheck().is_ok(), ExtraCheckLang::Js => { - // implement detailed check - rustdoc_js::has_tool(build_dir, "eslint") - && rustdoc_js::has_tool(build_dir, "jslint") - && rustdoc_js::has_tool(build_dir, "tsc") + match self.kind { + Some(ExtraCheckKind::Lint) => { + // If Lint is enabled, check both eslint and es-check. + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "es-check") + } + Some(ExtraCheckKind::Typecheck) => { + // If Typecheck is enabled, check tsc. + rustdoc_js::has_tool(build_dir, "tsc") + } + None => { + // No kind means it will check both Lint and Typecheck. + rustdoc_js::has_tool(build_dir, "eslint") + && rustdoc_js::has_tool(build_dir, "es-check") + && rustdoc_js::has_tool(build_dir, "tsc") + } + // Unreachable. + Some(_) => false, + } } _ => todo!("implement other checks"), } From a6b005a0c82c223c1f6c8e6d2d11f1f1a211a703 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Fri, 26 Dec 2025 10:12:18 +0900 Subject: [PATCH 033/340] fix `Expr::can_have_side_effects` for repeat and binary expressions --- compiler/rustc_hir/src/hir.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e176c703b33e..0898afef47e5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2618,6 +2618,12 @@ impl Expr<'_> { // them being used only for its side-effects. base.can_have_side_effects() } + ExprKind::Binary(_, lhs, rhs) => { + // This isn't exactly true for all `Binary`, but we are using this + // method exclusively for diagnostics and there's a *cultural* pressure against + // them being used only for its side-effects. + lhs.can_have_side_effects() || rhs.can_have_side_effects() + } ExprKind::Struct(_, fields, init) => { let init_side_effects = match init { StructTailExpr::Base(init) => init.can_have_side_effects(), @@ -2640,13 +2646,13 @@ impl Expr<'_> { }, args, ) => args.iter().any(|arg| arg.can_have_side_effects()), + ExprKind::Repeat(arg, _) => arg.can_have_side_effects(), ExprKind::If(..) | ExprKind::Match(..) | ExprKind::MethodCall(..) | ExprKind::Call(..) | ExprKind::Closure { .. } | ExprKind::Block(..) - | ExprKind::Repeat(..) | ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) @@ -2657,7 +2663,6 @@ impl Expr<'_> { | ExprKind::InlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::ConstBlock(..) - | ExprKind::Binary(..) | ExprKind::Yield(..) | ExprKind::DropTemps(..) | ExprKind::Err(_) => true, From ec9174248dbcd6bbce4512b6455c99aa714e3c1c Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 22 Dec 2025 03:20:08 +0100 Subject: [PATCH 034/340] Fix `multiple_inherent_impl` false negatives for generic impl blocks --- clippy_lints/src/inherent_impl.rs | 23 +++++--- tests/ui/impl.rs | 42 +++++++++++++-- tests/ui/impl.stderr | 90 ++++++++++++++++++++++++++++--- 3 files changed, 138 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index f59c7615d745..14928a1be13b 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -101,7 +101,21 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { InherentImplLintScope::Crate => Criterion::Crate, }; let is_test = is_cfg_test(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id); - match type_map.entry((impl_ty, criterion, is_test)) { + let predicates = { + // Gets the predicates (bounds) for the given impl block, + // sorted for consistent comparison to allow distinguishing between impl blocks + // with different generic bounds. + let mut predicates = cx + .tcx + .predicates_of(impl_id) + .predicates + .iter() + .map(|(clause, _)| *clause) + .collect::>(); + predicates.sort_by_key(|c| format!("{c:?}")); + predicates + }; + match type_map.entry((impl_ty, predicates, criterion, is_test)) { Entry::Vacant(e) => { // Store the id for the first impl block of this type. The span is retrieved lazily. e.insert(IdOrSpan::Id(impl_id)); @@ -152,15 +166,12 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { let id = cx.tcx.local_def_id_to_hir_id(id); if let Node::Item(&Item { - kind: ItemKind::Impl(impl_item), + kind: ItemKind::Impl(_), span, .. }) = cx.tcx.hir_node(id) { - (!span.from_expansion() - && impl_item.generics.params.is_empty() - && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])) - .then_some(span) + (!span.from_expansion() && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id])).then_some(span) } else { None } diff --git a/tests/ui/impl.rs b/tests/ui/impl.rs index e6044cc50781..75761a34c86e 100644 --- a/tests/ui/impl.rs +++ b/tests/ui/impl.rs @@ -14,6 +14,7 @@ impl MyStruct { } impl<'a> MyStruct { + //~^ multiple_inherent_impl fn lifetimed() {} } @@ -90,10 +91,12 @@ struct Lifetime<'s> { } impl Lifetime<'_> {} -impl Lifetime<'_> {} // false negative +impl Lifetime<'_> {} +//~^ multiple_inherent_impl impl<'a> Lifetime<'a> {} -impl<'a> Lifetime<'a> {} // false negative +impl<'a> Lifetime<'a> {} +//~^ multiple_inherent_impl impl<'b> Lifetime<'b> {} // false negative? @@ -104,6 +107,39 @@ struct Generic { } impl Generic {} -impl Generic {} // false negative +impl Generic {} +//~^ multiple_inherent_impl + +use std::fmt::Debug; + +#[derive(Debug)] +struct GenericWithBounds(T); + +impl GenericWithBounds { + fn make_one(_one: T) -> Self { + todo!() + } +} + +impl GenericWithBounds { + //~^ multiple_inherent_impl + fn make_two(_two: T) -> Self { + todo!() + } +} + +struct MultipleTraitBounds(T); + +impl MultipleTraitBounds { + fn debug_fn() {} +} + +impl MultipleTraitBounds { + fn clone_fn() {} +} + +impl MultipleTraitBounds { + fn debug_clone_fn() {} +} fn main() {} diff --git a/tests/ui/impl.stderr b/tests/ui/impl.stderr index 93d4b3998f90..9c4aaf183d70 100644 --- a/tests/ui/impl.stderr +++ b/tests/ui/impl.stderr @@ -19,7 +19,24 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]` error: multiple implementations of this structure - --> tests/ui/impl.rs:26:5 + --> tests/ui/impl.rs:16:1 + | +LL | / impl<'a> MyStruct { +LL | | +LL | | fn lifetimed() {} +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:6:1 + | +LL | / impl MyStruct { +LL | | fn first() {} +LL | | } + | |_^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:27:5 | LL | / impl super::MyStruct { LL | | @@ -37,7 +54,7 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:48:1 + --> tests/ui/impl.rs:49:1 | LL | / impl WithArgs { LL | | @@ -47,7 +64,7 @@ LL | | } | |_^ | note: first implementation here - --> tests/ui/impl.rs:45:1 + --> tests/ui/impl.rs:46:1 | LL | / impl WithArgs { LL | | fn f2() {} @@ -55,28 +72,85 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:71:1 + --> tests/ui/impl.rs:72:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:68:1 + --> tests/ui/impl.rs:69:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ error: multiple implementations of this structure - --> tests/ui/impl.rs:84:1 + --> tests/ui/impl.rs:85:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:81:1 + --> tests/ui/impl.rs:82:1 | LL | impl OneExpected {} | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: multiple implementations of this structure + --> tests/ui/impl.rs:94:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:93:1 + | +LL | impl Lifetime<'_> {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:98:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:97:1 + | +LL | impl<'a> Lifetime<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:110:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> tests/ui/impl.rs:109:1 + | +LL | impl Generic {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: multiple implementations of this structure + --> tests/ui/impl.rs:124:1 + | +LL | / impl GenericWithBounds { +LL | | +LL | | fn make_two(_two: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + | +note: first implementation here + --> tests/ui/impl.rs:118:1 + | +LL | / impl GenericWithBounds { +LL | | fn make_one(_one: T) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_^ + +error: aborting due to 10 previous errors From e12e19d98c1206f44dbf1ade6debf53f15f9ad66 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Fri, 26 Dec 2025 03:44:09 +0100 Subject: [PATCH 035/340] fix double_parens FP on macro repetition patterns --- clippy_lints/src/double_parens.rs | 2 ++ tests/ui/double_parens.fixed | 16 ++++++++++++++++ tests/ui/double_parens.rs | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 8defbeeaa5f2..351d29d87432 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -114,6 +114,8 @@ fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool { && inner.starts_with('(') && inner.ends_with(')') && outer_after_inner.trim_start().starts_with(')') + // Don't lint macro repetition patterns like `($($result),*)` where parens are necessary + && !inner.trim_start_matches('(').trim_start().starts_with("$(") { true } else { diff --git a/tests/ui/double_parens.fixed b/tests/ui/double_parens.fixed index 024af6840132..ef7838491f8f 100644 --- a/tests/ui/double_parens.fixed +++ b/tests/ui/double_parens.fixed @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 8a76f2837f35..07eafdf69575 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -161,4 +161,20 @@ fn issue15940() { pub struct Person; } +fn issue16224() { + fn test() -> i32 { 42 } + + macro_rules! call { + ($matcher:pat $(=> $result:expr)?) => { + match test() { + $matcher => Result::Ok(($($result),*)), + _ => Result::Err("No match".to_string()), + } + }; + } + + let _: Result<(), String> = call!(_); + let _: Result = call!(_ => 42); +} + fn main() {} From 86405fb507bef835470b0c678de80bc35d7ea514 Mon Sep 17 00:00:00 2001 From: Shinonn Date: Fri, 5 Dec 2025 11:02:17 +0700 Subject: [PATCH 036/340] Fix ICE by rejecting const blocks in patterns during AST lowering This fixes the ICE reported by rejecting `const` blocks in pattern position during AST lowering. Previously, `ExprKind::ConstBlock` could reach HIR as `PatExprKind::ConstBlock`, allowing invalid patterns to be type-checked and triggering an ICE. This patch removes the lowering path for const blocks in patterns and emits a proper diagnostic instead. A new UI test is added to ensure the compiler reports a regular error and to prevent regressions. --- clippy_lints/src/utils/author.rs | 1 - clippy_utils/src/consts.rs | 1 - clippy_utils/src/hir_utils.rs | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 03cbb0311c6c..9a5fd125a400 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -723,7 +723,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Lit {{ ref {lit}, {negated} }}"); self.lit(lit); }, - PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), PatExprKind::Path(_) => self.maybe_path(pat), } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7e3fa4f9909b..325fc85baa4e 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -578,7 +578,6 @@ impl<'tcx> ConstEvalCtxt<'tcx> { Some(val) } }, - PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value), PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), } } diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index c6d82c0e63fa..581209c68f18 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -506,9 +506,8 @@ impl HirEqInterExpr<'_, '_, '_> { negated: right_neg, }, ) => left_neg == right_neg && left.node == right.node, - (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body), (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right), - (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false, + (PatExprKind::Lit { .. } | PatExprKind::Path(..), _) => false, } } @@ -1102,7 +1101,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { lit.node.hash(&mut self.s); negated.hash(&mut self.s); }, - PatExprKind::ConstBlock(c) => self.hash_body(c.body), PatExprKind::Path(qpath) => self.hash_qpath(qpath), } } From 5642a2d322937b2ea85856f0c4e0949d63f41d8c Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Fri, 26 Dec 2025 14:28:05 +0000 Subject: [PATCH 037/340] implement py and cpp --- src/tools/tidy/src/extra_checks/mod.rs | 43 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 5c83a12e1e5c..d5b360cbe549 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -122,7 +122,7 @@ fn check_impl( }); } if lint_args.iter().any(|ck| ck.if_installed) { - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(outdir)); + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); } macro_rules! extra_check { @@ -322,7 +322,7 @@ fn check_impl( } let res = spellcheck_runner(root_path, &outdir, &cargo, &args); if res.is_err() { - rerun_with_bless("spellcheck", "fix typechecktypos"); + rerun_with_bless("spellcheck", "fix typos"); } res?; } @@ -425,21 +425,11 @@ fn py_runner( /// Create a virtuaenv at a given path if it doesn't already exist, or validate /// the install if it does. Returns the path to that venv's python executable. fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result { - let mut should_create = true; - let dst_reqs_path = venv_path.join("requirements.txt"); let mut py_path = venv_path.to_owned(); py_path.extend(REL_PY_PATH); - if let Ok(req) = fs::read_to_string(&dst_reqs_path) { - if req == fs::read_to_string(src_reqs_path)? { - // found existing environment - should_create = false; - } else { - eprintln!("requirements.txt file mismatch, recreating environment"); - } - } - - if should_create { + if !has_py_tools(venv_path, src_reqs_path)? { + let dst_reqs_path = venv_path.join("requirements.txt"); eprintln!("removing old virtual environment"); if venv_path.is_dir() { fs::remove_dir_all(venv_path).unwrap_or_else(|_| { @@ -454,6 +444,18 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result Result { + let dst_reqs_path = venv_path.join("requirements.txt"); + if let Ok(req) = fs::read_to_string(&dst_reqs_path) { + if req == fs::read_to_string(src_reqs_path)? { + return Ok(true); + } + eprintln!("requirements.txt file mismatch"); + } + + Ok(false) +} + /// Attempt to create a virtualenv at this path. Cycles through all expected /// valid python versions to find one that is installed. fn create_venv_at_path(path: &Path) -> Result<(), Error> { @@ -769,7 +771,7 @@ impl ExtraCheckArg { self.lang == lang && self.kind.map(|k| k == kind).unwrap_or(true) } - fn is_non_if_installed_or_matches(&self, build_dir: &Path) -> bool { + fn is_non_if_installed_or_matches(&self, root_path: &Path, build_dir: &Path) -> bool { if !self.if_installed { return true; } @@ -800,7 +802,16 @@ impl ExtraCheckArg { Some(_) => false, } } - _ => todo!("implement other checks"), + ExtraCheckLang::Py | ExtraCheckLang::Cpp => { + let venv_path = build_dir.join("venv"); + let mut reqs_path = root_path.to_owned(); + reqs_path.extend(PIP_REQ_PATH); + let Ok(v) = has_py_tools(&venv_path, &reqs_path) else { + return false; + }; + + v + } } } From 871cc746297de1a0837a7dfbfdb659cd5b1225fb Mon Sep 17 00:00:00 2001 From: cyrgani Date: Fri, 26 Dec 2025 22:08:18 +0000 Subject: [PATCH 038/340] move `multiple_bound_locations` to style --- clippy_lints/src/multiple_bound_locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 741f38f97560..5b6b4f112455 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.78.0"] pub MULTIPLE_BOUND_LOCATIONS, - suspicious, + style, "defining generic bounds in multiple locations" } From 981fddb4a1f5e4ae62062a87dd8aa250a3a5c705 Mon Sep 17 00:00:00 2001 From: Astralchroma Date: Sat, 27 Dec 2025 22:49:31 +0000 Subject: [PATCH 039/340] Fix typoed mention of config value using `_` of `-` --- clippy_lints/src/cargo/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 60371dcd7715..08d92adbacef 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Because this can be caused purely by the dependencies /// themselves, it's not always possible to fix this issue. /// In those cases, you can allow that specific crate using - /// the `allowed_duplicate_crates` configuration option. + /// the `allowed-duplicate-crates` configuration option. /// /// ### Example /// ```toml From 6da3605bfa84a1a090558ce00bb43402d6d73419 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Sun, 28 Dec 2025 04:22:01 +0000 Subject: [PATCH 040/340] Prepare for merging from rust-lang/rust This updates the rust-version file to 23d01cd2412583491621ab1ca4f1b01e37d11e39. --- 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 7345c25066a8..6a2835bc2d9e 100644 --- a/library/compiler-builtins/rust-version +++ b/library/compiler-builtins/rust-version @@ -1 +1 @@ -2dc30247c5d8293aaa31e1d7dae2ed2fde908ada +23d01cd2412583491621ab1ca4f1b01e37d11e39 From 380e4d28b2304b33995e54f3fa8295d5f4611c8f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 28 Dec 2025 04:32:23 +0000 Subject: [PATCH 041/340] compiler-builtins: Revert "cpuid is safe since the stdarch sync, so remove unsafe from usages" We can't drop the `unsafe` here because it is required at the `libm` MSRV. Instead, we will need to `allow` the lint. This reverts commit 96ac3624abc144db930d94504a9c67aad7b949ed. --- .../libm/src/math/arch/x86/detect.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index 5391a68228ed..e6d9b040bfaf 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -57,7 +57,7 @@ fn load_x86_features() -> Flags { // (in that order) let mut vendor_id = [0u8; 12]; let max_basic_leaf; - { + unsafe { let CpuidResult { eax, ebx, ecx, edx } = __cpuid(0); max_basic_leaf = eax; vendor_id[0..4].copy_from_slice(&ebx.to_ne_bytes()); @@ -72,7 +72,7 @@ fn load_x86_features() -> Flags { // EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits"; // Contains information about most x86 features. - let CpuidResult { ecx, edx, .. } = __cpuid(0x0000_0001_u32); + let CpuidResult { ecx, edx, .. } = unsafe { __cpuid(0x0000_0001_u32) }; let proc_info_ecx = Flags::from_bits(ecx); let proc_info_edx = Flags::from_bits(edx); @@ -82,23 +82,23 @@ fn load_x86_features() -> Flags { let mut extended_features_edx = Flags::empty(); let mut extended_features_eax_leaf_1 = Flags::empty(); if max_basic_leaf >= 7 { - let CpuidResult { ebx, edx, .. } = __cpuid(0x0000_0007_u32); + let CpuidResult { ebx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) }; extended_features_ebx = Flags::from_bits(ebx); extended_features_edx = Flags::from_bits(edx); - let CpuidResult { eax, .. } = __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32); + let CpuidResult { eax, .. } = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) }; extended_features_eax_leaf_1 = Flags::from_bits(eax) } // EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported // - EAX returns the max leaf value for extended information, that is, // `cpuid` calls in range [0x8000_0000; u32::MAX]: - let extended_max_basic_leaf = __cpuid(0x8000_0000_u32).eax; + let extended_max_basic_leaf = unsafe { __cpuid(0x8000_0000_u32) }.eax; // EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature Bits" let mut extended_proc_info_ecx = Flags::empty(); if extended_max_basic_leaf >= 1 { - let CpuidResult { ecx, .. } = __cpuid(0x8000_0001_u32); + let CpuidResult { ecx, .. } = unsafe { __cpuid(0x8000_0001_u32) }; extended_proc_info_ecx = Flags::from_bits(ecx); } From 1276564146497ed2e11e0ca4a59aa0ecec56f88d Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 27 Dec 2025 16:34:40 +0900 Subject: [PATCH 042/340] Ignore unused_unsafe lint in libm/src/math/arch/x86/detect.rs --- library/compiler-builtins/libm/src/math/arch/x86/detect.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs index e6d9b040bfaf..ca785470b806 100644 --- a/library/compiler-builtins/libm/src/math/arch/x86/detect.rs +++ b/library/compiler-builtins/libm/src/math/arch/x86/detect.rs @@ -39,6 +39,8 @@ pub fn get_cpu_features() -> Flags { /// Implementation is taken from [std-detect][std-detect]. /// /// [std-detect]: https://github.com/rust-lang/stdarch/blob/690b3a6334d482874163bd6fcef408e0518febe9/crates/std_detect/src/detect/os/x86.rs#L142 +// FIXME(msrv): Remove unsafe block around __cpuid once https://github.com/rust-lang/stdarch/pull/1935 is available in MSRV. +#[allow(unused_unsafe)] fn load_x86_features() -> Flags { let mut value = Flags::empty(); From 12474ce192941fae1f354d85eadb32e9d1da25da Mon Sep 17 00:00:00 2001 From: Mu001999 Date: Fri, 18 Jul 2025 13:12:27 +0800 Subject: [PATCH 043/340] Impls and impl items inherit lint levels of the corresponding traits and trait items --- compiler/rustc_passes/src/dead.rs | 17 +++++++++ .../ui/lint/dead-code/allow-trait-or-impl.rs | 38 +++++++++++++++++++ .../lint/dead-code/allow-trait-or-impl.stderr | 26 +++++++++++++ tests/ui/lint/dead-code/allow-unused-trait.rs | 29 ++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 tests/ui/lint/dead-code/allow-trait-or-impl.rs create mode 100644 tests/ui/lint/dead-code/allow-trait-or-impl.stderr create mode 100644 tests/ui/lint/dead-code/allow-unused-trait.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0563e9619419..3294b6802a71 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -778,6 +778,15 @@ fn maybe_record_as_seed<'tcx>( match tcx.def_kind(parent) { DefKind::Impl { of_trait: false } | DefKind::Trait => {} DefKind::Impl { of_trait: true } => { + if let Some(trait_item_def_id) = + tcx.associated_item(owner_id.def_id).trait_item_def_id() + && let Some(trait_item_local_def_id) = trait_item_def_id.as_local() + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_item_local_def_id) + { + worklist.push((owner_id.def_id, comes_from_allow)); + } + // We only care about associated items of traits, // because they cannot be visited directly, // so we later mark them as live if their corresponding traits @@ -791,6 +800,14 @@ fn maybe_record_as_seed<'tcx>( } DefKind::Impl { of_trait: true } => { if allow_dead_code.is_none() { + if let Some(trait_def_id) = + tcx.impl_trait_ref(owner_id.def_id).skip_binder().def_id.as_local() + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_def_id) + { + worklist.push((owner_id.def_id, comes_from_allow)); + } + unsolved_items.push(owner_id.def_id); } } diff --git a/tests/ui/lint/dead-code/allow-trait-or-impl.rs b/tests/ui/lint/dead-code/allow-trait-or-impl.rs new file mode 100644 index 000000000000..92817549a91e --- /dev/null +++ b/tests/ui/lint/dead-code/allow-trait-or-impl.rs @@ -0,0 +1,38 @@ +#![deny(dead_code)] + +pub mod a { + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; //~ ERROR struct `PrivateType` is never constructed + impl Foo for PrivateType { } // <-- warns as dead, even though Foo is public + + struct AnotherPrivateType; //~ ERROR struct `AnotherPrivateType` is never constructed + impl Foo for AnotherPrivateType { } // <-- warns as dead, even though Foo is public +} + +pub mod b { + #[allow(dead_code)] + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; + impl Foo for PrivateType { } // <-- no warning, trait is "allowed" + + struct AnotherPrivateType; + impl Foo for AnotherPrivateType { } // <-- no warning, trait is "allowed" +} + +pub mod c { + pub trait Foo { } + impl Foo for u32 { } + + struct PrivateType; + #[allow(dead_code)] + impl Foo for PrivateType { } // <-- no warning, impl is allowed + + struct AnotherPrivateType; //~ ERROR struct `AnotherPrivateType` is never constructed + impl Foo for AnotherPrivateType { } // <-- warns as dead, even though Foo is public +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/allow-trait-or-impl.stderr b/tests/ui/lint/dead-code/allow-trait-or-impl.stderr new file mode 100644 index 000000000000..130116b6c91d --- /dev/null +++ b/tests/ui/lint/dead-code/allow-trait-or-impl.stderr @@ -0,0 +1,26 @@ +error: struct `PrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:7:12 + | +LL | struct PrivateType; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow-trait-or-impl.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: struct `AnotherPrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:10:12 + | +LL | struct AnotherPrivateType; + | ^^^^^^^^^^^^^^^^^^ + +error: struct `AnotherPrivateType` is never constructed + --> $DIR/allow-trait-or-impl.rs:34:12 + | +LL | struct AnotherPrivateType; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/dead-code/allow-unused-trait.rs b/tests/ui/lint/dead-code/allow-unused-trait.rs new file mode 100644 index 000000000000..4eb63bd4d27a --- /dev/null +++ b/tests/ui/lint/dead-code/allow-unused-trait.rs @@ -0,0 +1,29 @@ +//@ check-pass + +#![deny(dead_code)] + +#[allow(dead_code)] +trait Foo { + const FOO: u32; + type Baz; + fn foobar(); +} + +const fn bar(x: u32) -> u32 { + x +} + +struct Qux; + +struct FooBar; + +impl Foo for u32 { + const FOO: u32 = bar(0); + type Baz = Qux; + + fn foobar() { + let _ = FooBar; + } +} + +fn main() {} From c516c284755130dac7d3232b7c40567a57cfb936 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 29 Dec 2025 06:45:17 +0800 Subject: [PATCH 044/340] Add useless prefix `try_into_` for suggest_name Example --- ```rust enum Foo { Num(i32) } impl Foo { fn try_into_num(self) -> Result { if let Self::Num(v) = self { Ok(v) } else { Err(self) } } } fn handle(foo: Foo) { foo.try_into_num().$0 } ``` **Before this PR** ```rust fn handle(foo: Foo) { if let Ok(${1:try_into_num}) = foo.try_into_num() { $0 } } ``` **After this PR** ```rust fn handle(foo: Foo) { if let Ok(${1:num}) = foo.try_into_num() { $0 } } ``` --- .../crates/ide-db/src/syntax_helpers/suggest_name.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 273328a8d270..b8b9a7a76816 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -44,7 +44,7 @@ const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"]; /// `vec.as_slice()` -> `slice` /// `args.into_config()` -> `config` /// `bytes.to_vec()` -> `vec` -const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; +const USELESS_METHOD_PREFIXES: &[&str] = &["try_into_", "into_", "as_", "to_"]; /// Useless methods that are stripped from expression /// From 2ac2b18910fcfca41d90b80f866b84ff23f0a2e2 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 19 Nov 2025 11:17:00 +0530 Subject: [PATCH 045/340] std: sys: fs: uefi: Implement initial File - Implement basic opening and creating files. - Also implement debug. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 153 ++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 58 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 1c65e3e2b155..41d35c01252a 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -11,7 +11,7 @@ use crate::sys::{helpers, unsupported}; const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; -pub struct File(!); +pub struct File(uefi_fs::File); #[derive(Clone)] pub struct FileAttr { @@ -235,9 +235,11 @@ impl OpenOptions { pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; + if create_new { + self.create(true); + } } - #[expect(dead_code)] const fn is_mode_valid(&self) -> bool { // Valid Combinations: Read, Read/Write, Read/Write/Create self.mode == file::MODE_READ @@ -247,100 +249,125 @@ impl OpenOptions { } impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + if !opts.is_mode_valid() { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid open options")); + } + + if opts.create_new && exists(path)? { + return Err(io::const_error!(io::ErrorKind::AlreadyExists, "File already exists")); + } + + let f = uefi_fs::File::from_path(path, opts.mode, 0).map(Self)?; + + if opts.truncate { + f.truncate(0)?; + } + + if opts.append { + f.seek(io::SeekFrom::End(0))?; + } + + Ok(f) } pub fn file_attr(&self) -> io::Result { - self.0 + self.0.file_info().map(FileAttr::from_uefi) } pub fn fsync(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn datasync(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn lock(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn lock_shared(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn try_lock(&self) -> Result<(), TryLockError> { - self.0 + unsupported().map_err(TryLockError::Error) } pub fn try_lock_shared(&self) -> Result<(), TryLockError> { - self.0 + unsupported().map_err(TryLockError::Error) } pub fn unlock(&self) -> io::Result<()> { - self.0 + unsupported() } - pub fn truncate(&self, _size: u64) -> io::Result<()> { - self.0 + pub fn truncate(&self, size: u64) -> io::Result<()> { + let mut file_info = self.0.file_info()?; + + unsafe { (*file_info.as_mut_ptr()).file_size = size }; + + self.0.set_file_info(file_info) } pub fn read(&self, _buf: &mut [u8]) -> io::Result { - self.0 + unsupported() } - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0 + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|b| self.read(b), bufs) } pub fn is_read_vectored(&self) -> bool { - self.0 + false } - pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> { - self.0 + pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { + crate::io::default_read_buf(|buf| self.read(buf), cursor) } pub fn write(&self, _buf: &[u8]) -> io::Result { - self.0 + unsupported() } - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - self.0 + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|b| self.write(b), bufs) } pub fn is_write_vectored(&self) -> bool { - self.0 + false } pub fn flush(&self) -> io::Result<()> { - self.0 + unsupported() } pub fn seek(&self, _pos: SeekFrom) -> io::Result { - self.0 + unsupported() } pub fn size(&self) -> Option> { - self.0 + match self.file_attr() { + Ok(x) => Some(Ok(x.size())), + Err(e) => Some(Err(e)), + } } pub fn tell(&self) -> io::Result { - self.0 + unsupported() } pub fn duplicate(&self) -> io::Result { - self.0 + unsupported() } - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - self.0 + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + set_perm_inner(&self.0, perm) } - pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - self.0 + pub fn set_times(&self, times: FileTimes) -> io::Result<()> { + set_times_inner(&self.0, times) } } @@ -355,8 +382,10 @@ impl DirBuilder { } impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut b = f.debug_struct("File"); + b.field("path", &self.0.path()); + b.finish() } } @@ -391,14 +420,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; - let mut file_info = f.file_info()?; - - unsafe { - (*file_info.as_mut_ptr()).attribute = - ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr() - }; - - f.set_file_info(file_info) + set_perm_inner(&f, perm) } pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { @@ -408,21 +430,7 @@ pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> { let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; - let mut file_info = f.file_info()?; - - if let Some(x) = times.accessed { - unsafe { - (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x); - } - } - - if let Some(x) = times.modified { - unsafe { - (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x); - } - } - - f.set_file_info(file_info) + set_times_inner(&f, times) } pub fn rmdir(p: &Path) -> io::Result<()> { @@ -480,6 +488,35 @@ pub fn copy(_from: &Path, _to: &Path) -> io::Result { unsupported() } +fn set_perm_inner(f: &uefi_fs::File, perm: FilePermissions) -> io::Result<()> { + let mut file_info = f.file_info()?; + + unsafe { + (*file_info.as_mut_ptr()).attribute = + ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr() + }; + + f.set_file_info(file_info) +} + +fn set_times_inner(f: &uefi_fs::File, times: FileTimes) -> io::Result<()> { + let mut file_info = f.file_info()?; + + if let Some(x) = times.accessed { + unsafe { + (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x); + } + } + + if let Some(x) = times.modified { + unsafe { + (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x); + } + } + + f.set_file_info(file_info) +} + mod uefi_fs { use r_efi::protocols::{device_path, file, simple_file_system}; From 67a76f9fb5893c87bee0360e72a74ed33e2b0741 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Mon, 29 Dec 2025 18:32:24 +0000 Subject: [PATCH 046/340] fix: `implicit_saturating_sub` suggests wrongly on untyped int literal --- clippy_lints/src/implicit_saturating_sub.rs | 27 ++++++++++++++++----- clippy_utils/src/lib.rs | 13 +++++++++- clippy_utils/src/sugg.rs | 2 +- tests/ui/implicit_saturating_sub.fixed | 8 ++++++ tests/ui/implicit_saturating_sub.rs | 8 ++++++ tests/ui/implicit_saturating_sub.stderr | 8 +++++- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 7b6f8729cb75..516f9e3aa60c 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,9 +1,13 @@ +use std::borrow::Cow; + use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::{ - SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym, + SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, is_integer_literal_untyped, + peel_blocks, peel_blocks_with_stmt, sym, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -238,10 +242,21 @@ fn check_subtraction( if eq_expr_value(cx, left, big_expr) && eq_expr_value(cx, right, little_expr) { // This part of the condition is voluntarily split from the one before to ensure that // if `snippet_opt` fails, it won't try the next conditions. - if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST)) - && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren) - && let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr) - { + if !is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST) { + let mut applicability = Applicability::MachineApplicable; + let big_expr_sugg = (if is_integer_literal_untyped(big_expr) { + let get_snippet = |span: Span| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + let big_expr_ty = cx.typeck_results().expr_ty(big_expr); + Cow::Owned(format!("{snippet}_{big_expr_ty}")) + }; + Sugg::hir_from_snippet(cx, big_expr, get_snippet) + } else { + Sugg::hir_with_applicability(cx, big_expr, "..", &mut applicability) + }) + .maybe_paren(); + let little_expr_sugg = Sugg::hir_with_applicability(cx, little_expr, "..", &mut applicability); + let sugg = format!( "{}{big_expr_sugg}.saturating_sub({little_expr_sugg}){}", if is_composited { "{ " } else { "" }, @@ -254,7 +269,7 @@ fn check_subtraction( "manual arithmetic check found", "replace it with", sugg, - Applicability::MachineApplicable, + applicability, ); } } else if eq_expr_value(cx, left, little_expr) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 954c32687af6..2d079deb0ce4 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -90,7 +90,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_ast::join_path_syms; +use rustc_ast::{LitIntType, join_path_syms}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexmap; use rustc_data_structures::packed::Pu128; @@ -1385,6 +1385,17 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { false } +/// Checks whether the given expression is an untyped integer literal. +pub fn is_integer_literal_untyped(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Int(_, suffix) = spanned.node + { + return suffix == LitIntType::Unsuffixed; + } + + false +} + /// Checks whether the given expression is a constant literal of the given value. pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool { if let ExprKind::Lit(spanned) = expr.kind diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 2ef2afb45071..3ade38bea8ed 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -127,7 +127,7 @@ impl<'a> Sugg<'a> { /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. - fn hir_from_snippet( + pub fn hir_from_snippet( cx: &LateContext<'_>, expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>, diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index 1aab6c54407e..22e59bbd2705 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -252,3 +252,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = 100_u8.saturating_sub(x); + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 7ca57a2902db..7fa19f0c8ad2 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -326,3 +326,11 @@ fn arbitrary_expression() { 0 }; } + +fn issue16307() { + let x: u8 = 100; + let y = if x >= 100 { 0 } else { 100 - x }; + //~^ implicit_saturating_sub + + println!("{y}"); +} diff --git a/tests/ui/implicit_saturating_sub.stderr b/tests/ui/implicit_saturating_sub.stderr index 0c225856fd07..2f3d2ba787e8 100644 --- a/tests/ui/implicit_saturating_sub.stderr +++ b/tests/ui/implicit_saturating_sub.stderr @@ -238,5 +238,11 @@ error: manual arithmetic check found LL | let _ = if a < b * 2 { 0 } else { a - b * 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b * 2)` -error: aborting due to 27 previous errors +error: manual arithmetic check found + --> tests/ui/implicit_saturating_sub.rs:332:13 + | +LL | let y = if x >= 100 { 0 } else { 100 - x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `100_u8.saturating_sub(x)` + +error: aborting due to 28 previous errors From 1ff953d63e8d470892d13cb99abeadb42bc1d997 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 29 Dec 2025 19:23:26 +0000 Subject: [PATCH 047/340] Fix and expand direct-access-external-data test This test currently doesn't fulfill its purpose, as `external dso_local` can still match `external {{.*}}`. Fix this by using CHECK-NOT directives. Also, this test is expanded to all platforms where it makes sense, instead of restricting to loongarch. --- .../direct-access-external-data.rs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index 5b2ff41ef052..c2c32d17ff7e 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -1,21 +1,25 @@ -//@ only-loongarch64-unknown-linux-gnu +//@ ignore-powerpc64 (handles dso_local differently) +//@ ignore-apple (handles dso_local differently) -//@ revisions: DEFAULT DIRECT INDIRECT +//@ revisions: DEFAULT PIE DIRECT INDIRECT //@ [DEFAULT] compile-flags: -C relocation-model=static -//@ [DIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=yes +//@ [PIE] compile-flags: -C relocation-model=pie +//@ [DIRECT] compile-flags: -C relocation-model=pie -Z direct-access-external-data=yes //@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no #![crate_type = "rlib"] -// DEFAULT: @VAR = external {{.*}} global i32 -// DIRECT: @VAR = external dso_local {{.*}} global i32 -// INDIRECT: @VAR = external {{.*}} global i32 - -extern "C" { - static VAR: i32; +unsafe extern "C" { + // CHECK: @VAR = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i32 + safe static VAR: i32; } #[no_mangle] -pub fn get() -> i32 { - unsafe { VAR } +pub fn refer() { + core::hint::black_box(VAR); } From 5467a398c2a33c9a49db2117c2c6f9e12015dd16 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 29 Dec 2025 17:21:29 +0000 Subject: [PATCH 048/340] Fix dso_local for external statics with linkage The current code applies `dso_local` to the internal generated symbols instead of the actually-externally one. --- compiler/rustc_codegen_llvm/src/consts.rs | 4 ++++ .../direct-access-external-data.rs | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 08c53179bc14..2b04f81c267f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -187,6 +187,10 @@ fn check_and_apply_linkage<'ll, 'tcx>( }; llvm::set_linkage(g1, base::linkage_to_llvm(linkage)); + // Normally this is done in `get_static_inner`, but when as we generate an internal global, + // it will apply the dso_local to the internal global instead, so do it here, too. + cx.assume_dso_local(g1, true); + // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is // discarded during linking (for example, if `foo` has weak diff --git a/tests/codegen-llvm/direct-access-external-data.rs b/tests/codegen-llvm/direct-access-external-data.rs index c2c32d17ff7e..73dc08dc2b57 100644 --- a/tests/codegen-llvm/direct-access-external-data.rs +++ b/tests/codegen-llvm/direct-access-external-data.rs @@ -8,6 +8,7 @@ //@ [INDIRECT] compile-flags: -C relocation-model=static -Z direct-access-external-data=no #![crate_type = "rlib"] +#![feature(linkage)] unsafe extern "C" { // CHECK: @VAR = external @@ -17,9 +18,31 @@ unsafe extern "C" { // INDIRECT-NOT: dso_local // CHECK-SAME: global i32 safe static VAR: i32; + + // When "linkage" is used, we generate an indirection global. + // Check dso_local is still applied to the actual global. + // CHECK: @EXTERNAL = external + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "external"] + safe static EXTERNAL: *const u32; + + // CHECK: @WEAK = extern_weak + // DEFAULT-SAME: dso_local + // PIE-NOT: dso_local + // DIRECT-SAME: dso_local + // INDIRECT-NOT: dso_local + // CHECK-SAME: global i8 + #[linkage = "extern_weak"] + safe static WEAK: *const u32; } #[no_mangle] pub fn refer() { core::hint::black_box(VAR); + core::hint::black_box(EXTERNAL); + core::hint::black_box(WEAK); } From b49e56d5a887a2c4dd8d78e9f215a219bd03a1ac Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Mon, 29 Dec 2025 22:11:16 +0000 Subject: [PATCH 049/340] fix typo (this commit will be squashed after review) --- src/tools/tidy/src/extra_checks/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index d5b360cbe549..bedcd08ca13f 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -754,7 +754,7 @@ enum ExtraCheckParseError { /// `auto` specified without lang part. AutoRequiresLang, /// `if-installed` specified without lang part. - IfInsatlledRequiresLang, + IfInstalledRequiresLang, } struct ExtraCheckArg { @@ -874,7 +874,7 @@ impl FromStr for ExtraCheckArg { if !if_installed && first == "if-installed" { let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::IfInsatlledRequiresLang); + return Err(ExtraCheckParseError::IfInstalledRequiresLang); }; if_installed = true; first = part; From 065791ee0603a45fefd686fb13b1e55dbf831ab3 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 13:01:12 -0800 Subject: [PATCH 050/340] Add allocator parameter to HashMap --- library/std/src/collections/hash/map.rs | 289 ++++++++++++++++++------ 1 file changed, 216 insertions(+), 73 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 251d62bd2033..ad6328f76ed6 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -4,6 +4,7 @@ mod tests; use hashbrown::hash_map as base; use self::Entry::*; +use crate::alloc::{Allocator, Global}; use crate::borrow::Borrow; use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::error::Error; @@ -243,8 +244,13 @@ use crate::ops::Index; #[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] -pub struct HashMap { - base: base::HashMap, +pub struct HashMap< + K, + V, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashMap, } impl HashMap { @@ -286,6 +292,46 @@ impl HashMap { } } +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> Self { + HashMap::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashMap` with at least the specified capacity using + /// the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + HashMap::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + impl HashMap { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. @@ -347,6 +393,47 @@ impl HashMap { pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder and + /// allocator. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) } + } + + /// Creates an empty `HashMap` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash map will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hasher` passed should implement the [`BuildHasher`] trait for + /// the `HashMap` to be useful, see its documentation for details. + /// + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) } + } /// Returns the number of elements the map can hold without reallocating. /// @@ -424,7 +511,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_keys(self) -> IntoKeys { + pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -519,7 +606,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] - pub fn into_values(self) -> IntoValues { + pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -648,7 +735,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain<'_, K, V> { + pub fn drain(&mut self) -> Drain<'_, K, V, A> { Drain { base: self.base.drain() } } @@ -688,7 +775,7 @@ impl HashMap { #[inline] #[rustc_lint_query_instability] #[stable(feature = "hash_extract_if", since = "1.88.0")] - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { @@ -762,10 +849,11 @@ impl HashMap { } } -impl HashMap +impl HashMap where K: Eq + Hash, S: BuildHasher, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashMap`. The collection may reserve more space to speculatively @@ -884,7 +972,7 @@ where /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, A> { map_entry(self.base.rustc_entry(key)) } @@ -1232,7 +1320,7 @@ where /// assert_eq!(err.value, "b"); /// ``` #[unstable(feature = "map_try_insert", issue = "82766")] - pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> { + pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>> { match self.entry(key) { Occupied(entry) => Err(OccupiedError { entry, value }), Vacant(entry) => Ok(entry.insert(value)), @@ -1298,11 +1386,12 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for HashMap +impl Clone for HashMap where K: Clone, V: Clone, S: Clone, + A: Allocator + Clone, { #[inline] fn clone(&self) -> Self { @@ -1316,13 +1405,14 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashMap +impl PartialEq for HashMap where K: Eq + Hash, V: PartialEq, S: BuildHasher, + A: Allocator, { - fn eq(&self, other: &HashMap) -> bool { + fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } @@ -1332,19 +1422,21 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashMap +impl Eq for HashMap where K: Eq + Hash, V: Eq, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for HashMap +impl Debug for HashMap where K: Debug, V: Debug, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -1364,11 +1456,12 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Index<&Q> for HashMap +impl Index<&Q> for HashMap where K: Eq + Hash + Borrow, Q: Eq + Hash, S: BuildHasher, + A: Allocator, { type Output = V; @@ -1523,11 +1616,15 @@ impl Default for IterMut<'_, K, V> { /// let iter = map.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - base: base::IntoIter, +pub struct IntoIter< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, } -impl IntoIter { +impl IntoIter { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -1656,11 +1753,16 @@ impl fmt::Debug for Values<'_, K, V> { /// ``` #[stable(feature = "drain", since = "1.6.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_drain_ty")] -pub struct Drain<'a, K: 'a, V: 'a> { - base: base::Drain<'a, K, V>, +pub struct Drain< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, V, A>, } -impl<'a, K, V> Drain<'a, K, V> { +impl<'a, K, V, A: Allocator> Drain<'a, K, V, A> { /// Returns an iterator of references over the remaining items. #[inline] pub(super) fn iter(&self) -> Iter<'_, K, V> { @@ -1687,8 +1789,14 @@ impl<'a, K, V> Drain<'a, K, V> { #[stable(feature = "hash_extract_if", since = "1.88.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` to remove and discard elements"] -pub struct ExtractIf<'a, K, V, F> { - base: base::ExtractIf<'a, K, V, F>, +pub struct ExtractIf< + 'a, + K, + V, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, V, F, A>, } /// A mutable iterator over the values of a `HashMap`. @@ -1740,8 +1848,12 @@ impl Default for ValuesMut<'_, K, V> { /// let iter_keys = map.into_keys(); /// ``` #[stable(feature = "map_into_keys_values", since = "1.54.0")] -pub struct IntoKeys { - inner: IntoIter, +pub struct IntoKeys< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1770,8 +1882,12 @@ impl Default for IntoKeys { /// let iter_keys = map.into_values(); /// ``` #[stable(feature = "map_into_keys_values", since = "1.54.0")] -pub struct IntoValues { - inner: IntoIter, +pub struct IntoValues< + K, + V, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + inner: IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1789,14 +1905,19 @@ impl Default for IntoValues { /// [`entry`]: HashMap::entry #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "HashMapEntry")] -pub enum Entry<'a, K: 'a, V: 'a> { +pub enum Entry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V, A>), /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V, A>), } #[stable(feature = "debug_hash_map", since = "1.12.0")] @@ -1812,12 +1933,17 @@ impl Debug for Entry<'_, K, V> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. #[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - base: base::RustcOccupiedEntry<'a, K, V>, +pub struct OccupiedEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcOccupiedEntry<'a, K, V, A>, } #[stable(feature = "debug_hash_map", since = "1.12.0")] -impl Debug for OccupiedEntry<'_, K, V> { +impl Debug for OccupiedEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) @@ -1829,12 +1955,17 @@ impl Debug for OccupiedEntry<'_, K, V> { /// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. #[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - base: base::RustcVacantEntry<'a, K, V>, +pub struct VacantEntry< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::RustcVacantEntry<'a, K, V, A>, } #[stable(feature = "debug_hash_map", since = "1.12.0")] -impl Debug for VacantEntry<'_, K, V> { +impl Debug for VacantEntry<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } @@ -1844,15 +1975,20 @@ impl Debug for VacantEntry<'_, K, V> { /// /// Contains the occupied entry, and the value that was not inserted. #[unstable(feature = "map_try_insert", issue = "82766")] -pub struct OccupiedError<'a, K: 'a, V: 'a> { +pub struct OccupiedError< + 'a, + K: 'a, + V: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// The entry in the map that was already occupied. - pub entry: OccupiedEntry<'a, K, V>, + pub entry: OccupiedEntry<'a, K, V, A>, /// The value which was not inserted, because the entry was already occupied. pub value: V, } #[unstable(feature = "map_try_insert", issue = "82766")] -impl Debug for OccupiedError<'_, K, V> { +impl Debug for OccupiedError<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedError") .field("key", self.entry.key()) @@ -1863,7 +1999,7 @@ impl Debug for OccupiedError<'_, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { +impl<'a, K: Debug, V: Debug, A: Allocator> fmt::Display for OccupiedError<'a, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, @@ -1876,10 +2012,10 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } #[unstable(feature = "map_try_insert", issue = "82766")] -impl<'a, K: Debug, V: Debug> Error for OccupiedError<'a, K, V> {} +impl<'a, K: Debug, V: Debug, A: Allocator> Error for OccupiedError<'a, K, V, A> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1891,7 +2027,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V, S> IntoIterator for &'a mut HashMap { +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1903,9 +2039,9 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashMap { +impl IntoIterator for HashMap { type Item = (K, V); - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each key-value /// pair out of the map in arbitrary order. The map cannot be used after @@ -1927,7 +2063,7 @@ impl IntoIterator for HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { IntoIter { base: self.base.into_iter() } } } @@ -2015,7 +2151,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = (K, V); #[inline] @@ -2040,17 +2176,17 @@ impl Iterator for IntoIter { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } @@ -2169,7 +2305,7 @@ impl fmt::Debug for ValuesMut<'_, K, V> { } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoKeys { +impl Iterator for IntoKeys { type Item = K; #[inline] @@ -2194,24 +2330,24 @@ impl Iterator for IntoKeys { } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoKeys { +impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoKeys {} +impl FusedIterator for IntoKeys {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl Iterator for IntoValues { +impl Iterator for IntoValues { type Item = V; #[inline] @@ -2236,24 +2372,24 @@ impl Iterator for IntoValues { } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl ExactSizeIterator for IntoValues { +impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl FusedIterator for IntoValues {} +impl FusedIterator for IntoValues {} #[stable(feature = "map_into_keys_values", since = "1.54.0")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() } } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, K, V> Iterator for Drain<'a, K, V> { +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { type Item = (K, V); #[inline] @@ -2274,17 +2410,17 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { } } #[stable(feature = "drain", since = "1.6.0")] -impl ExactSizeIterator for Drain<'_, K, V> { +impl ExactSizeIterator for Drain<'_, K, V, A> { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, K, V> {} +impl FusedIterator for Drain<'_, K, V, A> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Drain<'_, K, V> +impl fmt::Debug for Drain<'_, K, V, A> where K: fmt::Debug, V: fmt::Debug, @@ -2295,7 +2431,7 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl Iterator for ExtractIf<'_, K, V, F> +impl Iterator for ExtractIf<'_, K, V, F, A> where F: FnMut(&K, &mut V) -> bool, { @@ -2312,10 +2448,13 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +impl FusedIterator for ExtractIf<'_, K, V, F, A> where + F: FnMut(&K, &mut V) -> bool +{ +} #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl fmt::Debug for ExtractIf<'_, K, V, F> +impl fmt::Debug for ExtractIf<'_, K, V, F, A> where K: fmt::Debug, V: fmt::Debug, @@ -2325,7 +2464,7 @@ where } } -impl<'a, K, V> Entry<'a, K, V> { +impl<'a, K, V, A: Allocator> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. /// @@ -2473,7 +2612,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// ``` #[inline] #[stable(feature = "entry_insert", since = "1.83.0")] - pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { match self { Occupied(mut entry) => { entry.insert(value); @@ -2510,7 +2649,7 @@ impl<'a, K, V: Default> Entry<'a, K, V> { } } -impl<'a, K, V> OccupiedEntry<'a, K, V> { +impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -2682,7 +2821,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { } } -impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { +impl<'a, K: 'a, V: 'a, A: Allocator> VacantEntry<'a, K, V, A> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntry`. /// @@ -2760,7 +2899,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// ``` #[inline] #[stable(feature = "entry_insert", since = "1.83.0")] - pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { let base = self.base.insert_entry(value); OccupiedEntry { base } } @@ -2786,10 +2925,11 @@ where /// Inserts all new key-values from the iterator and replaces values with existing /// keys with new values returned from the iterator. #[stable(feature = "rust1", since = "1.0.0")] -impl Extend<(K, V)> for HashMap +impl Extend<(K, V)> for HashMap where K: Eq + Hash, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: T) { @@ -2808,11 +2948,12 @@ where } #[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap where K: Eq + Hash + Copy, V: Copy, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: T) { @@ -2831,7 +2972,9 @@ where } #[inline] -fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> { +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>( + raw: base::RustcEntry<'a, K, V, A>, +) -> Entry<'a, K, V, A> { match raw { base::RustcEntry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), base::RustcEntry::Vacant(base) => Entry::Vacant(VacantEntry { base }), From 0f516ec9294746eb781feb3c2787f0c9591e1c50 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 15:05:58 -0800 Subject: [PATCH 051/340] Update UI tests for addition of HashMap allocator --- tests/ui/generics/wrong-number-of-args.rs | 4 --- tests/ui/generics/wrong-number-of-args.stderr | 24 ++++++------------ tests/ui/inference/issue-71732.stderr | 2 +- ...clone-when-some-obligation-is-unmet.stderr | 2 +- tests/ui/privacy/suggest-box-new.rs | 2 +- tests/ui/privacy/suggest-box-new.stderr | 21 +++++++++------- .../suggestions/multi-suggestion.ascii.stderr | 21 +++++++++------- tests/ui/suggestions/multi-suggestion.rs | 2 +- .../multi-suggestion.unicode.stderr | 25 +++++++++++-------- tests/ui/traits/issue-77982.stderr | 2 +- 10 files changed, 51 insertions(+), 54 deletions(-) diff --git a/tests/ui/generics/wrong-number-of-args.rs b/tests/ui/generics/wrong-number-of-args.rs index 6524bd538b6b..8bc384a3d817 100644 --- a/tests/ui/generics/wrong-number-of-args.rs +++ b/tests/ui/generics/wrong-number-of-args.rs @@ -321,10 +321,6 @@ mod stdlib { //~| ERROR struct takes at least 2 //~| HELP add missing - type D = HashMap; - //~^ ERROR struct takes at most 3 - //~| HELP remove the - type E = HashMap<>; //~^ ERROR struct takes at least 2 generic arguments but 0 generic arguments //~| HELP add missing diff --git a/tests/ui/generics/wrong-number-of-args.stderr b/tests/ui/generics/wrong-number-of-args.stderr index bac0d26b622d..bedeeb812fc9 100644 --- a/tests/ui/generics/wrong-number-of-args.stderr +++ b/tests/ui/generics/wrong-number-of-args.stderr @@ -926,16 +926,8 @@ help: add missing generic arguments LL | type C = HashMap<'static, K, V>; | ++++++ -error[E0107]: struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:324:18 - | -LL | type D = HashMap; - | ^^^^^^^ ----- help: remove the unnecessary generic argument - | | - | expected at most 3 generic arguments - error[E0107]: struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:328:18 + --> $DIR/wrong-number-of-args.rs:324:18 | LL | type E = HashMap<>; | ^^^^^^^ expected at least 2 generic arguments @@ -946,7 +938,7 @@ LL | type E = HashMap; | ++++ error[E0107]: missing generics for enum `Result` - --> $DIR/wrong-number-of-args.rs:334:18 + --> $DIR/wrong-number-of-args.rs:330:18 | LL | type A = Result; | ^^^^^^ expected 2 generic arguments @@ -957,7 +949,7 @@ LL | type A = Result; | ++++++ error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:338:18 + --> $DIR/wrong-number-of-args.rs:334:18 | LL | type B = Result; | ^^^^^^ ------ supplied 1 generic argument @@ -970,7 +962,7 @@ LL | type B = Result; | +++ error[E0107]: enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:338:18 | LL | type C = Result<'static>; | ^^^^^^--------- help: remove the unnecessary generics @@ -978,7 +970,7 @@ LL | type C = Result<'static>; | expected 0 lifetime arguments error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:342:18 + --> $DIR/wrong-number-of-args.rs:338:18 | LL | type C = Result<'static>; | ^^^^^^ expected 2 generic arguments @@ -989,7 +981,7 @@ LL | type C = Result<'static, T, E>; | ++++++ error[E0107]: enum takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:348:18 + --> $DIR/wrong-number-of-args.rs:344:18 | LL | type D = Result; | ^^^^^^ ------ help: remove the unnecessary generic argument @@ -997,7 +989,7 @@ LL | type D = Result; | expected 2 generic arguments error[E0107]: enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:352:18 + --> $DIR/wrong-number-of-args.rs:348:18 | LL | type E = Result<>; | ^^^^^^ expected 2 generic arguments @@ -1007,7 +999,7 @@ help: add missing generic arguments LL | type E = Result; | ++++ -error: aborting due to 71 previous errors +error: aborting due to 70 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/inference/issue-71732.stderr b/tests/ui/inference/issue-71732.stderr index af8b310fd1d9..e79131694856 100644 --- a/tests/ui/inference/issue-71732.stderr +++ b/tests/ui/inference/issue-71732.stderr @@ -10,7 +10,7 @@ LL | .get(&"key".into()) - impl Borrow for String; - impl Borrow for T where T: ?Sized; -note: required by a bound in `HashMap::::get` +note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying the generic argument | diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr index 6272455cc57e..af0f67b7c1c0 100644 --- a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr @@ -6,7 +6,7 @@ LL | let mut copy: Vec = map.clone().into_values().collect(); | | | move occurs because value has type `HashMap`, which does not implement the `Copy` trait | -note: `HashMap::::into_values` takes ownership of the receiver `self`, which moves value +note: `HashMap::::into_values` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL note: if `Hash128_1` implemented `Clone`, you could clone the value --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:8:1 diff --git a/tests/ui/privacy/suggest-box-new.rs b/tests/ui/privacy/suggest-box-new.rs index ff585387020e..87ee13d15edb 100644 --- a/tests/ui/privacy/suggest-box-new.rs +++ b/tests/ui/privacy/suggest-box-new.rs @@ -14,7 +14,7 @@ fn main() { let _ = std::collections::HashMap(); //~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` let _ = std::collections::HashMap {}; - //~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + //~^ ERROR cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields let _ = Box {}; //~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields // test that we properly instantiate the parameter of `Box::::new` with an inference variable diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index e3a7e5f62017..7367672351d6 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -5,6 +5,7 @@ LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ::: $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL | let _ = std::collections::HashMap::new(); | +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL | let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), | -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields --> $DIR/suggest-box-new.rs:16:13 | LL | let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); | LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index c2ae19b1ae9a..2da0f9bd12c2 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -5,6 +5,7 @@ LL | let _ = std::collections::HashMap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ::: $SRC_DIR/std/src/collections/hash/map.rs:LL:COL | = note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL | let _ = std::collections::HashMap::new(); | +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL | let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), | -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields --> $DIR/multi-suggestion.rs:19:13 | LL | let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); | LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + | +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); | LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - | -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); | + = and 4 other candidates help: consider using the `Default` trait | LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/suggestions/multi-suggestion.rs b/tests/ui/suggestions/multi-suggestion.rs index 99d2407aa212..6d822a8e5aff 100644 --- a/tests/ui/suggestions/multi-suggestion.rs +++ b/tests/ui/suggestions/multi-suggestion.rs @@ -17,6 +17,6 @@ fn main() { let _ = std::collections::HashMap(); //[ascii]~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` let _ = std::collections::HashMap {}; - //[ascii]~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + //[ascii]~^ ERROR cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields let _ = Box {}; //[ascii]~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields } diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index fc187cac91d1..69529b67b775 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -5,6 +5,7 @@ LL │ let _ = std::collections::HashMap(); │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ ╰╴ ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + ⸬ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL │ ╰ note: `std::collections::HashMap` defined here help: you might have meant to use an associated function to build this type @@ -12,14 +13,15 @@ help: you might have meant to use an associated function to build this type LL │ let _ = std::collections::HashMap::new(); ├╴ +++++ LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::new_in(_); + ├╴ +LL - let _ = std::collections::HashMap(); LL + let _ = std::collections::HashMap::with_capacity(_); ├╴ LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_hasher(_); - ├╴ -LL - let _ = std::collections::HashMap(); -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); - ╰╴ +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); + │ + ╰ and 4 other candidates help: consider using the `Default` trait ╭╴ LL │ let _ = ::default(); @@ -73,7 +75,7 @@ LL - })), LL + wtf: Some(::default()), ╰╴ -error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields +error: cannot construct `HashMap<_, _, _, _>` with struct literal syntax due to private fields ╭▸ $DIR/multi-suggestion.rs:19:13 │ LL │ let _ = std::collections::HashMap {}; @@ -86,14 +88,15 @@ LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::new(); ├╴ LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new_in(_); + ├╴ +LL - let _ = std::collections::HashMap {}; LL + let _ = std::collections::HashMap::with_capacity(_); ├╴ LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_hasher(_); - ├╴ -LL - let _ = std::collections::HashMap {}; -LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); - ╰╴ +LL + let _ = std::collections::HashMap::with_capacity_in(_, _); + │ + ╰ and 4 other candidates help: consider using the `Default` trait ╭╴ LL - let _ = std::collections::HashMap {}; diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index edc7f56ea467..4bc24e81215a 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -10,7 +10,7 @@ LL | opts.get(opt.as_ref()); - impl Borrow for String; - impl Borrow for T where T: ?Sized; -note: required by a bound in `HashMap::::get` +note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying the generic argument | From ef7616dbaa9378ac8028f76f9ce74a9c4237565e Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 5 Nov 2025 14:44:14 -0800 Subject: [PATCH 052/340] Add allocator parameter to HashSet --- library/std/src/collections/hash/set.rs | 429 ++++++++++++++++-------- 1 file changed, 286 insertions(+), 143 deletions(-) diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 6795da80aacb..02a4a0d9c815 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -4,6 +4,7 @@ mod tests; use hashbrown::hash_set as base; use super::map::map_try_reserve_error; +use crate::alloc::{Allocator, Global}; use crate::borrow::Borrow; use crate::collections::TryReserveError; use crate::fmt; @@ -122,8 +123,12 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] #[stable(feature = "rust1", since = "1.0.0")] -pub struct HashSet { - base: base::HashSet, +pub struct HashSet< + T, + S = RandomState, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::HashSet, } impl HashSet { @@ -166,7 +171,141 @@ impl HashSet { } } +impl HashSet { + /// Creates an empty `HashSet` in the provided allocator. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn new_in(alloc: A) -> HashSet { + HashSet::with_hasher_in(Default::default(), alloc) + } + + /// Creates an empty `HashSet` with at least the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_in(capacity: usize, alloc: A) -> HashSet { + HashSet::with_capacity_and_hasher_in(capacity, Default::default(), alloc) + } +} + impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] + pub const fn with_hasher(hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_hasher(hasher) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::RandomState; + /// + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys and will allocate memory using the provided allocator. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) } + } + + /// Creates an empty `HashSet` with at least the specified capacity, using + /// `hasher` to hash the keys and `alloc` to allocate memory. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is zero, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the `HashSet` to be useful, see its documentation for details. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet { + HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) } + } + /// Returns the number of elements the set can hold without reallocating. /// /// # Examples @@ -272,7 +411,7 @@ impl HashSet { #[inline] #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain<'_, T> { + pub fn drain(&mut self) -> Drain<'_, T, A> { Drain { base: self.base.drain() } } @@ -309,7 +448,7 @@ impl HashSet { #[inline] #[rustc_lint_query_instability] #[stable(feature = "hash_extract_if", since = "1.88.0")] - pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> + pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool, { @@ -362,67 +501,6 @@ impl HashSet { self.base.clear() } - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the `HashSet` to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_hasher(s); - /// set.insert(2); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] - pub const fn with_hasher(hasher: S) -> HashSet { - HashSet { base: base::HashSet::with_hasher(hasher) } - } - - /// Creates an empty `HashSet` with at least the specified capacity, using - /// `hasher` to hash the keys. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. This method is allowed to allocate for more elements than - /// `capacity`. If `capacity` is zero, the hash set will not allocate. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the `HashSet` to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::RandomState; - /// - /// let s = RandomState::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10, s); - /// set.insert(1); - /// ``` - #[inline] - #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } - } - /// Returns a reference to the set's [`BuildHasher`]. /// /// # Examples @@ -442,10 +520,11 @@ impl HashSet { } } -impl HashSet +impl HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to speculatively @@ -569,7 +648,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { + pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S, A> { Difference { iter: self.iter(), other } } @@ -599,8 +678,8 @@ where #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>( &'a self, - other: &'a HashSet, - ) -> SymmetricDifference<'a, T, S> { + other: &'a HashSet, + ) -> SymmetricDifference<'a, T, S, A> { SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } @@ -631,7 +710,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { + pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S, A> { if self.len() <= other.len() { Intersection { iter: self.iter(), other } } else { @@ -660,7 +739,7 @@ where #[inline] #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] - pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { + pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S, A> { if self.len() >= other.len() { Union { iter: self.iter().chain(other.difference(self)) } } else { @@ -812,7 +891,7 @@ where /// ``` #[inline] #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn entry(&mut self, value: T) -> Entry<'_, T, S> { + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { map_entry(self.base.entry(value)) } @@ -834,7 +913,7 @@ where /// assert_eq!(a.is_disjoint(&b), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_disjoint(&self, other: &HashSet) -> bool { + pub fn is_disjoint(&self, other: &HashSet) -> bool { if self.len() <= other.len() { self.iter().all(|v| !other.contains(v)) } else { @@ -860,7 +939,7 @@ where /// assert_eq!(set.is_subset(&sup), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_subset(&self, other: &HashSet) -> bool { + pub fn is_subset(&self, other: &HashSet) -> bool { if self.len() <= other.len() { self.iter().all(|v| other.contains(v)) } else { false } } @@ -886,7 +965,7 @@ where /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_superset(&self, other: &HashSet) -> bool { + pub fn is_superset(&self, other: &HashSet) -> bool { other.is_subset(self) } @@ -995,7 +1074,7 @@ where } #[inline] -fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { +fn map_entry<'a, K: 'a, V: 'a, A: Allocator>(raw: base::Entry<'a, K, V, A>) -> Entry<'a, K, V, A> { match raw { base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }), base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }), @@ -1003,10 +1082,11 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for HashSet +impl Clone for HashSet where T: Clone, S: Clone, + A: Allocator + Clone, { #[inline] fn clone(&self) -> Self { @@ -1024,12 +1104,13 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for HashSet +impl PartialEq for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { - fn eq(&self, other: &HashSet) -> bool { + fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } @@ -1039,17 +1120,19 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for HashSet +impl Eq for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for HashSet +impl fmt::Debug for HashSet where T: fmt::Debug, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -1107,10 +1190,11 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Extend for HashSet +impl Extend for HashSet where T: Eq + Hash, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: I) { @@ -1129,10 +1213,11 @@ where } #[stable(feature = "hash_extend_copy", since = "1.4.0")] -impl<'a, T, S> Extend<&'a T> for HashSet +impl<'a, T, S, A> Extend<&'a T> for HashSet where T: 'a + Eq + Hash + Copy, S: BuildHasher, + A: Allocator, { #[inline] fn extend>(&mut self, iter: I) { @@ -1341,8 +1426,11 @@ impl Default for Iter<'_, K> { /// let mut iter = a.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - base: base::IntoIter, +pub struct IntoIter< + K, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::IntoIter, } #[stable(feature = "default_iters_hash", since = "1.83.0")] @@ -1371,8 +1459,12 @@ impl Default for IntoIter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_drain_ty")] -pub struct Drain<'a, K: 'a> { - base: base::Drain<'a, K>, +pub struct Drain< + 'a, + K: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::Drain<'a, K, A>, } /// A draining, filtering iterator over the items of a `HashSet`. @@ -1393,8 +1485,13 @@ pub struct Drain<'a, K: 'a> { #[stable(feature = "hash_extract_if", since = "1.88.0")] #[must_use = "iterators are lazy and do nothing unless consumed; \ use `retain` to remove and discard elements"] -pub struct ExtractIf<'a, K, F> { - base: base::ExtractIf<'a, K, F>, +pub struct ExtractIf< + 'a, + K, + F, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::ExtractIf<'a, K, F, A>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1417,11 +1514,16 @@ pub struct ExtractIf<'a, K, F> { #[must_use = "this returns the intersection as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Intersection<'a, T: 'a, S: 'a> { +pub struct Intersection< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// A lazy iterator producing elements in the difference of `HashSet`s. @@ -1444,11 +1546,16 @@ pub struct Intersection<'a, T: 'a, S: 'a> { #[must_use = "this returns the difference as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Difference<'a, T: 'a, S: 'a> { +pub struct Difference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// A lazy iterator producing elements in the symmetric difference of `HashSet`s. @@ -1471,8 +1578,13 @@ pub struct Difference<'a, T: 'a, S: 'a> { #[must_use = "this returns the difference as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct SymmetricDifference<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, +pub struct SymmetricDifference< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, } /// A lazy iterator producing elements in the union of `HashSet`s. @@ -1495,12 +1607,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { #[must_use = "this returns the union as an iterator, \ without modifying either input set"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Union<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>>, +pub struct Union< + 'a, + T: 'a, + S: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + iter: Chain, Difference<'a, T, S, A>>, } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> IntoIterator for &'a HashSet { +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1512,9 +1629,9 @@ impl<'a, T, S> IntoIterator for &'a HashSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for HashSet { +impl IntoIterator for HashSet { type Item = T; - type IntoIter = IntoIter; + type IntoIter = IntoIter; /// Creates a consuming iterator, that is, one that moves each value out /// of the set in arbitrary order. The set cannot be used after calling @@ -1538,7 +1655,7 @@ impl IntoIterator for HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - fn into_iter(self) -> IntoIter { + fn into_iter(self) -> IntoIter { IntoIter { base: self.base.into_iter() } } } @@ -1593,7 +1710,7 @@ impl fmt::Debug for Iter<'_, K> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +impl Iterator for IntoIter { type Item = K; #[inline] @@ -1618,24 +1735,24 @@ impl Iterator for IntoIter { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { +impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} +impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for IntoIter { +impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.base, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K> Iterator for Drain<'a, K> { +impl<'a, K, A: Allocator> Iterator for Drain<'a, K, A> { type Item = K; #[inline] @@ -1656,24 +1773,24 @@ impl<'a, K> Iterator for Drain<'a, K> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Drain<'_, K> { +impl ExactSizeIterator for Drain<'_, K, A> { #[inline] fn len(&self) -> usize { self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Drain<'_, K> {} +impl FusedIterator for Drain<'_, K, A> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Drain<'_, K> { +impl fmt::Debug for Drain<'_, K, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.base, f) } } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl Iterator for ExtractIf<'_, K, F> +impl Iterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool, { @@ -1690,10 +1807,10 @@ where } #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} #[stable(feature = "hash_extract_if", since = "1.88.0")] -impl fmt::Debug for ExtractIf<'_, K, F> +impl fmt::Debug for ExtractIf<'_, K, F, A> where K: fmt::Debug, { @@ -1703,7 +1820,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Intersection<'_, T, S> { +impl Clone for Intersection<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Intersection { iter: self.iter.clone(), ..*self } @@ -1711,10 +1828,11 @@ impl Clone for Intersection<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Intersection<'a, T, S> +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1745,10 +1863,11 @@ where } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Intersection<'_, T, S> +impl fmt::Debug for Intersection<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1756,15 +1875,16 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Intersection<'_, T, S> +impl FusedIterator for Intersection<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Difference<'_, T, S> { +impl Clone for Difference<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Difference { iter: self.iter.clone(), ..*self } @@ -1772,10 +1892,11 @@ impl Clone for Difference<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Difference<'a, T, S> +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1806,18 +1927,20 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Difference<'_, T, S> +impl FusedIterator for Difference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Difference<'_, T, S> +impl fmt::Debug for Difference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1825,7 +1948,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SymmetricDifference<'_, T, S> { +impl Clone for SymmetricDifference<'_, T, S, A> { #[inline] fn clone(&self) -> Self { SymmetricDifference { iter: self.iter.clone() } @@ -1833,10 +1956,11 @@ impl Clone for SymmetricDifference<'_, T, S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1859,18 +1983,20 @@ where } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SymmetricDifference<'_, T, S> +impl FusedIterator for SymmetricDifference<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for SymmetricDifference<'_, T, S> +impl fmt::Debug for SymmetricDifference<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1878,7 +2004,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Union<'_, T, S> { +impl Clone for Union<'_, T, S, A> { #[inline] fn clone(&self) -> Self { Union { iter: self.iter.clone() } @@ -1886,7 +2012,7 @@ impl Clone for Union<'_, T, S> { } #[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Union<'_, T, S> +impl FusedIterator for Union<'_, T, S, A> where T: Eq + Hash, S: BuildHasher, @@ -1894,10 +2020,11 @@ where } #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for Union<'_, T, S> +impl fmt::Debug for Union<'_, T, S, A> where T: fmt::Debug + Eq + Hash, S: BuildHasher, + A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() @@ -1905,10 +2032,11 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, S> Iterator for Union<'a, T, S> +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> where T: Eq + Hash, S: BuildHasher, + A: Allocator, { type Item = &'a T; @@ -1973,7 +2101,12 @@ where /// assert_eq!(vec, ["a", "b", "c", "d", "e"]); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub enum Entry<'a, T, S> { +pub enum Entry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { /// An occupied entry. /// /// # Examples @@ -1990,7 +2123,7 @@ pub enum Entry<'a, T, S> { /// Entry::Occupied(_) => { } /// } /// ``` - Occupied(OccupiedEntry<'a, T, S>), + Occupied(OccupiedEntry<'a, T, S, A>), /// A vacant entry. /// @@ -2008,11 +2141,11 @@ pub enum Entry<'a, T, S> { /// Entry::Vacant(_) => { } /// } /// ``` - Vacant(VacantEntry<'a, T, S>), + Vacant(VacantEntry<'a, T, S, A>), } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for Entry<'_, T, S> { +impl fmt::Debug for Entry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -2060,12 +2193,17 @@ impl fmt::Debug for Entry<'_, T, S> { /// assert_eq!(set.len(), 2); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub struct OccupiedEntry<'a, T, S> { - base: base::OccupiedEntry<'a, T, S>, +pub struct OccupiedEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::OccupiedEntry<'a, T, S, A>, } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for OccupiedEntry<'_, T, S> { +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry").field("value", self.get()).finish() } @@ -2100,18 +2238,23 @@ impl fmt::Debug for OccupiedEntry<'_, T, S> { /// assert!(set.contains("b") && set.len() == 2); /// ``` #[unstable(feature = "hash_set_entry", issue = "60896")] -pub struct VacantEntry<'a, T, S> { - base: base::VacantEntry<'a, T, S>, +pub struct VacantEntry< + 'a, + T, + S, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + base: base::VacantEntry<'a, T, S, A>, } #[unstable(feature = "hash_set_entry", issue = "60896")] -impl fmt::Debug for VacantEntry<'_, T, S> { +impl fmt::Debug for VacantEntry<'_, T, S, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.get()).finish() } } -impl<'a, T, S> Entry<'a, T, S> { +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { /// Sets the value of the entry, and returns an OccupiedEntry. /// /// # Examples @@ -2128,7 +2271,7 @@ impl<'a, T, S> Entry<'a, T, S> { /// ``` #[inline] #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn insert(self) -> OccupiedEntry<'a, T, S> + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> where T: Hash, S: BuildHasher, @@ -2198,7 +2341,7 @@ impl<'a, T, S> Entry<'a, T, S> { } } -impl OccupiedEntry<'_, T, S> { +impl OccupiedEntry<'_, T, S, A> { /// Gets a reference to the value in the entry. /// /// # Examples @@ -2255,7 +2398,7 @@ impl OccupiedEntry<'_, T, S> { } } -impl<'a, T, S> VacantEntry<'a, T, S> { +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { /// Gets a reference to the value that would be used when inserting /// through the `VacantEntry`. /// @@ -2325,7 +2468,7 @@ impl<'a, T, S> VacantEntry<'a, T, S> { } #[inline] - fn insert_entry(self) -> OccupiedEntry<'a, T, S> + fn insert_entry(self) -> OccupiedEntry<'a, T, S, A> where T: Hash, S: BuildHasher, From 72c6b0714142f45b7c8989b2bc54de22c4a38c6d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 30 Dec 2025 10:57:15 +0800 Subject: [PATCH 053/340] Migrate `move_arm_cond_to_match_guard` assist to use `SyntaxEditor` --- .../ide-assists/src/handlers/move_guard.rs | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index 8daf86923d92..1c0c6e43d53b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -1,6 +1,11 @@ +use itertools::Itertools; use syntax::{ SyntaxKind::WHITESPACE, - ast::{AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make}, + ast::{ + AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat, edit::AstNodeEdit, make, + syntax_factory::SyntaxFactory, + }, + syntax_editor::Element, }; use crate::{AssistContext, AssistId, Assists}; @@ -131,8 +136,10 @@ pub(crate) fn move_arm_cond_to_match_guard( AssistId::refactor_rewrite("move_arm_cond_to_match_guard"), "Move condition to match guard", replace_node.text_range(), - |edit| { - edit.delete(match_arm.syntax().text_range()); + |builder| { + let make = SyntaxFactory::without_mappings(); + let mut replace_arms = vec![]; + // Dedent if if_expr is in a BlockExpr let dedent = if needs_dedent { cov_mark::hit!(move_guard_ifelse_in_block); @@ -141,47 +148,30 @@ pub(crate) fn move_arm_cond_to_match_guard( cov_mark::hit!(move_guard_ifelse_else_block); 0 }; - let then_arm_end = match_arm.syntax().text_range().end(); let indent_level = match_arm.indent_level(); - let spaces = indent_level; - let mut first = true; for (cond, block) in conds_blocks { - if !first { - edit.insert(then_arm_end, format!("\n{spaces}")); - } else { - first = false; - } - let guard = format!("{match_pat} if {cond} => "); - edit.insert(then_arm_end, guard); let only_expr = block.statements().next().is_none(); - match &block.tail_expr() { - Some(then_expr) if only_expr => { - edit.insert(then_arm_end, then_expr.syntax().text()); - edit.insert(then_arm_end, ","); - } - _ => { - let to_insert = block.dedent(dedent.into()).syntax().text(); - edit.insert(then_arm_end, to_insert) - } - } + let expr = match block.tail_expr() { + Some(then_expr) if only_expr => then_expr, + _ => block.dedent(dedent.into()).into(), + }; + let guard = make.match_guard(cond); + let new_arm = make.match_arm(match_pat.clone(), Some(guard), expr); + replace_arms.push(new_arm); } - if let Some(e) = tail { + if let Some(block) = tail { cov_mark::hit!(move_guard_ifelse_else_tail); - let guard = format!("\n{spaces}{match_pat} => "); - edit.insert(then_arm_end, guard); - let only_expr = e.statements().next().is_none(); - match &e.tail_expr() { + let only_expr = block.statements().next().is_none(); + let expr = match block.tail_expr() { Some(expr) if only_expr => { cov_mark::hit!(move_guard_ifelse_expr_only); - edit.insert(then_arm_end, expr.syntax().text()); - edit.insert(then_arm_end, ","); + expr } - _ => { - let to_insert = e.dedent(dedent.into()).syntax().text(); - edit.insert(then_arm_end, to_insert) - } - } + _ => block.dedent(dedent.into()).into(), + }; + let new_arm = make.match_arm(match_pat, None, expr); + replace_arms.push(new_arm); } else { // There's no else branch. Add a pattern without guard, unless the following match // arm is `_ => ...` @@ -193,9 +183,21 @@ pub(crate) fn move_arm_cond_to_match_guard( { cov_mark::hit!(move_guard_ifelse_has_wildcard); } - _ => edit.insert(then_arm_end, format!("\n{spaces}{match_pat} => {{}}")), + _ => { + let block_expr = make.expr_empty_block().into(); + replace_arms.push(make.match_arm(match_pat, None, block_expr)); + } } } + + let mut edit = builder.make_editor(match_arm.syntax()); + + let newline = make.whitespace(&format!("\n{indent_level}")); + let replace_arms = replace_arms.iter().map(|it| it.syntax().syntax_element()); + let replace_arms = Itertools::intersperse(replace_arms, newline.syntax_element()); + edit.replace_with_many(match_arm.syntax(), replace_arms.collect()); + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } From ea3839ae18ff5850e35820017a583235722e8f7f Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez Date: Tue, 30 Dec 2025 14:15:00 +0100 Subject: [PATCH 054/340] Remove a single allocation on doc lints --- clippy_lints/src/doc/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 120da92da944..5ff66f10a3fe 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -869,10 +869,12 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ }), true, ); - let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| { - add_doc_fragment(&mut acc, fragment); - acc - }); + + let mut doc = String::with_capacity(fragments.iter().map(|frag| frag.doc.as_str().len() + 1).sum()); + + for fragment in &fragments { + add_doc_fragment(&mut doc, fragment); + } doc.pop(); if doc.trim().is_empty() { From a74de276d1e847ae8ecb8107d7b7f10dd7f4486f Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 30 Dec 2025 17:55:07 +0100 Subject: [PATCH 055/340] remove another single allocation --- clippy_lints/src/booleans.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index a04a56d72bc0..0bd459d8b021 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, Symbol, SyntaxContext}; +use std::fmt::Write as _; declare_clippy_lint! { /// ### What it does @@ -356,7 +357,7 @@ impl SuggestContext<'_, '_, '_> { if app != Applicability::MachineApplicable { return None; } - self.output.push_str(&(!snip).to_string()); + let _cannot_fail = write!(&mut self.output, "{}", &(!snip)); } }, True | False | Not(_) => { From 862ab4cab6f2031800838c62f6a8b06b825a054a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 14:23:56 +0530 Subject: [PATCH 056/340] remove unwanted comment --- .../rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 25a5104c5df3..1a929a02ac3b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -81,7 +81,6 @@ fn run_new() -> io::Result<()> { } bidirectional::Request::ApiVersionCheck {} => { - // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout) send_response::( &stdout, bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), From ec7db072ee3cc62f825f1b918cd8043cca03c6c7 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 31 Dec 2025 12:59:40 +0200 Subject: [PATCH 057/340] Allow finding references from doc comments --- .../crates/ide/src/references.rs | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index ffae7bf6c7c5..4918fe4ff9a4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -38,7 +38,8 @@ use syntax::{ }; use crate::{ - Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related, + Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, + doc_links::token_as_doc_comment, highlight_related, }; /// Result of a reference search operation. @@ -211,6 +212,13 @@ pub(crate) fn find_defs( syntax: &SyntaxNode, offset: TextSize, ) -> Option> { + if let Some(token) = syntax.token_at_offset(offset).left_biased() + && let Some(doc_comment) = token_as_doc_comment(&token) + { + return doc_comment + .get_definition_with_descend_at(sema, offset, |def, _, _| Some(vec![def])); + } + let token = syntax.token_at_offset(offset).find(|t| { matches!( t.kind(), @@ -785,6 +793,23 @@ fn main() { ); } + #[test] + fn test_find_all_refs_in_comments() { + check( + r#" +struct Foo; + +/// $0[`Foo`] is just above +struct Bar; +"#, + expect![[r#" + Foo Struct FileId(0) 0..11 7..10 + + (no references) + "#]], + ); + } + #[test] fn search_filters_by_range() { check( From 2a7e3e6f2361d081d94822ac53474cd9e1010f6a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:50:14 +0530 Subject: [PATCH 058/340] add bidirectional flow for file method --- .../crates/load-cargo/src/lib.rs | 14 ++++++++++ .../src/bidirectional_protocol/msg.rs | 2 ++ .../proc-macro-srv-cli/src/main_loop.rs | 26 +++++++++++++++++++ .../crates/proc-macro-srv/src/lib.rs | 1 + .../src/server_impl/rust_analyzer_span.rs | 13 +++++----- 5 files changed, 50 insertions(+), 6 deletions(-) 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 5122051fb3c2..c8a157e88e17 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -546,6 +546,20 @@ impl ProcMacroExpander for Expander { let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text: slice }) } + SubRequest::FileName { file_id } => { + let file = FileId::from_raw(file_id); + let source_root_id = db.file_source_root(file).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); + + let name = source_root.path_for_file(&file).and_then(|path| { + path.name_and_extension().map(|(name, ext)| match ext { + Some(ext) => format!("{name}.{ext}"), + None => name.to_owned(), + }) + }); + + Ok(SubResponse::FileNameResult { name: name.unwrap_or_default() }) + } }; match self.0.expand( subtree.view(), diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index cf8becd922de..7edd9062d994 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -10,11 +10,13 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { + FileName { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { + FileNameResult { name: String }, SourceTextResult { text: Option }, } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 1a929a02ac3b..279eab06c0b4 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -167,6 +167,32 @@ struct ProcMacroClientHandle<'a, C: Codec> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { + fn file(&mut self, file_id: u32) -> String { + let req = + bidirectional::BidirectionalMessage::SubRequest(bidirectional::SubRequest::FileName { + file_id, + }); + + if req.write::<_, C>(&mut self.stdout.lock()).is_err() { + return String::new(); + } + + let msg = match bidirectional::BidirectionalMessage::read::<_, C>( + &mut self.stdin.lock(), + self.buf, + ) { + Ok(Some(msg)) => msg, + _ => return String::new(), + }; + + match msg { + bidirectional::BidirectionalMessage::SubResponse( + bidirectional::SubResponse::FileNameResult { name }, + ) => name, + _ => String::new(), + } + } + fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { let req = bidirectional::BidirectionalMessage::SubRequest( bidirectional::SubRequest::SourceText { file_id, start, end }, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 17ffa29ce172..1804238a32a1 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,6 +94,7 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { + fn file(&mut self, file_id: u32) -> String; fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 5d9090c060e0..7a9d655431f5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -127,13 +127,14 @@ impl server::Span for RaSpanServer<'_> { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span) } - fn file(&mut self, _: Self::Span) -> String { - // FIXME - String::new() + fn file(&mut self, span: Self::Span) -> String { + self.callback + .as_mut() + .map(|cb| cb.file(span.anchor.file_id.file_id().index())) + .unwrap_or_default() } - fn local_file(&mut self, _: Self::Span) -> Option { - // FIXME - None + fn local_file(&mut self, span: Self::Span) -> Option { + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools From abbf0272fa13f49532ece6a125de288ba39c82c7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:50:20 +0530 Subject: [PATCH 059/340] add bidirectional flow for local file method --- .../crates/load-cargo/src/lib.rs | 14 +++++++++++ .../src/bidirectional_protocol/msg.rs | 2 ++ .../proc-macro-srv-cli/src/main_loop.rs | 25 +++++++++++++++++++ .../crates/proc-macro-srv/src/lib.rs | 1 + 4 files changed, 42 insertions(+) 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 c8a157e88e17..dc75abe7ad8c 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -540,6 +540,20 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { + SubRequest::LocalFileName { file_id } => { + let file = FileId::from_raw(file_id); + let source_root_id = db.file_source_root(file).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); + + let name = source_root + .path_for_file(&file) + .and_then(|path| path.clone().into_abs_path()) + .and_then(|path| { + path.as_path().file_name().map(|filename| filename.to_owned()) + }); + + Ok(SubResponse::LocalFileNameResult { name }) + } SubRequest::SourceText { file_id, start, end } => { let file = FileId::from_raw(file_id); let text = db.file_text(file).text(db); diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 7edd9062d994..2819a92fe33a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -12,12 +12,14 @@ use crate::{ pub enum SubRequest { FileName { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, + LocalFileName { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { FileNameResult { name: String }, SourceTextResult { text: Option }, + LocalFileNameResult { name: Option }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 279eab06c0b4..76119b27a8b6 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -217,6 +217,31 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl _ => None, } } + + fn local_file(&mut self, file_id: u32) -> Option { + let req = bidirectional::BidirectionalMessage::SubRequest( + bidirectional::SubRequest::LocalFileName { file_id }, + ); + + if req.write::<_, C>(&mut self.stdout.lock()).is_err() { + return Some(String::new()); + } + + let msg = match bidirectional::BidirectionalMessage::read::<_, C>( + &mut self.stdin.lock(), + self.buf, + ) { + Ok(msg) => msg, + _ => return None, + }; + + match msg { + Some(bidirectional::BidirectionalMessage::SubResponse( + bidirectional::SubResponse::LocalFileNameResult { name }, + )) => Some(name.unwrap_or_default()), + _ => None, + } + } } fn handle_expand_ra( diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 1804238a32a1..8de712dbd386 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -96,6 +96,7 @@ pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Syn pub trait ProcMacroClientInterface { fn file(&mut self, file_id: u32) -> String; fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; + fn local_file(&mut self, file_id: u32) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; From c4dd25f6cd2e11e0a4f055bba2cffed5a1553cb2 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 31 Dec 2025 17:54:22 +0530 Subject: [PATCH 060/340] add roundtrip abstraction to remove subrequest subresponse boilerplate code --- .../proc-macro-srv-cli/src/main_loop.rs | 79 ++++++------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 76119b27a8b6..77cb8760a100 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -166,79 +166,48 @@ struct ProcMacroClientHandle<'a, C: Codec> { buf: &'a mut C::Buf, } -impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - let req = - bidirectional::BidirectionalMessage::SubRequest(bidirectional::SubRequest::FileName { - file_id, - }); +impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { + fn roundtrip( + &mut self, + req: bidirectional::SubRequest, + ) -> Option { + let msg = bidirectional::BidirectionalMessage::SubRequest(req); - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return String::new(); + if msg.write::<_, C>(&mut self.stdout.lock()).is_err() { + return None; } - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(Some(msg)) => msg, - _ => return String::new(), - }; + match bidirectional::BidirectionalMessage::read::<_, C>(&mut self.stdin.lock(), self.buf) { + Ok(Some(msg)) => Some(msg), + _ => None, + } + } +} - match msg { - bidirectional::BidirectionalMessage::SubResponse( +impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { + fn file(&mut self, file_id: u32) -> String { + match self.roundtrip(bidirectional::SubRequest::FileName { file_id }) { + Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FileNameResult { name }, - ) => name, + )) => name, _ => String::new(), } } fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { - let req = bidirectional::BidirectionalMessage::SubRequest( - bidirectional::SubRequest::SourceText { file_id, start, end }, - ); - - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return None; - } - - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(Some(msg)) => msg, - _ => return None, - }; - - match msg { - bidirectional::BidirectionalMessage::SubResponse( + match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, start, end }) { + Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, - ) => text, + )) => text, _ => None, } } fn local_file(&mut self, file_id: u32) -> Option { - let req = bidirectional::BidirectionalMessage::SubRequest( - bidirectional::SubRequest::LocalFileName { file_id }, - ); - - if req.write::<_, C>(&mut self.stdout.lock()).is_err() { - return Some(String::new()); - } - - let msg = match bidirectional::BidirectionalMessage::read::<_, C>( - &mut self.stdin.lock(), - self.buf, - ) { - Ok(msg) => msg, - _ => return None, - }; - - match msg { + match self.roundtrip(bidirectional::SubRequest::LocalFileName { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFileNameResult { name }, - )) => Some(name.unwrap_or_default()), + )) => name, _ => None, } } From cc01b1c3789e628ff2e339e584fd190c051a8c3c Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Wed, 31 Dec 2025 16:09:23 +0100 Subject: [PATCH 061/340] Back into rotation --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 5f637205fa65..09dec7675e7e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -63,7 +63,6 @@ users_on_vacation = [ "Alexendoo", "y21", "blyxyas", - "samueltardieu", ] [assign.owners] From 4ba73c33b8d354724d1d713be177912b1636a67c Mon Sep 17 00:00:00 2001 From: Dushyanth Date: Wed, 31 Dec 2025 21:09:11 +0530 Subject: [PATCH 062/340] test: add regression cases for valtree hashing ICE --- .../printing_valtrees_supports_non_values.rs | 11 ++++++ ...inting_valtrees_supports_non_values.stderr | 38 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs index fbe310f7de4c..484d6f14a82a 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs @@ -25,3 +25,14 @@ fn baz() { } fn main() {} + +fn test_ice_missing_bound() { + foo::<{Option::Some::{0: ::ASSOC}}>(); + //~^ ERROR the trait bound `T: Trait` is not satisfied + //~| ERROR the constant `Option::::Some(_)` is not of type `Foo` +} + +fn test_underscore_inference() { + foo::<{ Option::Some:: { 0: _ } }>(); + //~^ ERROR the constant `Option::::Some(_)` is not of type `Foo` +} diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index 8b2871f2b6d3..b4f03e07b569 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -22,5 +22,41 @@ note: required by a const generic parameter in `foo` LL | fn foo() {} | ^^^^^^^^^^^^ required by this const generic parameter in `foo` -error: aborting due to 2 previous errors +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/printing_valtrees_supports_non_values.rs:30:5 + | +LL | foo::<{Option::Some::{0: ::ASSOC}}>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +help: consider restricting type parameter `T` with trait `Trait` + | +LL | fn test_ice_missing_bound() { + | +++++++ +error: the constant `Option::::Some(_)` is not of type `Foo` + --> $DIR/printing_valtrees_supports_non_values.rs:30:12 + | +LL | foo::<{Option::Some::{0: ::ASSOC}}>(); + | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | +note: required by a const generic parameter in `foo` + --> $DIR/printing_valtrees_supports_non_values.rs:15:8 + | +LL | fn foo() {} + | ^^^^^^^^^^^^ required by this const generic parameter in `foo` + +error: the constant `Option::::Some(_)` is not of type `Foo` + --> $DIR/printing_valtrees_supports_non_values.rs:36:13 + | +LL | foo::<{ Option::Some:: { 0: _ } }>(); + | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | +note: required by a const generic parameter in `foo` + --> $DIR/printing_valtrees_supports_non_values.rs:15:8 + | +LL | fn foo() {} + | ^^^^^^^^^^^^ required by this const generic parameter in `foo` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. From 215768a7347ff7388b271ccc7ed6b19c4921b24e Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Wed, 31 Dec 2025 17:05:41 +0000 Subject: [PATCH 063/340] fix missing_panics_doc in `std::os::fd::owned` https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc --- library/std/src/os/fd/owned.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 846ad37aad22..5ba6c9c1fd14 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -77,7 +77,11 @@ impl BorrowedFd<'_> { /// # Safety /// /// The resource pointed to by `fd` must remain open for the duration of - /// the returned `BorrowedFd`, and it must not have the value `-1`. + /// the returned `BorrowedFd`. + /// + /// # Panics + /// + /// Panics if the raw file descriptor has the value `-1`. #[inline] #[track_caller] #[rustc_const_stable(feature = "io_safety", since = "1.63.0")] @@ -177,6 +181,10 @@ impl FromRawFd for OwnedFd { /// [ownership][io-safety]. The resource must not require any cleanup other than `close`. /// /// [io-safety]: io#io-safety + /// + /// # Panics + /// + /// Panics if the raw file descriptor has the value `-1`. #[inline] #[track_caller] unsafe fn from_raw_fd(fd: RawFd) -> Self { From c2f97d194f837a21f80e3c304c0ebe847649f055 Mon Sep 17 00:00:00 2001 From: mnemonikr <138624285+mnemonikr@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:48:21 -0800 Subject: [PATCH 064/340] Added check for next_multiple_of in manual_div_ceil --- clippy_lints/src/operators/manual_div_ceil.rs | 127 +++++++++++------- clippy_utils/src/sym.rs | 1 + tests/ui/manual_div_ceil.fixed | 29 ++++ tests/ui/manual_div_ceil.rs | 29 ++++ tests/ui/manual_div_ceil.stderr | 20 ++- tests/ui/manual_div_ceil_with_feature.fixed | 29 ++++ tests/ui/manual_div_ceil_with_feature.rs | 29 ++++ tests/ui/manual_div_ceil_with_feature.stderr | 20 ++- 8 files changed, 233 insertions(+), 51 deletions(-) diff --git a/clippy_lints/src/operators/manual_div_ceil.rs b/clippy_lints/src/operators/manual_div_ceil.rs index 98aa47421537..5ed923d719bc 100644 --- a/clippy_lints/src/operators/manual_div_ceil.rs +++ b/clippy_lints/src/operators/manual_div_ceil.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::res::{MaybeDef, MaybeQPath}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -7,7 +8,7 @@ use rustc_data_structures::packed::Pu128; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self}; +use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Spanned; use super::MANUAL_DIV_CEIL; @@ -16,59 +17,84 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, lhs: & let mut applicability = Applicability::MachineApplicable; if op == BinOpKind::Div - && check_int_ty_and_feature(cx, lhs) - && check_int_ty_and_feature(cx, rhs) - && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = lhs.kind + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(lhs)) + && check_int_ty_and_feature(cx, cx.typeck_results().expr_ty(rhs)) && msrv.meets(cx, msrvs::DIV_CEIL) { - // (x + (y - 1)) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - return; - } + match lhs.kind { + ExprKind::Binary(inner_op, inner_lhs, inner_rhs) => { + // (x + (y - 1)) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + return; + } - // ((y - 1) + x) / y - if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Add - && sub_op.node == BinOpKind::Sub - && check_literal(sub_rhs) - && check_eq_expr(cx, sub_lhs, rhs) - { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - return; - } + // ((y - 1) + x) / y + if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Add + && sub_op.node == BinOpKind::Sub + && check_literal(sub_rhs) + && check_eq_expr(cx, sub_lhs, rhs) + { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + return; + } - // (x + y - 1) / y - if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind - && inner_op.node == BinOpKind::Sub - && add_op.node == BinOpKind::Add - && check_literal(inner_rhs) - && check_eq_expr(cx, add_rhs, rhs) - { - build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); - } + // (x + y - 1) / y + if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind + && inner_op.node == BinOpKind::Sub + && add_op.node == BinOpKind::Add + && check_literal(inner_rhs) + && check_eq_expr(cx, add_rhs, rhs) + { + build_suggestion(cx, expr, add_lhs, rhs, &mut applicability); + } - // (x + (Y - 1)) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); - } + // (x + (Y - 1)) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_rhs, rhs) { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } - // ((Y - 1) + x) / Y - if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { - build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); - } + // ((Y - 1) + x) / Y + if inner_op.node == BinOpKind::Add && differ_by_one(inner_lhs, rhs) { + build_suggestion(cx, expr, inner_rhs, rhs, &mut applicability); + } - // (x - (-Y - 1)) / Y - if inner_op.node == BinOpKind::Sub - && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind - && differ_by_one(abs_div_rhs, inner_rhs) - { - build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + // (x - (-Y - 1)) / Y + if inner_op.node == BinOpKind::Sub + && let ExprKind::Unary(UnOp::Neg, abs_div_rhs) = rhs.kind + && differ_by_one(abs_div_rhs, inner_rhs) + { + build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); + } + }, + ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) => { + // x.next_multiple_of(Y) / Y + if method.ident.name == sym::next_multiple_of + && check_int_ty(cx.typeck_results().expr_ty(receiver)) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + ExprKind::Call(callee, [receiver, next_multiple_of_arg]) => { + // int_type::next_multiple_of(x, Y) / Y + if let Some(impl_ty_binder) = callee + .ty_rel_def_if_named(cx, sym::next_multiple_of) + .assoc_fn_parent(cx) + .opt_impl_ty(cx) + && check_int_ty(impl_ty_binder.skip_binder()) + && check_eq_expr(cx, next_multiple_of_arg, rhs) + { + build_suggestion(cx, expr, receiver, rhs, &mut applicability); + } + }, + _ => (), } } } @@ -91,8 +117,11 @@ fn differ_by_one(small_expr: &Expr<'_>, large_expr: &Expr<'_>) -> bool { } } -fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr); +fn check_int_ty(expr_ty: Ty<'_>) -> bool { + matches!(expr_ty.peel_refs().kind(), ty::Int(_) | ty::Uint(_)) +} + +fn check_int_ty_and_feature(cx: &LateContext<'_>, expr_ty: Ty<'_>) -> bool { match expr_ty.peel_refs().kind() { ty::Uint(_) => true, ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings), diff --git a/clippy_utils/src/sym.rs b/clippy_utils/src/sym.rs index 00f4a9c7e586..dd20fe16ce61 100644 --- a/clippy_utils/src/sym.rs +++ b/clippy_utils/src/sym.rs @@ -244,6 +244,7 @@ generate! { next_back, next_if, next_if_eq, + next_multiple_of, next_tuple, nth, ok, diff --git a/tests/ui/manual_div_ceil.fixed b/tests/ui/manual_div_ceil.fixed index cd91be87ec17..8ffd107dd42e 100644 --- a/tests/ui/manual_div_ceil.fixed +++ b/tests/ui/manual_div_ceil.fixed @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = size.div_ceil(*c); //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.rs b/tests/ui/manual_div_ceil.rs index 9899c7d775c2..859fb5a13c44 100644 --- a/tests/ui/manual_div_ceil.rs +++ b/tests/ui/manual_div_ceil.rs @@ -105,3 +105,32 @@ fn issue_15705(size: u64, c: &u64) { let _ = (size + c - 1) / c; //~^ manual_div_ceil } + +struct MyStruct(u32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: u32) -> u32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33u32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = u32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil.stderr b/tests/ui/manual_div_ceil.stderr index 44de3ba99be7..0efc114c7078 100644 --- a/tests/ui/manual_div_ceil.stderr +++ b/tests/ui/manual_div_ceil.stderr @@ -131,5 +131,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (size + c - 1) / c; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `size.div_ceil(*c)` -error: aborting due to 20 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:121:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:123:13 + | +LL | let _ = u32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:127:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 23 previous errors diff --git a/tests/ui/manual_div_ceil_with_feature.fixed b/tests/ui/manual_div_ceil_with_feature.fixed index f55999c5ad08..d77b8bc28986 100644 --- a/tests/ui/manual_div_ceil_with_feature.fixed +++ b/tests/ui/manual_div_ceil_with_feature.fixed @@ -84,3 +84,32 @@ fn issue_13950() { let _ = y.div_ceil(-7); //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + + let y = &x; + let _ = y.div_ceil(8); + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.rs b/tests/ui/manual_div_ceil_with_feature.rs index 8a895f634cb4..5b9a4d9156a7 100644 --- a/tests/ui/manual_div_ceil_with_feature.rs +++ b/tests/ui/manual_div_ceil_with_feature.rs @@ -84,3 +84,32 @@ fn issue_13950() { let _ = (y - 8) / -7; //~^ manual_div_ceil } + +struct MyStruct(i32); +impl MyStruct { + // Method matching name on different type should not trigger lint + fn next_multiple_of(self, y: i32) -> i32 { + self.0.next_multiple_of(y) + } +} + +fn issue_16219() { + let x = 33i32; + + // Lint. + let _ = x.next_multiple_of(8) / 8; + //~^ manual_div_ceil + let _ = i32::next_multiple_of(x, 8) / 8; + //~^ manual_div_ceil + + let y = &x; + let _ = y.next_multiple_of(8) / 8; + //~^ manual_div_ceil + + // No lint. + let _ = x.next_multiple_of(8) / 7; + let _ = x.next_multiple_of(7) / 8; + + let z = MyStruct(x); + let _ = z.next_multiple_of(8) / 8; +} diff --git a/tests/ui/manual_div_ceil_with_feature.stderr b/tests/ui/manual_div_ceil_with_feature.stderr index e1160d962996..c5fa15112a87 100644 --- a/tests/ui/manual_div_ceil_with_feature.stderr +++ b/tests/ui/manual_div_ceil_with_feature.stderr @@ -139,5 +139,23 @@ error: manually reimplementing `div_ceil` LL | let _ = (y - 8) / -7; | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` -error: aborting due to 23 previous errors +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:100:13 + | +LL | let _ = x.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:102:13 + | +LL | let _ = i32::next_multiple_of(x, 8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil_with_feature.rs:106:13 + | +LL | let _ = y.next_multiple_of(8) / 8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(8)` + +error: aborting due to 26 previous errors From b725981fe266f483da0232ec9abcce8fe43331df Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 31 Dec 2025 13:17:55 +0530 Subject: [PATCH 065/340] std: sys: fs: uefi: Implement rename - Using the file_name field in `EFI_FILE_INFO` works for renaming, even when changing directories. - Does not work for cross-device rename, but that is already expected behaviour according to the docs: "This will not work if the new name is on a different mount point." - Also add some helper code for dealing with UefiBox. - Tested using OVMF in qemu. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 48 ++++++++++++++++---- library/std/src/sys/pal/uefi/helpers.rs | 59 ++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 1c65e3e2b155..b38d86afb093 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -385,8 +385,43 @@ pub fn unlink(p: &Path) -> io::Result<()> { } } -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() +/// The implementation mirrors `mv` implementation in UEFI shell: +/// https://github.com/tianocore/edk2/blob/66346d5edeac2a00d3cf2f2f3b5f66d423c07b3e/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c#L455 +/// +/// In a nutshell we do the following: +/// 1. Convert both old and new paths to absolute paths. +/// 2. Check that both lie in the same disk. +/// 3. Construct the target path relative to the current disk root. +/// 4. Set this target path as the file_name in the file_info structure. +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + let old_absolute = crate::path::absolute(old)?; + let new_absolute = crate::path::absolute(new)?; + + let mut old_components = old_absolute.components(); + let mut new_components = new_absolute.components(); + + let Some(old_disk) = old_components.next() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "Old path is not valid")); + }; + let Some(new_disk) = new_components.next() else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "New path is not valid")); + }; + + // Ensure that paths are on the same device. + if old_disk != new_disk { + return Err(io::const_error!(io::ErrorKind::CrossesDevices, "Cannot rename across device")); + } + + // Construct an path relative the current disk root. + let new_relative = + [crate::path::Component::RootDir].into_iter().chain(new_components).collect::(); + + let f = uefi_fs::File::from_path(old, file::MODE_READ | file::MODE_WRITE, 0)?; + let file_info = f.file_info()?; + + let new_info = file_info.with_file_name(new_relative.as_os_str())?; + + f.set_file_info(new_info) } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { @@ -751,12 +786,7 @@ mod uefi_fs { } pub(crate) fn file_name_from_uefi(info: &UefiBox) -> OsString { - let file_name = { - let size = unsafe { (*info.as_ptr()).size }; - let strlen = (size as usize - crate::mem::size_of::>() - 1) / 2; - unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) } - }; - - OsString::from_wide(file_name) + let fname = info.file_name(); + OsString::from_wide(&fname[..fname.len() - 1]) } } diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index d059be010e98..10749b5519d6 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -10,7 +10,7 @@ //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles) use r_efi::efi::{self, Guid}; -use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell}; +use r_efi::protocols::{device_path, device_path_to_text, file, service_binding, shell}; use crate::alloc::Layout; use crate::ffi::{OsStr, OsString}; @@ -787,7 +787,7 @@ impl UefiBox { match NonNull::new(ptr.cast()) { Some(inner) => Ok(Self { inner, size: len }), - None => Err(io::Error::new(io::ErrorKind::OutOfMemory, "Allocation failed")), + None => Err(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed")), } } @@ -814,3 +814,58 @@ impl Drop for UefiBox { unsafe { crate::alloc::dealloc(self.inner.as_ptr().cast(), layout) }; } } + +impl UefiBox { + fn size(&self) -> u64 { + unsafe { (*self.as_ptr()).size } + } + + fn set_size(&mut self, s: u64) { + unsafe { (*self.as_mut_ptr()).size = s } + } + + // Length of string (including NULL), not number of bytes. + fn file_name_len(&self) -> usize { + (self.size() as usize - size_of::>()) / size_of::() + } + + pub(crate) fn file_name(&self) -> &[u16] { + unsafe { + crate::slice::from_raw_parts((*self.as_ptr()).file_name.as_ptr(), self.file_name_len()) + } + } + + fn file_name_mut(&mut self) -> &mut [u16] { + unsafe { + crate::slice::from_raw_parts_mut( + (*self.as_mut_ptr()).file_name.as_mut_ptr(), + self.file_name_len(), + ) + } + } + + pub(crate) fn with_file_name(mut self, name: &OsStr) -> io::Result { + // os_string_to_raw returns NULL terminated string. So no need to handle it separately. + let fname = os_string_to_raw(name) + .ok_or(const_error!(io::ErrorKind::OutOfMemory, "Allocation failed"))?; + let new_size = size_of::>() + fname.len() * size_of::(); + + // Reuse the current structure if the new name can fit in it. + if self.size() >= new_size as u64 { + self.file_name_mut()[..fname.len()].copy_from_slice(&fname); + self.set_size(new_size as u64); + + return Ok(self); + } + + let mut new_box = UefiBox::new(new_size)?; + + unsafe { + crate::ptr::copy_nonoverlapping(self.as_ptr(), new_box.as_mut_ptr(), 1); + } + new_box.set_size(new_size as u64); + new_box.file_name_mut().copy_from_slice(&fname); + + Ok(new_box) + } +} From f89cce3acb5106b98f6ada765677dc11e41518a0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 17 Dec 2025 14:33:10 +0100 Subject: [PATCH 066/340] `c_variadic`: provide `va_arg` for more targets --- compiler/rustc_codegen_llvm/src/va_arg.rs | 106 +++++++++++++++++----- 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index b23415a732cc..688f461e7478 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,12 +1,13 @@ -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size, TyAndLayout}; +use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, LayoutTypeCodegenMethods, }; +use rustc_middle::bug; use rustc_middle::ty::Ty; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_target::spec::{Abi, Arch, Env}; use crate::builder::Builder; @@ -82,6 +83,7 @@ enum PassMode { enum SlotSize { Bytes8 = 8, Bytes4 = 4, + Bytes1 = 1, } enum AllowHigherAlign { @@ -728,7 +730,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, reg_addr: &'ll Value, - layout: TyAndLayout<'tcx, Ty<'tcx>>, + layout: TyAndLayout<'tcx>, src_align: Align, ) -> &'ll Value { if layout.layout.align.abi > src_align { @@ -751,7 +753,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>( fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, va_list_addr: &'ll Value, - layout: TyAndLayout<'tcx, Ty<'tcx>>, + layout: TyAndLayout<'tcx>, ) -> &'ll Value { let dl = bx.cx.data_layout(); let ptr_align_abi = dl.data_layout().pointer_align().abi; @@ -1003,15 +1005,17 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( return bx.load(layout.llvm_type(bx), value_ptr, layout.align.abi); } +/// Determine the va_arg implementation to use. The LLVM va_arg instruction +/// is lacking in some instances, so we should only use it as a fallback. pub(super) fn emit_va_arg<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, addr: OperandRef<'tcx, &'ll Value>, target_ty: Ty<'tcx>, ) -> &'ll Value { - // Determine the va_arg implementation to use. The LLVM va_arg instruction - // is lacking in some instances, so we should only use it as a fallback. - let target = &bx.cx.tcx.sess.target; + let layout = bx.cx.layout_of(target_ty); + let target_ty_size = layout.layout.size().bytes(); + let target = &bx.cx.tcx.sess.target; match target.arch { Arch::X86 => emit_ptr_va_arg( bx, @@ -1069,23 +1073,79 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( AllowHigherAlign::Yes, ForceRightAdjust::No, ), + Arch::LoongArch32 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 2 * 4 { PassMode::Indirect } else { PassMode::Direct }, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::LoongArch64 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 2 * 8 { PassMode::Indirect } else { PassMode::Direct }, + SlotSize::Bytes8, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::AmdGpu => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes4, + AllowHigherAlign::No, + ForceRightAdjust::No, + ), + Arch::Nvptx64 => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes1, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::Wasm32 => emit_ptr_va_arg( + bx, + addr, + target_ty, + if layout.is_aggregate() || layout.is_zst() || layout.is_1zst() { + PassMode::Indirect + } else { + PassMode::Direct + }, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), + Arch::Wasm64 => bug!("c-variadic functions are not fully implemented for wasm64"), + Arch::CSky => emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ), // Windows x86_64 - Arch::X86_64 if target.is_like_windows => { - let target_ty_size = bx.cx.size_of(target_ty).bytes(); - emit_ptr_va_arg( - bx, - addr, - target_ty, - if target_ty_size > 8 || !target_ty_size.is_power_of_two() { - PassMode::Indirect - } else { - PassMode::Direct - }, - SlotSize::Bytes8, - AllowHigherAlign::No, - ForceRightAdjust::No, - ) - } + Arch::X86_64 if target.is_like_windows => emit_ptr_va_arg( + bx, + addr, + target_ty, + if target_ty_size > 8 || !target_ty_size.is_power_of_two() { + PassMode::Indirect + } else { + PassMode::Direct + }, + SlotSize::Bytes8, + AllowHigherAlign::No, + ForceRightAdjust::No, + ), // This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64. Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty), Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty), From a390881bde042f39c12001044c7476545abcb390 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 1 Jan 2026 14:46:16 +0100 Subject: [PATCH 067/340] Do not make suggestion machine-applicable if it may change semantics When suggesting to replace an iterator method by `.all()` or `.any()`, make the suggestion at most `MaybeIncorrect` instead of `MachineApplicable` and warn about the fact that semantics may change because those two methods are short-circuiting. --- clippy_lints/src/methods/unnecessary_fold.rs | 108 ++++++++++++------- tests/ui/unnecessary_fold.stderr | 7 ++ 2 files changed, 77 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 9dae6fbb48dd..7802763ef74a 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,10 +1,10 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_hir::def::{DefKind, Res}; @@ -59,6 +59,34 @@ struct Replacement { method_name: &'static str, has_args: bool, has_generic_return: bool, + is_short_circuiting: bool, +} + +impl Replacement { + fn default_applicability(&self) -> Applicability { + if self.is_short_circuiting { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + } + } + + fn maybe_add_note(&self, diag: &mut Diag<'_, ()>) { + if self.is_short_circuiting { + diag.note(format!( + "the `{}` method is short circuiting and may change the program semantics if the iterator has side effects", + self.method_name + )); + } + } + + fn maybe_turbofish(&self, ty: Ty<'_>) -> String { + if self.has_generic_return { + format!("::<{ty}>") + } else { + String::new() + } + } } fn check_fold_with_op( @@ -86,32 +114,29 @@ fn check_fold_with_op( && left_expr.res_local_id() == Some(first_arg_id) && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id)) { - let mut applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) - } else { - String::new() - }; - - let sugg = if replacement.has_args { - format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", - method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!("{method}{turbofish}()", method = replacement.method_name) - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, + |diag| { + let mut applicability = replacement.default_applicability(); + let turbofish = + replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!("{method}{turbofish}()", method = replacement.method_name) + }; + + diag.span_suggestion(span, "try", sugg, applicability); + replacement.maybe_add_note(diag); + }, ); return true; } @@ -131,22 +156,25 @@ fn check_fold_with_method( // Check if the function belongs to the operator && cx.tcx.is_diagnostic_item(method, fn_did) { - let applicability = Applicability::MachineApplicable; - - let turbofish = if replacement.has_generic_return { - format!("::<{}>", cx.typeck_results().expr_ty(expr)) - } else { - String::new() - }; - - span_lint_and_sugg( + let span = fold_span.with_hi(expr.span.hi()); + span_lint_and_then( cx, UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), + span, "this `.fold` can be written more succinctly using another method", - "try", - format!("{method}{turbofish}()", method = replacement.method_name), - applicability, + |diag| { + diag.span_suggestion( + span, + "try", + format!( + "{method}{turbofish}()", + method = replacement.method_name, + turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty(expr)) + ), + replacement.default_applicability(), + ); + replacement.maybe_add_note(diag); + }, ); } } @@ -171,6 +199,7 @@ pub(super) fn check<'tcx>( method_name: "any", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, replacement); }, @@ -179,6 +208,7 @@ pub(super) fn check<'tcx>( method_name: "all", has_args: true, has_generic_return: false, + is_short_circuiting: true, }; check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, replacement); }, @@ -187,6 +217,7 @@ pub(super) fn check<'tcx>( method_name: "sum", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::add, replacement); @@ -197,6 +228,7 @@ pub(super) fn check<'tcx>( method_name: "product", has_args: false, has_generic_return: needs_turbofish(cx, expr), + is_short_circuiting: false, }; if !check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, replacement) { check_fold_with_method(cx, expr, acc, fold_span, sym::mul, replacement); diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index bb8aa7e18d34..025a2bd0048b 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -4,6 +4,7 @@ error: this `.fold` can be written more succinctly using another method LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects = note: `-D clippy::unnecessary-fold` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` @@ -21,6 +22,8 @@ error: this `.fold` can be written more succinctly using another method | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` + | + = note: the `all` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:24:25 @@ -63,12 +66,16 @@ error: this `.fold` can be written more succinctly using another method | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:110:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method --> tests/ui/unnecessary_fold.rs:123:33 From cde301fabc81b25b6ef54268139d93721448b118 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 19:20:42 +0000 Subject: [PATCH 068/340] Bump qs from 6.14.0 to 6.14.1 in /editors/code Bumps [qs](https://github.com/ljharb/qs) from 6.14.0 to 6.14.1. - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.14.0...v6.14.1) --- updated-dependencies: - dependency-name: qs dependency-version: 6.14.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/tools/rust-analyzer/editors/code/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 00d83e906848..57f6bf69beb0 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -5584,9 +5584,9 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { From 48657cec85a38c0f1fade3eaf905b19bf23d356f Mon Sep 17 00:00:00 2001 From: Aliaksei Semianiuk Date: Fri, 2 Jan 2026 01:59:16 +0500 Subject: [PATCH 069/340] Update year --- COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 2 +- clippy_utils/README.md | 2 +- rustc_tools_util/README.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index f402dcf465a3..5d3075903a01 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 9990a0cec474..6f6e5844208d 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 5d6e36ef6bfc..a51639bc0f9b 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2025 The Rust Project Developers +Copyright (c) 2014-2026 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 78498c73ae78..287dee82daaa 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/clippy_utils/README.md b/clippy_utils/README.md index 01257c1a3059..e3ce95d30074 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index f47a4c69c2c3..083814e1e05d 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under: -Copyright 2014-2025 The Rust Project Developers +Copyright 2014-2026 The Rust Project Developers Licensed under the Apache License, Version 2.0 or the MIT license From 68ea14a27283bc5e55acbf81ae9dbe6a05506e79 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Thu, 1 Jan 2026 22:07:57 +0000 Subject: [PATCH 070/340] address review --- src/tools/tidy/src/extra_checks/mod.rs | 37 ++++++++++++-------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index bedcd08ca13f..2d654339e883 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -121,9 +121,7 @@ fn check_impl( ck.is_non_auto_or_matches(path) }); } - if lint_args.iter().any(|ck| ck.if_installed) { - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); - } + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -597,29 +595,26 @@ fn install_requirements( Ok(()) } +/// Returns `Ok` if shellcheck is installed, `Err` otherwise. fn has_shellcheck() -> Result<(), Error> { match Command::new("shellcheck").arg("--version").status() { Ok(_) => Ok(()), - Err(e) if e.kind() == io::ErrorKind::NotFound => { - return Err(Error::MissingReq( - "shellcheck", - "shell file checks", - Some( - "see \ - for installation instructions" - .to_owned(), - ), - )); - } - Err(e) => return Err(e.into()), + Err(e) if e.kind() == io::ErrorKind::NotFound => Err(Error::MissingReq( + "shellcheck", + "shell file checks", + Some( + "see \ + for installation instructions" + .to_owned(), + ), + )), + Err(e) => Err(e.into()), } } /// Check that shellcheck is installed then run it at the given path fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { - if let Err(err) = has_shellcheck() { - return Err(err); - } + has_shellcheck()?; let status = Command::new("shellcheck").args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } @@ -758,6 +753,7 @@ enum ExtraCheckParseError { } struct ExtraCheckArg { + /// Only run the check if files to check have been modified. auto: bool, /// Only run the check if the requisite software is already installed. if_installed: bool, @@ -798,8 +794,7 @@ impl ExtraCheckArg { && rustdoc_js::has_tool(build_dir, "es-check") && rustdoc_js::has_tool(build_dir, "tsc") } - // Unreachable. - Some(_) => false, + Some(_) => unreachable!("js shouldn't have other type of ExtraCheckKind"), } } ExtraCheckLang::Py | ExtraCheckLang::Cpp => { @@ -862,6 +857,8 @@ impl FromStr for ExtraCheckArg { let Some(mut first) = parts.next() else { return Err(ExtraCheckParseError::Empty); }; + // The loop allows users to specify `auto` and `if-installed` in any order. + // Both auto:if-installed: and if-installed:auto: are valid. loop { if !auto && first == "auto" { let Some(part) = parts.next() else { From 8ca47cd1fe50eb4d160d1ab801f159312a35c54a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Jan 2026 09:29:26 +1100 Subject: [PATCH 071/340] Clarify `MoveData::init_loc_map`. Change the `SmallVec` size from 4 to 1, because that's sufficient in the vast majority of cases. (This doesn't affect performance in practice, so it's more of a code clarity change than a performance change.) --- compiler/rustc_mir_dataflow/src/move_paths/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 800d4e406cf0..8be7d210f8df 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -177,8 +177,9 @@ pub struct MoveData<'tcx> { pub rev_lookup: MovePathLookup<'tcx>, pub inits: IndexVec, /// Each Location `l` is mapped to the Inits that are effects - /// of executing the code at `l`. - pub init_loc_map: LocationMap>, + /// of executing the code at `l`. Only very rarely (e.g. inline asm) + /// is there more than one Init at any `l`. + pub init_loc_map: LocationMap>, pub init_path_map: IndexVec>, } From 6394373dccc7b4bc49617b03bd505ea0f75a57a7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 2 Jan 2026 05:44:43 +0530 Subject: [PATCH 072/340] add nits --- src/tools/rust-analyzer/crates/load-cargo/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 dc75abe7ad8c..5aa96582e9f3 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -547,10 +547,8 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) - .and_then(|path| path.clone().into_abs_path()) - .and_then(|path| { - path.as_path().file_name().map(|filename| filename.to_owned()) - }); + .and_then(|path| path.as_path()) + .and_then(|path| path.file_name().map(|filename| filename.to_owned())); Ok(SubResponse::LocalFileNameResult { name }) } From 3982d3e70648ce3769d40610d86e330e4456b0ce Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 19 Oct 2025 23:52:19 +0000 Subject: [PATCH 073/340] `Vec::push` in consts MVP --- library/alloc/src/alloc.rs | 259 ++++++++++++++---- library/alloc/src/collections/mod.rs | 23 +- library/alloc/src/lib.rs | 6 + library/alloc/src/raw_vec/mod.rs | 81 ++++-- library/alloc/src/vec/mod.rs | 33 ++- library/alloctests/lib.rs | 7 + library/alloctests/tests/lib.rs | 1 + library/alloctests/tests/vec.rs | 16 ++ library/core/src/alloc/mod.rs | 7 +- .../const-eval/heap/vec-not-made-global.rs | 5 + .../heap/vec-not-made-global.stderr | 10 + 11 files changed, 361 insertions(+), 87 deletions(-) create mode 100644 tests/ui/consts/const-eval/heap/vec-not-made-global.rs create mode 100644 tests/ui/consts/const-eval/heap/vec-not-made-global.stderr diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index c5f16f3708d7..ee40596c620f 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,8 +5,8 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -use core::hint; use core::ptr::{self, NonNull}; +use core::{cmp, hint}; unsafe extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates @@ -182,7 +182,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { impl Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -194,10 +194,26 @@ impl Global { } } + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn deallocate_impl_runtime(ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: + // * We have checked that `layout` is non-zero in size. + // * The caller is obligated to provide a layout that "fits", and in this case, + // "fit" always means a layout that is equal to the original, because our + // `allocate()`, `grow()`, and `shrink()` implementations never returns a larger + // allocation than requested. + // * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s + // safety documentation. + unsafe { dealloc(ptr.as_ptr(), layout) } + } + } + // SAFETY: Same as `Allocator::grow` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow_impl( + fn grow_impl_runtime( &self, ptr: NonNull, old_layout: Layout, @@ -241,69 +257,16 @@ impl Global { }, } } -} -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for Global { + // SAFETY: Same as `Allocator::grow` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, false) - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, true) - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - if layout.size() != 0 { - // SAFETY: - // * We have checked that `layout` is non-zero in size. - // * The caller is obligated to provide a layout that "fits", and in this case, - // "fit" always means a layout that is equal to the original, because our - // `allocate()`, `grow()`, and `shrink()` implementations never returns a larger - // allocation than requested. - // * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s - // safety documentation. - unsafe { dealloc(ptr.as_ptr(), layout) } - } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn grow_zeroed( - &self, - ptr: NonNull, - old_layout: Layout, - new_layout: Layout, - ) -> Result, AllocError> { - // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } - } - - #[inline] - #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - unsafe fn shrink( + fn shrink_impl_runtime( &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, + _zeroed: bool, ) -> Result, AllocError> { debug_assert!( new_layout.size() <= old_layout.size(), @@ -340,6 +303,184 @@ unsafe impl Allocator for Global { }, } } + + // SAFETY: Same as `Allocator::allocate` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (layout, zeroed), + Global::alloc_impl_const, + Global::alloc_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::deallocate` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn deallocate_impl(&self, ptr: NonNull, layout: Layout) { + core::intrinsics::const_eval_select( + (ptr, layout), + Global::deallocate_impl_const, + Global::deallocate_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::grow` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_impl( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, + ) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (self, ptr, old_layout, new_layout, zeroed), + Global::grow_shrink_impl_const, + Global::grow_impl_runtime, + ) + } + + // SAFETY: Same as `Allocator::shrink` + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn shrink_impl( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + core::intrinsics::const_eval_select( + (self, ptr, old_layout, new_layout, false), + Global::grow_shrink_impl_const, + Global::shrink_impl_runtime, + ) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result, AllocError> { + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), + // SAFETY: `layout` is non-zero in size, + size => unsafe { + let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + if zeroed { + let mut offset = 0; + while offset < size { + offset += 1; + // SAFETY: the pointer returned by `const_allocate` is valid to write to. + ptr.add(offset).write(0) + } + } + Ok(NonNull::slice_from_raw_parts(ptr, size)) + }, + } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn deallocate_impl_const(ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: We checked for nonzero size; other preconditions must be upheld by caller. + unsafe { + core::intrinsics::const_deallocate(ptr.as_ptr(), layout.size(), layout.align()); + } + } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn grow_shrink_impl_const( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + zeroed: bool, + ) -> Result, AllocError> { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + // SAFETY: both pointers are valid and this operations is in bounds. + unsafe { + ptr::copy_nonoverlapping( + ptr.as_ptr(), + new_ptr.as_mut_ptr(), + cmp::min(old_layout.size(), new_layout.size()), + ); + } + unsafe { + self.deallocate_impl(ptr, old_layout); + } + Ok(new_ptr) + } +} + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +unsafe impl const Allocator for Global { + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, false) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, true) + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.deallocate_impl(ptr, layout) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } + } + + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + // SAFETY: all conditions must be upheld by the caller + unsafe { self.shrink_impl(ptr, old_layout, new_layout) } + } } /// The allocator for `Box`. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 212d7c8465b6..e09326759fd1 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -84,13 +84,14 @@ impl TryReserveError { reason = "Uncertain how much info should be exposed", issue = "48043" )] - pub fn kind(&self) -> TryReserveErrorKind { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn kind(&self) -> TryReserveErrorKind { self.kind.clone() } } /// Details of the allocation that caused a `TryReserveError` -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug)] #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", @@ -120,6 +121,24 @@ pub enum TryReserveErrorKind { }, } +#[unstable( + feature = "try_reserve_kind", + reason = "Uncertain how much info should be exposed", + issue = "48043" +)] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[cfg(not(test))] +impl const Clone for TryReserveErrorKind { + fn clone(&self) -> Self { + match self { + TryReserveErrorKind::CapacityOverflow => TryReserveErrorKind::CapacityOverflow, + TryReserveErrorKind::AllocError { layout, non_exhaustive: () } => { + TryReserveErrorKind::AllocError { layout: *layout, non_exhaustive: () } + } + } + } +} + #[cfg(test)] pub use realalloc::collections::TryReserveErrorKind; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b659e904c8a0..1aee92424602 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,11 +101,16 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(const_clone)] +#![feature(const_cmp)] #![feature(const_convert)] #![feature(const_default)] +#![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_heap)] #![feature(copied_into_inner)] +#![feature(const_option_ops)] +#![feature(const_try)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] @@ -171,6 +176,7 @@ #![feature(const_trait_impl)] #![feature(coroutine_trait)] #![feature(decl_macro)] +#![feature(derive_const)] #![feature(dropck_eyepatch)] #![feature(fundamental)] #![feature(hashmap_internals)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 15b0823df9ec..4994f01047d0 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -4,7 +4,7 @@ // Note: This module is also included in the alloctests crate using #[path] to // run the tests. See the comment there for an explanation why this is the case. -use core::marker::PhantomData; +use core::marker::{Destruct, PhantomData}; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ptr::{self, Alignment, NonNull, Unique}; use core::{cmp, hint}; @@ -24,7 +24,7 @@ mod tests; // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] #[cfg_attr(not(panic = "immediate-abort"), inline(never))] -fn capacity_overflow() -> ! { +const fn capacity_overflow() -> ! { panic!("capacity overflow"); } @@ -182,7 +182,11 @@ impl RawVec { /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) const fn with_capacity_in(capacity: usize, alloc: A) -> Self + where + A: [const] Allocator + [const] Destruct, + { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -331,7 +335,11 @@ impl RawVec { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] - pub(crate) fn grow_one(&mut self) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) const fn grow_one(&mut self) + where + A: [const] Allocator, + { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.grow_one(T::LAYOUT) } } @@ -415,7 +423,11 @@ impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] - fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self + where + A: [const] Allocator + [const] Destruct, + { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { unsafe { @@ -446,12 +458,16 @@ impl RawVecInner { } } - fn try_allocate_in( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, - ) -> Result { + ) -> Result + where + A: [const] Allocator + [const] Destruct, + { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match layout_array(capacity, elem_layout) { @@ -519,7 +535,8 @@ impl RawVecInner { /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment #[inline] - unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn current_memory(&self, elem_layout: Layout) -> Option<(NonNull, Layout)> { if elem_layout.size() == 0 || self.cap.as_inner() == 0 { None } else { @@ -572,7 +589,11 @@ impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - unsafe fn grow_one(&mut self, elem_layout: Layout) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_one(&mut self, elem_layout: Layout) + where + A: [const] Allocator, + { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { handle_error(err); @@ -651,12 +672,13 @@ impl RawVecInner { } #[inline] - fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { + const fn needs_to_grow(&self, len: usize, additional: usize, elem_layout: Layout) -> bool { additional > self.capacity(elem_layout.size()).wrapping_sub(len) } #[inline] - unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { // Allocators currently return a `NonNull<[u8]>` whose length matches // the size requested. If that ever changes, the capacity here should // change to `ptr.len() / size_of::()`. @@ -669,12 +691,16 @@ impl RawVecInner { /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment /// - The sum of `len` and `additional` must be greater than the current capacity - unsafe fn grow_amortized( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn grow_amortized( &mut self, len: usize, additional: usize, elem_layout: Layout, - ) -> Result<(), TryReserveError> { + ) -> Result<(), TryReserveError> + where + A: [const] Allocator, + { // This is ensured by the calling contexts. debug_assert!(additional > 0); @@ -737,15 +763,20 @@ impl RawVecInner { // not marked inline(never) since we want optimizers to be able to observe the specifics of this // function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] - unsafe fn finish_grow( + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + const unsafe fn finish_grow( &self, cap: usize, elem_layout: Layout, - ) -> Result, TryReserveError> { + ) -> Result, TryReserveError> + where + A: [const] Allocator, + { let new_layout = layout_array(cap, elem_layout)?; let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { - debug_assert_eq!(old_layout.align(), new_layout.align()); + // FIXME(const-hack): switch to `debug_assert_eq` + debug_assert!(old_layout.align() == new_layout.align()); unsafe { // The allocator checks for alignment equality hint::assert_unchecked(old_layout.align() == new_layout.align()); @@ -755,7 +786,11 @@ impl RawVecInner { self.alloc.allocate(new_layout) }; - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) + // FIXME(const-hack): switch back to `map_err` + match memory { + Ok(memory) => Ok(memory), + Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), + } } /// # Safety @@ -839,7 +874,8 @@ impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] -fn handle_error(e: TryReserveError) -> ! { +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const fn handle_error(e: TryReserveError) -> ! { match e.kind() { CapacityOverflow => capacity_overflow(), AllocError { layout, .. } => handle_alloc_error(layout), @@ -847,6 +883,11 @@ fn handle_error(e: TryReserveError) -> ! { } #[inline] -fn layout_array(cap: usize, elem_layout: Layout) -> Result { - elem_layout.repeat(cap).map(|(layout, _pad)| layout).map_err(|_| CapacityOverflow.into()) +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +const fn layout_array(cap: usize, elem_layout: Layout) -> Result { + // FIXME(const-hack) return to using `map` and `map_err` once `const_closures` is implemented + match elem_layout.repeat(cap) { + Ok((layout, _pad)) => Ok(layout), + Err(_) => Err(CapacityOverflow.into()), + } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f8a96e358d6d..10a34d17730f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -81,6 +81,8 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; +#[cfg(not(no_global_oom_handling))] +use core::marker::Destruct; use core::marker::PhantomData; use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; @@ -519,7 +521,8 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] #[rustc_diagnostic_item = "vec_with_capacity"] - pub fn with_capacity(capacity: usize) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) } @@ -881,6 +884,16 @@ impl Vec { // SAFETY: A `Vec` always has a non-null pointer. (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) } + + /// Leaks the `Vec` to be interned statically. This mut be done for all + /// `Vec` created during compile time. + #[unstable(feature = "const_heap", issue = "79597")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn const_leak(mut self) -> &'static [T] { + unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; + let me = ManuallyDrop::new(self); + unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } + } } impl Vec { @@ -962,7 +975,11 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn with_capacity_in(capacity: usize, alloc: A) -> Self + where + A: [const] Allocator + [const] Destruct, + { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } @@ -2575,7 +2592,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] - pub fn push(&mut self, value: T) { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn push(&mut self, value: T) + where + A: [const] Allocator, + { let _ = self.push_mut(value); } @@ -2664,7 +2685,11 @@ impl Vec { #[inline] #[unstable(feature = "push_mut", issue = "135974")] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - pub fn push_mut(&mut self, value: T) -> &mut T { + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub const fn push_mut(&mut self, value: T) -> &mut T + where + A: [const] Allocator, + { // Inform codegen that the length does not change across grow_one(). let len = self.len; // This will panic or abort if we would allocate > isize::MAX bytes diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index cd02c0a53857..b85fc8eb9970 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -20,6 +20,13 @@ #![feature(assert_matches)] #![feature(box_vec_non_null)] #![feature(char_internals)] +#![feature(const_alloc_error)] +#![feature(const_cmp)] +#![feature(const_convert)] +#![feature(const_destruct)] +#![feature(const_heap)] +#![feature(const_option_ops)] +#![feature(const_try)] #![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(exact_size_is_empty)] diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 34c65bf787c8..db01cebe5b27 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(allocator_api)] #![feature(alloc_layout_extra)] +#![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] #![feature(assert_matches)] diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index cd5b14f6eff3..a7997cd060d3 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2749,3 +2749,19 @@ fn zst_collections_iter_nth_back_regression() { list.push_back(Thing); let _ = list.into_iter().nth_back(1); } + +#[test] +fn const_heap() { + const X: &'static [u32] = { + let mut v = Vec::with_capacity(6); + let mut x = 1; + while x < 42 { + v.push(x); + x *= 2; + } + assert!(v.len() == 6); + v.const_leak() + }; + + assert_eq!([1, 2, 4, 8, 16, 32], X); +} diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 680b1ec105a2..ef1abcaf639a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -102,6 +102,8 @@ impl fmt::Display for AllocError { /// /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[const_trait] pub unsafe trait Allocator { /// Attempts to allocate a block of memory. /// @@ -368,9 +370,10 @@ pub unsafe trait Allocator { } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl Allocator for &A +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +unsafe impl const Allocator for &A where - A: Allocator + ?Sized, + A: [const] Allocator + ?Sized, { #[inline] fn allocate(&self, layout: Layout) -> Result, AllocError> { diff --git a/tests/ui/consts/const-eval/heap/vec-not-made-global.rs b/tests/ui/consts/const-eval/heap/vec-not-made-global.rs new file mode 100644 index 000000000000..4f78e977e4d5 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/vec-not-made-global.rs @@ -0,0 +1,5 @@ +#![feature(const_heap)] +const V: Vec = Vec::with_capacity(1); +//~^ ERROR: encountered `const_allocate` pointer in final value that was not made global + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr b/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr new file mode 100644 index 000000000000..595cbeb8df26 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/vec-not-made-global.stderr @@ -0,0 +1,10 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/vec-not-made-global.rs:2:1 + | +LL | const V: Vec = Vec::with_capacity(1); + | ^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning + +error: aborting due to 1 previous error + From 47864e80cb4b873c1c3090be9923bfdf90148962 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 26 Oct 2025 18:42:13 +0000 Subject: [PATCH 074/340] address review comments; fix CI --- library/alloc/src/alloc.rs | 8 ++--- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 14 +++++--- library/alloctests/tests/vec.rs | 2 +- .../item-collection/opaque-return-impls.rs | 2 +- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 26 ++++++++------ ...ce.PreCodegen.after.64bit.panic-unwind.mir | 26 ++++++++------ ..._constant.main.GVN.32bit.panic-unwind.diff | 36 +++++++++---------- ..._constant.main.GVN.64bit.panic-unwind.diff | 36 +++++++++---------- 9 files changed, 77 insertions(+), 74 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index ee40596c620f..5dd828bd54e1 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -374,12 +374,8 @@ impl Global { let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align()); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { - let mut offset = 0; - while offset < size { - offset += 1; - // SAFETY: the pointer returned by `const_allocate` is valid to write to. - ptr.add(offset).write(0) - } + // SAFETY: the pointer returned by `const_allocate` is valid to write to. + ptr.write_bytes(0, size); } Ok(NonNull::slice_from_raw_parts(ptr, size)) }, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1aee92424602..f15dfc9b5de7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -124,6 +124,7 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(formatting_options)] +#![feature(freeze)] #![feature(generic_atomic)] #![feature(hasher_prefixfree_extras)] #![feature(inplace_iteration)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 10a34d17730f..29e83113d489 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -83,7 +83,7 @@ use core::hash::{Hash, Hasher}; use core::iter; #[cfg(not(no_global_oom_handling))] use core::marker::Destruct; -use core::marker::PhantomData; +use core::marker::{Freeze, PhantomData}; use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, TransmuteFrom}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; @@ -885,11 +885,17 @@ impl Vec { (unsafe { NonNull::new_unchecked(ptr) }, len, capacity) } - /// Leaks the `Vec` to be interned statically. This mut be done for all - /// `Vec` created during compile time. + /// Interns the `Vec`, making the underlying memory read-only. This method should be + /// called during compile time. (This is a no-op if called during runtime) + /// + /// This method must be called if the memory used by `Vec` needs to appear in the final + /// values of constants. #[unstable(feature = "const_heap", issue = "79597")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn const_leak(mut self) -> &'static [T] { + pub const fn const_make_global(mut self) -> &'static [T] + where + T: Freeze, + { unsafe { core::intrinsics::const_make_global(self.as_mut_ptr().cast()) }; let me = ManuallyDrop::new(self); unsafe { slice::from_raw_parts(me.as_ptr(), me.len) } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index a7997cd060d3..c8f9504ae14e 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -2760,7 +2760,7 @@ fn const_heap() { x *= 2; } assert!(v.len() == 6); - v.const_leak() + v.const_make_global() }; assert_eq!([1, 2, 4, 8, 16, 32], X); diff --git a/tests/codegen-units/item-collection/opaque-return-impls.rs b/tests/codegen-units/item-collection/opaque-return-impls.rs index d54951b933fd..54ab656c53db 100644 --- a/tests/codegen-units/item-collection/opaque-return-impls.rs +++ b/tests/codegen-units/item-collection/opaque-return-impls.rs @@ -44,7 +44,7 @@ pub fn foo2() -> Box { //~ MONO_ITEM fn ::test_func2 //~ MONO_ITEM fn alloc::alloc::exchange_malloc //~ MONO_ITEM fn foo2 -//~ MONO_ITEM fn std::alloc::Global::alloc_impl +//~ MONO_ITEM fn std::alloc::Global::alloc_impl_runtime //~ 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 diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 15a9d9e39c49..485ff902a7b9 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -9,22 +9,22 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { + scope 6 (inlined std::alloc::Global::alloc_impl) { + } } - scope 6 (inlined NonNull::<[u8]>::as_ptr) { + scope 7 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -35,10 +35,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; } @@ -59,30 +59,26 @@ } bb3: { - _11 = option::unwrap_failed() -> unwind continue; + _9 = option::unwrap_failed() -> unwind continue; } bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb5, unwind continue]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index df008ececae3..beee899dafe6 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -9,22 +9,22 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { + scope 6 (inlined std::alloc::Global::alloc_impl) { + } } - scope 6 (inlined NonNull::<[u8]>::as_ptr) { + scope 7 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -35,10 +35,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb3, 1: bb4, otherwise: bb2]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb3, 1: bb4, otherwise: bb2]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb3, 1: bb4, otherwise: bb2]; } @@ -59,30 +59,26 @@ } bb3: { - _11 = option::unwrap_failed() -> unwind continue; + _9 = option::unwrap_failed() -> unwind continue; } bb4: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb5, unwind continue]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb5, unwind continue]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_8); StorageDead(_7); _5 = Result::, std::alloc::AllocError>::unwrap(move _6) -> [return: bb1, unwind continue]; } From cf61cbcb07a000ab0303baa601ea5a21f35bccda Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 21 Nov 2025 23:01:26 +0000 Subject: [PATCH 075/340] Move into `const impl` blocks --- library/alloc/src/raw_vec/mod.rs | 306 +++++++++++++++---------------- library/alloc/src/vec/mod.rs | 215 +++++++++++----------- library/core/src/alloc/mod.rs | 3 +- 3 files changed, 255 insertions(+), 269 deletions(-) diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index 4994f01047d0..c92deb06903d 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -165,6 +165,32 @@ const fn min_non_zero_cap(size: usize) -> usize { } } +const impl RawVec { + /// Like `with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self + { + Self { + inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), + _marker: PhantomData, + } + } + + /// A specialized version of `self.reserve(len, 1)` which requires the + /// caller to ensure `len == self.capacity()`. + #[cfg(not(no_global_oom_handling))] + #[inline(never)] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub(crate) fn grow_one(&mut self) + { + // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout + unsafe { self.inner.grow_one(T::LAYOUT) } + } +} + impl RawVec { #[cfg(not(no_global_oom_handling))] pub(crate) const MIN_NON_ZERO_CAP: usize = min_non_zero_cap(size_of::()); @@ -178,21 +204,6 @@ impl RawVec { Self { inner: RawVecInner::new_in(alloc, Alignment::of::()), _marker: PhantomData } } - /// Like `with_capacity`, but parameterized over the choice of - /// allocator for the returned `RawVec`. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) const fn with_capacity_in(capacity: usize, alloc: A) -> Self - where - A: [const] Allocator + [const] Destruct, - { - Self { - inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), - _marker: PhantomData, - } - } - /// Like `try_with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] @@ -331,19 +342,6 @@ impl RawVec { unsafe { self.inner.reserve(len, additional, T::LAYOUT) } } - /// A specialized version of `self.reserve(len, 1)` which requires the - /// caller to ensure `len == self.capacity()`. - #[cfg(not(no_global_oom_handling))] - #[inline(never)] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) const fn grow_one(&mut self) - where - A: [const] Allocator, - { - // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout - unsafe { self.inner.grow_one(T::LAYOUT) } - } - /// The same as `reserve`, but returns on errors instead of panicking or aborting. pub(crate) fn try_reserve( &mut self, @@ -413,20 +411,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { } } -impl RawVecInner { - #[inline] - const fn new_in(alloc: A, align: Alignment) -> Self { - let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); - // `cap: 0` means "unallocated". zero-sized types are ignored. - Self { ptr, cap: ZERO_CAP, alloc } - } - +const impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self - where - A: [const] Allocator + [const] Destruct, + fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { @@ -439,34 +428,13 @@ impl RawVecInner { Err(err) => handle_error(err), } } - - #[inline] - fn try_with_capacity_in( - capacity: usize, - alloc: A, - elem_layout: Layout, - ) -> Result { - Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) - } - - #[cfg(not(no_global_oom_handling))] - #[inline] - fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { - match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { - Ok(res) => res, - Err(err) => handle_error(err), - } - } - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const fn try_allocate_in( + fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, ) -> Result - where - A: [const] Allocator + [const] Destruct, { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. @@ -500,6 +468,125 @@ impl RawVecInner { }) } + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + #[cfg(not(no_global_oom_handling))] + #[inline] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn grow_one(&mut self, elem_layout: Layout) + { + // SAFETY: Precondition passed to caller + if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { + handle_error(err); + } + } + + + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - The sum of `len` and `additional` must be greater than the current capacity + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn grow_amortized( + &mut self, + len: usize, + additional: usize, + elem_layout: Layout, + ) -> Result<(), TryReserveError> + { + // This is ensured by the calling contexts. + debug_assert!(additional > 0); + + if elem_layout.size() == 0 { + // Since we return a capacity of `usize::MAX` when `elem_size` is + // 0, getting to here necessarily means the `RawVec` is overfull. + return Err(CapacityOverflow.into()); + } + + // Nothing we can really do about these checks, sadly. + let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + + // This guarantees exponential growth. The doubling cannot overflow + // because `cap <= isize::MAX` and the type of `cap` is `usize`. + let cap = cmp::max(self.cap.as_inner() * 2, required_cap); + let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); + + // SAFETY: + // - cap >= len + additional + // - other preconditions passed to caller + let ptr = unsafe { self.finish_grow(cap, elem_layout)? }; + + // SAFETY: `finish_grow` would have failed if `cap > isize::MAX` + unsafe { self.set_ptr_and_cap(ptr, cap) }; + Ok(()) + } + + /// # Safety + /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to + /// initially construct `self` + /// - `elem_layout`'s size must be a multiple of its alignment + /// - `cap` must be greater than the current capacity + // not marked inline(never) since we want optimizers to be able to observe the specifics of this + // function, see tests/codegen-llvm/vec-reserve-extend.rs. + #[cold] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + unsafe fn finish_grow( + &self, + cap: usize, + elem_layout: Layout, + ) -> Result, TryReserveError> + { + let new_layout = layout_array(cap, elem_layout)?; + + let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { + // FIXME(const-hack): switch to `debug_assert_eq` + debug_assert!(old_layout.align() == new_layout.align()); + unsafe { + // The allocator checks for alignment equality + hint::assert_unchecked(old_layout.align() == new_layout.align()); + self.alloc.grow(ptr, old_layout, new_layout) + } + } else { + self.alloc.allocate(new_layout) + }; + + // FIXME(const-hack): switch back to `map_err` + match memory { + Ok(memory) => Ok(memory), + Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), + } + } +} + +impl RawVecInner { + #[inline] + const fn new_in(alloc: A, align: Alignment) -> Self { + let ptr = Unique::from_non_null(NonNull::without_provenance(align.as_nonzero())); + // `cap: 0` means "unallocated". zero-sized types are ignored. + Self { ptr, cap: ZERO_CAP, alloc } + } + + #[inline] + fn try_with_capacity_in( + capacity: usize, + alloc: A, + elem_layout: Layout, + ) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) + } + + #[cfg(not(no_global_oom_handling))] + #[inline] + fn with_capacity_zeroed_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { + match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc, elem_layout) { + Ok(res) => res, + Err(err) => handle_error(err), + } + } + #[inline] unsafe fn from_raw_parts_in(ptr: *mut u8, cap: Cap, alloc: A) -> Self { Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap, alloc } @@ -583,23 +670,6 @@ impl RawVecInner { } } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - #[cfg(not(no_global_oom_handling))] - #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn grow_one(&mut self, elem_layout: Layout) - where - A: [const] Allocator, - { - // SAFETY: Precondition passed to caller - if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { - handle_error(err); - } - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` @@ -686,48 +756,6 @@ impl RawVecInner { self.cap = unsafe { Cap::new_unchecked(cap) }; } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - /// - The sum of `len` and `additional` must be greater than the current capacity - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn grow_amortized( - &mut self, - len: usize, - additional: usize, - elem_layout: Layout, - ) -> Result<(), TryReserveError> - where - A: [const] Allocator, - { - // This is ensured by the calling contexts. - debug_assert!(additional > 0); - - if elem_layout.size() == 0 { - // Since we return a capacity of `usize::MAX` when `elem_size` is - // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); - } - - // Nothing we can really do about these checks, sadly. - let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; - - // This guarantees exponential growth. The doubling cannot overflow - // because `cap <= isize::MAX` and the type of `cap` is `usize`. - let cap = cmp::max(self.cap.as_inner() * 2, required_cap); - let cap = cmp::max(min_non_zero_cap(elem_layout.size()), cap); - - // SAFETY: - // - cap >= len + additional - // - other preconditions passed to caller - let ptr = unsafe { self.finish_grow(cap, elem_layout)? }; - - // SAFETY: `finish_grow` would have failed if `cap > isize::MAX` - unsafe { self.set_ptr_and_cap(ptr, cap) }; - Ok(()) - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` @@ -755,44 +783,6 @@ impl RawVecInner { Ok(()) } - /// # Safety - /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to - /// initially construct `self` - /// - `elem_layout`'s size must be a multiple of its alignment - /// - `cap` must be greater than the current capacity - // not marked inline(never) since we want optimizers to be able to observe the specifics of this - // function, see tests/codegen-llvm/vec-reserve-extend.rs. - #[cold] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - const unsafe fn finish_grow( - &self, - cap: usize, - elem_layout: Layout, - ) -> Result, TryReserveError> - where - A: [const] Allocator, - { - let new_layout = layout_array(cap, elem_layout)?; - - let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { - // FIXME(const-hack): switch to `debug_assert_eq` - debug_assert!(old_layout.align() == new_layout.align()); - unsafe { - // The allocator checks for alignment equality - hint::assert_unchecked(old_layout.align() == new_layout.align()); - self.alloc.grow(ptr, old_layout, new_layout) - } - } else { - self.alloc.allocate(new_layout) - }; - - // FIXME(const-hack): switch back to `map_err` - match memory { - Ok(memory) => Ok(memory), - Err(_) => Err(AllocError { layout: new_layout, non_exhaustive: () }.into()), - } - } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 29e83113d489..e3aa4785b4f5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -902,27 +902,7 @@ impl Vec { } } -impl Vec { - /// Constructs a new, empty `Vec`. - /// - /// The vector will not allocate until elements are pushed onto it. - /// - /// # Examples - /// - /// ``` - /// #![feature(allocator_api)] - /// - /// use std::alloc::System; - /// - /// # #[allow(unused_mut)] - /// let mut vec: Vec = Vec::new_in(System); - /// ``` - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub const fn new_in(alloc: A) -> Self { - Vec { buf: RawVec::new_in(alloc), len: 0 } - } - +const impl Vec { /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. /// @@ -982,13 +962,115 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn with_capacity_in(capacity: usize, alloc: A) -> Self - where - A: [const] Allocator + [const] Destruct, + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } + + /// Appends an element to the back of a collection. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2]; + /// vec.push(3); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// # Time complexity + /// + /// Takes amortized *O*(1) time. If the vector's length would exceed its + /// capacity after the push, *O*(*capacity*) time is taken to copy the + /// vector's elements to a larger allocation. This expensive operation is + /// offset by the *capacity* *O*(1) insertions it allows. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push_back", "put", "append")] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub fn push(&mut self, value: T) + { + let _ = self.push_mut(value); + } + + /// Appends an element to the back of a collection, returning a reference to it. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds `isize::MAX` _bytes_. + /// + /// # Examples + /// + /// ``` + /// #![feature(push_mut)] + /// + /// + /// let mut vec = vec![1, 2]; + /// let last = vec.push_mut(3); + /// assert_eq!(*last, 3); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// let last = vec.push_mut(3); + /// *last += 1; + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// # Time complexity + /// + /// Takes amortized *O*(1) time. If the vector's length would exceed its + /// capacity after the push, *O*(*capacity*) time is taken to copy the + /// vector's elements to a larger allocation. This expensive operation is + /// offset by the *capacity* *O*(1) insertions it allows. + #[cfg(not(no_global_oom_handling))] + #[inline] + #[unstable(feature = "push_mut", issue = "135974")] + #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] + #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + pub fn push_mut(&mut self, value: T) -> &mut T + { + // Inform codegen that the length does not change across grow_one(). + let len = self.len; + // This will panic or abort if we would allocate > isize::MAX bytes + // or if the length increment would overflow for zero-sized types. + if len == self.buf.capacity() { + self.buf.grow_one(); + } + unsafe { + let end = self.as_mut_ptr().add(len); + ptr::write(end, value); + self.len = len + 1; + // SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference. + &mut *end + } + } +} + +impl Vec { + /// Constructs a new, empty `Vec`. + /// + /// The vector will not allocate until elements are pushed onto it. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// # #[allow(unused_mut)] + /// let mut vec: Vec = Vec::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + Vec { buf: RawVec::new_in(alloc), len: 0 } + } + /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. /// @@ -2574,38 +2656,6 @@ impl Vec { } } - /// Appends an element to the back of a collection. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Examples - /// - /// ``` - /// let mut vec = vec![1, 2]; - /// vec.push(3); - /// assert_eq!(vec, [1, 2, 3]); - /// ``` - /// - /// # Time complexity - /// - /// Takes amortized *O*(1) time. If the vector's length would exceed its - /// capacity after the push, *O*(*capacity*) time is taken to copy the - /// vector's elements to a larger allocation. This expensive operation is - /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_confusables("push_back", "put", "append")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn push(&mut self, value: T) - where - A: [const] Allocator, - { - let _ = self.push_mut(value); - } - /// Appends an element and returns a reference to it if there is sufficient spare capacity, /// otherwise an error is returned with the element. /// @@ -2659,59 +2709,6 @@ impl Vec { } } - /// Appends an element to the back of a collection, returning a reference to it. - /// - /// # Panics - /// - /// Panics if the new capacity exceeds `isize::MAX` _bytes_. - /// - /// # Examples - /// - /// ``` - /// #![feature(push_mut)] - /// - /// - /// let mut vec = vec![1, 2]; - /// let last = vec.push_mut(3); - /// assert_eq!(*last, 3); - /// assert_eq!(vec, [1, 2, 3]); - /// - /// let last = vec.push_mut(3); - /// *last += 1; - /// assert_eq!(vec, [1, 2, 3, 4]); - /// ``` - /// - /// # Time complexity - /// - /// Takes amortized *O*(1) time. If the vector's length would exceed its - /// capacity after the push, *O*(*capacity*) time is taken to copy the - /// vector's elements to a larger allocation. This expensive operation is - /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] - #[inline] - #[unstable(feature = "push_mut", issue = "135974")] - #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub const fn push_mut(&mut self, value: T) -> &mut T - where - A: [const] Allocator, - { - // Inform codegen that the length does not change across grow_one(). - let len = self.len; - // This will panic or abort if we would allocate > isize::MAX bytes - // or if the length increment would overflow for zero-sized types. - if len == self.buf.capacity() { - self.buf.grow_one(); - } - unsafe { - let end = self.as_mut_ptr().add(len); - ptr::write(end, value); - self.len = len + 1; - // SAFETY: We just wrote a value to the pointer that will live the lifetime of the reference. - &mut *end - } - } - /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ef1abcaf639a..959407b75348 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -103,8 +103,7 @@ impl fmt::Display for AllocError { /// [*currently allocated*]: #currently-allocated-memory #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[const_trait] -pub unsafe trait Allocator { +pub const unsafe trait Allocator { /// Attempts to allocate a block of memory. /// /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. From a913065d80129fa501ee9309fb753378d2f5f3d3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 21 Dec 2025 14:11:40 -0500 Subject: [PATCH 076/340] fix rustfmt and bless tidy/tests --- library/alloc/src/lib.rs | 2 +- library/alloc/src/raw_vec/mod.rs | 34 ++++----- library/alloc/src/vec/mod.rs | 19 ++--- ...ng_operand.test.GVN.32bit.panic-abort.diff | 22 +++--- ...ace.PreCodegen.after.32bit.panic-abort.mir | 26 ++++--- ...d_constant.main.GVN.32bit.panic-abort.diff | 72 +++++++++---------- 6 files changed, 80 insertions(+), 95 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f15dfc9b5de7..06133ce056df 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -108,9 +108,9 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_heap)] -#![feature(copied_into_inner)] #![feature(const_option_ops)] #![feature(const_try)] +#![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index c92deb06903d..1e76710d3536 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -165,14 +165,14 @@ const fn min_non_zero_cap(size: usize) -> usize { } } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl RawVec { /// Like `with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self - { + pub(crate) fn with_capacity_in(capacity: usize, alloc: A) -> Self { Self { inner: RawVecInner::with_capacity_in(capacity, alloc, T::LAYOUT), _marker: PhantomData, @@ -183,9 +183,7 @@ const impl RawVec { /// caller to ensure `len == self.capacity()`. #[cfg(not(no_global_oom_handling))] #[inline(never)] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub(crate) fn grow_one(&mut self) - { + pub(crate) fn grow_one(&mut self) { // SAFETY: All calls on self.inner pass T::LAYOUT as the elem_layout unsafe { self.inner.grow_one(T::LAYOUT) } } @@ -411,12 +409,12 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { } } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl RawVecInner { #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self - { + fn with_capacity_in(capacity: usize, alloc: A, elem_layout: Layout) -> Self { match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc, elem_layout) { Ok(this) => { unsafe { @@ -428,14 +426,13 @@ const impl RawVecInner { Err(err) => handle_error(err), } } - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] + fn try_allocate_in( capacity: usize, init: AllocInit, alloc: A, elem_layout: Layout, - ) -> Result - { + ) -> Result { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match layout_array(capacity, elem_layout) { @@ -474,29 +471,24 @@ const impl RawVecInner { /// - `elem_layout`'s size must be a multiple of its alignment #[cfg(not(no_global_oom_handling))] #[inline] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - unsafe fn grow_one(&mut self, elem_layout: Layout) - { + unsafe fn grow_one(&mut self, elem_layout: Layout) { // SAFETY: Precondition passed to caller if let Err(err) = unsafe { self.grow_amortized(self.cap.as_inner(), 1, elem_layout) } { handle_error(err); } } - /// # Safety /// - `elem_layout` must be valid for `self`, i.e. it must be the same `elem_layout` used to /// initially construct `self` /// - `elem_layout`'s size must be a multiple of its alignment /// - The sum of `len` and `additional` must be greater than the current capacity - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] unsafe fn grow_amortized( &mut self, len: usize, additional: usize, elem_layout: Layout, - ) -> Result<(), TryReserveError> - { + ) -> Result<(), TryReserveError> { // This is ensured by the calling contexts. debug_assert!(additional > 0); @@ -532,13 +524,11 @@ const impl RawVecInner { // not marked inline(never) since we want optimizers to be able to observe the specifics of this // function, see tests/codegen-llvm/vec-reserve-extend.rs. #[cold] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] unsafe fn finish_grow( &self, cap: usize, elem_layout: Layout, - ) -> Result, TryReserveError> - { + ) -> Result, TryReserveError> { let new_layout = layout_array(cap, elem_layout)?; let memory = if let Some((ptr, old_layout)) = unsafe { self.current_memory(elem_layout) } { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e3aa4785b4f5..5a9887f1de55 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -902,6 +902,9 @@ impl Vec { } } +#[cfg(not(no_global_oom_handling))] +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustfmt::skip] // FIXME(fee1-dead): temporary measure before rustfmt is bumped const impl Vec { /// Constructs a new, empty `Vec` with at least the specified capacity /// with the provided allocator. @@ -958,16 +961,12 @@ const impl Vec { /// let vec_units = Vec::<(), System>::with_capacity_in(10, System); /// assert_eq!(vec_units.capacity(), usize::MAX); /// ``` - #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "allocator_api", issue = "32838")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn with_capacity_in(capacity: usize, alloc: A) -> Self - { + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } - /// Appends an element to the back of a collection. /// /// # Panics @@ -988,13 +987,10 @@ const impl Vec { /// capacity after the push, *O*(*capacity*) time is taken to copy the /// vector's elements to a larger allocation. This expensive operation is /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("push_back", "put", "append")] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn push(&mut self, value: T) - { + pub fn push(&mut self, value: T) { let _ = self.push_mut(value); } @@ -1026,13 +1022,10 @@ const impl Vec { /// capacity after the push, *O*(*capacity*) time is taken to copy the /// vector's elements to a larger allocation. This expensive operation is /// offset by the *capacity* *O*(1) insertions it allows. - #[cfg(not(no_global_oom_handling))] #[inline] #[unstable(feature = "push_mut", issue = "135974")] #[must_use = "if you don't need a reference to the value, use `Vec::push` instead"] - #[rustc_const_unstable(feature = "const_heap", issue = "79597")] - pub fn push_mut(&mut self, value: T) -> &mut T - { + pub fn push_mut(&mut self, value: T) -> &mut T { // Inform codegen that the length does not change across grow_one(). let len = self.len; // This will panic or abort if we would allocate > isize::MAX bytes diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 2aa92fd34ebf..bcf0ad7c165f 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -26,12 +26,12 @@ scope 4 { debug _x => _8; } - scope 18 (inlined foo) { + scope 19 (inlined foo) { let mut _27: *const [()]; } } - scope 16 (inlined slice_from_raw_parts::<()>) { - scope 17 (inlined std::ptr::from_raw_parts::<[()], ()>) { + scope 17 (inlined slice_from_raw_parts::<()>) { + scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) { } } } @@ -49,19 +49,21 @@ scope 7 { let _21: std::ptr::NonNull<[u8]>; scope 8 { - scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { - scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { - scope 13 (inlined NonNull::<[u8]>::cast::) { + scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) { + scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) { + scope 14 (inlined NonNull::<[u8]>::cast::) { let mut _25: *mut [u8]; - scope 14 (inlined NonNull::<[u8]>::as_ptr) { + scope 15 (inlined NonNull::<[u8]>::as_ptr) { } } } - scope 15 (inlined NonNull::::as_ptr) { + scope 16 (inlined NonNull::::as_ptr) { } } } scope 10 (inlined ::allocate) { + scope 11 (inlined std::alloc::Global::alloc_impl) { + } } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { @@ -192,8 +194,8 @@ + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; StorageDead(_24); StorageLive(_19); -- _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; -+ _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; +- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable]; ++ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 3f854b6cbcfb..d0fda06c115c 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -9,33 +9,33 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { - } - scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { - let mut _12: isize; - let _13: std::alloc::AllocError; - let mut _14: !; - let mut _15: &dyn std::fmt::Debug; - let _16: &std::alloc::AllocError; - scope 7 { + scope 6 (inlined std::alloc::Global::alloc_impl) { } + } + scope 7 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { + let mut _10: isize; + let _11: std::alloc::AllocError; + let mut _12: !; + let mut _13: &dyn std::fmt::Debug; + let _14: &std::alloc::AllocError; scope 8 { } + scope 9 { + } } - scope 9 (inlined NonNull::<[u8]>::as_ptr) { + scope 10 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -46,10 +46,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -58,48 +58,44 @@ } bb2: { - _11 = option::unwrap_failed() -> unwind unreachable; + _9 = option::unwrap_failed() -> unwind unreachable; } bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb4, unwind unreachable]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_8); StorageDead(_7); - StorageLive(_12); - StorageLive(_16); - _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + StorageLive(_10); + StorageLive(_14); + _10 = discriminant(_6); + switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - StorageLive(_15); - _16 = &_13; - _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); - _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; + StorageLive(_13); + _14 = &_11; + _13 = copy _14 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); + _12 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _13) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_16); - StorageDead(_12); + StorageDead(_14); + StorageDead(_10); StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); From aa4ec54dfe9e63f146847265ed0655ffa9027cea Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 04:52:22 +0000 Subject: [PATCH 077/340] fix: `cmp_owned` wrongly unmangled macros --- clippy_lints/src/operators/cmp_owned.rs | 58 +++++++++-------------- tests/ui/cmp_owned/with_suggestion.fixed | 29 ++++++++++++ tests/ui/cmp_owned/with_suggestion.rs | 29 ++++++++++++ tests/ui/cmp_owned/with_suggestion.stderr | 8 +++- 4 files changed, 87 insertions(+), 37 deletions(-) diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index 05358de5b348..39097833a6c5 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeQPath; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_copy}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -94,51 +94,37 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) return; } - let arg_snip = snippet(cx, arg_span, ".."); - let expr_snip; - let eq_impl; - if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { - expr_snip = format!("*{arg_snip}"); - eq_impl = with_deref; + let mut applicability = Applicability::MachineApplicable; + let (arg_snip, _) = snippet_with_context(cx, arg_span, expr.span.ctxt(), "..", &mut applicability); + let (expr_snip, eq_impl) = if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() { + (format!("*{arg_snip}"), with_deref) } else { - expr_snip = arg_snip.to_string(); - eq_impl = without_deref; - } + (arg_snip.to_string(), without_deref) + }; - let span; - let hint; - if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { - span = expr.span; - hint = expr_snip; + let (span, hint) = if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + (expr.span, expr_snip) } else { - span = expr.span.to(other.span); + let span = expr.span.to(other.span); let cmp_span = if other.span < expr.span { other.span.between(expr.span) } else { expr.span.between(other.span) }; - if eq_impl.ty_eq_other { - hint = format!( - "{expr_snip}{}{}", - snippet(cx, cmp_span, ".."), - snippet(cx, other.span, "..") - ); - } else { - hint = format!( - "{}{}{expr_snip}", - snippet(cx, other.span, ".."), - snippet(cx, cmp_span, "..") - ); - } - } - diag.span_suggestion( - span, - "try", - hint, - Applicability::MachineApplicable, // snippet - ); + let (cmp_snippet, _) = snippet_with_context(cx, cmp_span, expr.span.ctxt(), "..", &mut applicability); + let (other_snippet, _) = + snippet_with_context(cx, other.span, expr.span.ctxt(), "..", &mut applicability); + + if eq_impl.ty_eq_other { + (span, format!("{expr_snip}{cmp_snippet}{other_snippet}")) + } else { + (span, format!("{other_snippet}{cmp_snippet}{expr_snip}")) + } + }; + + diag.span_suggestion(span, "try", hint, applicability); }, ); } diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index 85d0991bef05..4c3b13b30043 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2; //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr) { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.rs b/tests/ui/cmp_owned/with_suggestion.rs index 2393757d76f2..a9d7509feaaf 100644 --- a/tests/ui/cmp_owned/with_suggestion.rs +++ b/tests/ui/cmp_owned/with_suggestion.rs @@ -83,3 +83,32 @@ fn issue_8103() { let _ = foo1 == foo2.to_owned(); //~^ cmp_owned } + +macro_rules! issue16322_macro_generator { + ($locale:ident) => { + mod $locale { + macro_rules! _make { + ($token:tt) => { + stringify!($token) + }; + } + + pub(crate) use _make; + } + + macro_rules! t { + ($token:tt) => { + crate::$locale::_make!($token) + }; + } + }; +} + +issue16322_macro_generator!(de); + +fn issue16322(item: String) { + if item == t!(frohes_neu_Jahr).to_string() { + //~^ cmp_owned + println!("Ja!"); + } +} diff --git a/tests/ui/cmp_owned/with_suggestion.stderr b/tests/ui/cmp_owned/with_suggestion.stderr index dd9ffa70897a..66544ce0c217 100644 --- a/tests/ui/cmp_owned/with_suggestion.stderr +++ b/tests/ui/cmp_owned/with_suggestion.stderr @@ -49,5 +49,11 @@ error: this creates an owned instance just for comparison LL | let _ = foo1 == foo2.to_owned(); | ^^^^^^^^^^^^^^^ help: try: `foo2` -error: aborting due to 8 previous errors +error: this creates an owned instance just for comparison + --> tests/ui/cmp_owned/with_suggestion.rs:110:16 + | +LL | if item == t!(frohes_neu_Jahr).to_string() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)` + +error: aborting due to 9 previous errors From 7b8d4c602ee8af316ef06838fafbc1c4da940550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 11:11:44 +0100 Subject: [PATCH 078/340] Rename the `gcc` component to `gcc-dev` To free up the `gcc` name for the actual libgccjit component that we will ship to rustup, and also make it more explicit that this component is internal and for bootstrap usages only. --- src/bootstrap/src/core/build_steps/dist.rs | 14 ++++++++------ src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/download.rs | 2 +- .../docker/host-x86_64/dist-x86_64-linux/dist.sh | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index b9ec063f4352..46cf7aed383b 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2871,24 +2871,26 @@ impl Step for ReproducibleArtifacts { /// Tarball containing a prebuilt version of the libgccjit library, /// needed as a dependency for the GCC codegen backend (similarly to the LLVM /// backend needing a prebuilt libLLVM). +/// +/// This component is used for `download-ci-gcc`. #[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Gcc { +pub struct GccDev { target: TargetSelection, } -impl Step for Gcc { +impl Step for GccDev { type Output = GeneratedTarball; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.alias("gcc") + run.alias("gcc-dev") } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Gcc { target: run.target }); + run.builder.ensure(GccDev { target: run.target }); } fn run(self, builder: &Builder<'_>) -> Self::Output { - let tarball = Tarball::new(builder, "gcc", &self.target.triple); + let tarball = Tarball::new(builder, "gcc-dev", &self.target.triple); let output = builder .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) }); tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary); @@ -2896,6 +2898,6 @@ impl Step for Gcc { } fn metadata(&self) -> Option { - Some(StepMetadata::dist("gcc", self.target)) + Some(StepMetadata::dist("gcc-dev", self.target)) } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7d2b1685bda9..92a6eb8ce837 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -989,7 +989,7 @@ impl<'a> Builder<'a> { dist::PlainSourceTarballGpl, dist::BuildManifest, dist::ReproducibleArtifacts, - dist::Gcc + dist::GccDev ), Kind::Install => describe!( install::Docs, diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d950dc1a1c58..43efdcd7db17 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -381,7 +381,7 @@ impl Config { } let base = &self.stage0_metadata.config.artifacts_server; let version = self.artifact_version_part(gcc_sha); - let filename = format!("gcc-{version}-{}.tar.xz", self.host_target.triple); + let filename = format!("gcc-dev-{version}-{}.tar.xz", self.host_target.triple); let tarball = gcc_cache.join(&filename); if !tarball.exists() { let help_on_error = "ERROR: failed to download gcc from ci diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index 4c95d4a401e5..9579e0d79cb0 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -9,8 +9,8 @@ python3 ../x.py build --set rust.debug=true opt-dist --include-default-paths \ build-manifest bootstrap -# Use GCC for building GCC, as it seems to behave badly when built with Clang +# Use GCC for building GCC components, as it seems to behave badly when built with Clang # Only build GCC on full builds, not try builds if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then - CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc + CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc-dev fi From 4129f3aeef37e1ec9d79863f88ece1e13eeb9800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 11:12:05 +0100 Subject: [PATCH 079/340] Temporarily disable `gcc.download-ci-gcc` Because we renamed the CI component. We will have to re-enable it in a follow-up PR. --- src/ci/run.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index b486f0525f40..425ad38a6655 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -187,8 +187,9 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi - # Download GCC from CI on test builders - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true" + # Download GCC from CI on test builders (temporarily disabled because the CI gcc component + # was renamed). + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=false" # download-rustc seems to be broken on CI after the stage0 redesign # Disable it until these issues are debugged and resolved From 2a893bd67feeda40adc8fa962988703cda3199b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:41:31 +0100 Subject: [PATCH 080/340] Remove unused GCC ignore in opt-dist The `CiGcc` step is not enabled by defaut, so it does not have to be skipped. --- src/tools/opt-dist/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 48b25f235dd6..5515dbf1940e 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -454,7 +454,6 @@ fn main() -> anyhow::Result<()> { "clippy", "miri", "rustfmt", - "gcc", "generate-copyright", "bootstrap", ] { From 4b34f4f4fbc1cb43307d31ed349909c53843a6d1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 10:19:02 +0100 Subject: [PATCH 081/340] minor: Fix some minor FIXMEs --- .../crates/hir-def/src/expr_store.rs | 8 ++++---- .../crates/hir-def/src/expr_store/expander.rs | 7 +------ .../crates/hir-def/src/expr_store/lower.rs | 19 +++++++++---------- .../src/expr_store/lower/format_args.rs | 3 ++- .../crates/hir-def/src/hir/generics.rs | 3 +-- .../hir-def/src/nameres/path_resolution.rs | 2 -- .../crates/hir-def/src/resolver.rs | 2 +- .../crates/hir/src/has_source.rs | 2 +- .../crates/rust-analyzer/src/lib.rs | 3 +++ 9 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index 66f7e25ffac4..10cd460d1d36 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -57,8 +57,7 @@ impl HygieneId { Self(ctx) } - // FIXME: Inline this - pub(crate) fn lookup(self) -> SyntaxContext { + pub(crate) fn syntax_context(self) -> SyntaxContext { self.0 } @@ -73,7 +72,8 @@ pub type ExprSource = InFile; pub type PatPtr = AstPtr; pub type PatSource = InFile; -pub type LabelPtr = AstPtr; +/// BlockExpr -> Desugared label from try block +pub type LabelPtr = AstPtr>; pub type LabelSource = InFile; pub type FieldPtr = AstPtr; @@ -942,7 +942,7 @@ impl ExpressionStoreSourceMap { } pub fn node_label(&self, node: InFile<&ast::Label>) -> Option { - let src = node.map(AstPtr::new); + let src = node.map(AstPtr::new).map(AstPtr::wrap_left); self.expr_only()?.label_map.get(&src).cloned() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index 6a2f06b0a6f6..de5974fff1ad 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, }; -use span::{AstIdMap, Edition, SyntaxContext}; +use span::{AstIdMap, SyntaxContext}; use syntax::ast::HasAttrs; use syntax::{AstNode, Parse, ast}; use triomphe::Arc; @@ -75,11 +75,6 @@ impl Expander { AttrFlags::is_cfg_enabled_for(owner, cfg_options) } - pub(super) fn call_syntax_ctx(&self) -> SyntaxContext { - // FIXME: - SyntaxContext::root(Edition::CURRENT_FIXME) - } - pub(super) fn enter_expand( &mut self, db: &dyn DefDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 42b076abb2a6..af274f1a485b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -1096,7 +1096,7 @@ impl<'db> ExprCollector<'db> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { - // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c + // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c let is_rustc_box = { let attrs = e.attrs(); attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") @@ -1649,7 +1649,7 @@ impl<'db> ExprCollector<'db> { fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId { let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput); let label = self.generate_new_name(); - let label = self.alloc_label_desugared(Label { name: label }); + let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right()); let old_label = self.current_try_block_label.replace(label); let ptr = AstPtr::new(&e).upcast(); @@ -2399,7 +2399,6 @@ impl<'db> ExprCollector<'db> { }; let start = range_part_lower(p.start()); let end = range_part_lower(p.end()); - // FIXME: Exclusive ended pattern range is stabilised match p.op_kind() { Some(range_type) => Pat::Range { start, end, range_type }, None => Pat::Missing, @@ -2519,9 +2518,9 @@ impl<'db> ExprCollector<'db> { let mut hygiene_info = if hygiene_id.is_root() { None } else { - hygiene_id.lookup().outer_expn(self.db).map(|expansion| { + hygiene_id.syntax_context().outer_expn(self.db).map(|expansion| { let expansion = self.db.lookup_intern_macro_call(expansion.into()); - (hygiene_id.lookup().parent(self.db), expansion.def) + (hygiene_id.syntax_context().parent(self.db), expansion.def) }) }; let name = Name::new_lifetime(&lifetime.text()); @@ -2727,17 +2726,17 @@ impl ExprCollector<'_> { self.store.pats.alloc(Pat::Missing) } - fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { + fn alloc_label(&mut self, label: Label, ptr: AstPtr) -> LabelId { + self.alloc_label_desugared(label, ptr.wrap_left()) + } + + fn alloc_label_desugared(&mut self, label: Label, ptr: LabelPtr) -> LabelId { let src = self.expander.in_file(ptr); let id = self.store.labels.alloc(label); self.store.label_map_back.insert(id, src); self.store.label_map.insert(src, id); id } - // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow. - fn alloc_label_desugared(&mut self, label: Label) -> LabelId { - self.store.labels.alloc(label) - } fn is_lowering_awaitable_block(&self) -> &Awaitable { self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown")) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs index 32c9df3dfefb..7ef84f27f664 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs @@ -3,6 +3,7 @@ use base_db::FxIndexSet; use hir_expand::name::Name; use intern::{Symbol, sym}; +use span::SyntaxContext; use syntax::{AstPtr, AstToken as _, ast}; use crate::{ @@ -49,7 +50,7 @@ impl<'db> ExprCollector<'db> { self.expand_macros_to_string(template.clone()).map(|it| (it, template)) }) { Some(((s, is_direct_literal), template)) => { - let call_ctx = self.expander.call_syntax_ctx(); + let call_ctx = SyntaxContext::root(self.def_map.edition()); let hygiene = self.hygiene_id_for(s.syntax().text_range()); let fmt = format_args::parse( &s, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index 1a2d5ebba467..482cf36f95b0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -20,8 +20,7 @@ pub type LocalLifetimeParamId = Idx; /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { - /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. FIXME: Might be better to just - /// make it always be a value, giving impl trait a special name. + /// [`None`] only if the type ref is an [`crate::type_ref::TypeRef::ImplTrait`]. pub name: Option, pub default: Option, pub provenance: TypeParamProvenance, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index e4b1d2a98735..cf33cecf5fba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -267,7 +267,6 @@ impl DefMap { // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition PathKind::Plain | PathKind::Abs if self.data.edition == Edition::Edition2015 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => @@ -383,7 +382,6 @@ impl DefMap { // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition PathKind::Plain | PathKind::Abs if self.data.edition == Edition::Edition2015 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 263f603a0bfb..f643ed31ad53 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -950,7 +950,7 @@ fn hygiene_info( hygiene_id: HygieneId, ) -> Option<(SyntaxContext, MacroDefId)> { if !hygiene_id.is_root() { - let ctx = hygiene_id.lookup(); + let ctx = hygiene_id.syntax_context(); ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (ctx.parent(db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 09c5b1cca7f3..e032a16989ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -330,7 +330,7 @@ impl HasSource for Label { let (_body, source_map) = db.body_with_source_map(self.parent); let src = source_map.label_syntax(self.label_id); let root = src.file_syntax(db); - Some(src.map(|ast| ast.to_node(&root))) + src.map(|ast| ast.to_node(&root).left()).transpose() } } 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 971ae2a601f7..4a37bb34aba3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -16,6 +16,9 @@ extern crate rustc_driver as _; extern crate ra_ap_rustc_type_ir as rustc_type_ir; +/* + If you bump this, grep for `FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION)` to check for old support code we can drop +*/ /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version { major: 1, From bcdcabee75e5f0aad8811ce204f38e54174d26fd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:15:58 +0300 Subject: [PATCH 082/340] resolve: Do not break from the scope visiting loop if we already found the innermost binding. Previously we could lose the already found binding and break with an error, if some blocking error was found in the shadowed scopes. Also, avoid some impossible state in the return type of `fn resolve_ident_in_scope`. --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 669f045681b7..8e5c15e88ca5 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -429,10 +429,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident.span.ctxt(), derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { - // We can break with an error at this step, it means we cannot determine the - // resolution right now, but we must block and wait until we can instead of - // considering outer scopes. - match this.reborrow().resolve_ident_in_scope( + let res = match this.reborrow().resolve_ident_in_scope( orig_ident, ns, scope, @@ -445,7 +442,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force, ignore_binding, ignore_import, - )? { + ) { + Ok(binding) => Ok(binding), + // We can break with an error at this step, it means we cannot determine the + // resolution right now, but we must block and wait until we can, instead of + // considering outer scopes. Although there's no need to do that if we already + // have a better solution. + Err(ControlFlow::Break(determinacy)) if innermost_results.is_empty() => { + return ControlFlow::Break(Err(determinacy)); + } + Err(determinacy) => Err(determinacy.into_value()), + }; + match res { Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, @@ -504,8 +512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, ignore_binding: Option>, ignore_import: Option>, - ) -> ControlFlow, Determinacy>, Result, Determinacy>> - { + ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { @@ -591,7 +598,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return ControlFlow::Break(Err(Determinacy::determined(force))); + return Err(ControlFlow::Break(Determinacy::determined(force))); } // Privacy errors, do not happen during in scope resolution. Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), @@ -680,7 +687,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, }; - ControlFlow::Continue(ret) + ret.map_err(ControlFlow::Continue) } fn maybe_push_ambiguity( From 75d90094e732948f4a45cb407f604239ae6a31ef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:24:59 +0300 Subject: [PATCH 083/340] resolve: Split `Scope::Module` into two scopes for non-glob and glob bindings --- compiler/rustc_resolve/src/diagnostics.rs | 7 +- compiler/rustc_resolve/src/ident.rs | 71 +++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 17 +++-- tests/ui/imports/issue-114682-1.rs | 1 + tests/ui/imports/issue-114682-1.stderr | 28 +++++++- .../local-modularized-tricky-fail-1.rs | 1 + .../local-modularized-tricky-fail-1.stderr | 32 ++++++++- tests/ui/imports/macro-paths.rs | 1 + tests/ui/imports/macro-paths.stderr | 28 ++++++-- 9 files changed, 157 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8f20b5fe5745..716e1d5a2e7f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1206,9 +1206,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } - Scope::Module(module, _) => { + Scope::ModuleNonGlobs(module, _) => { this.add_module_candidates(module, suggestions, filter_fn, None); } + Scope::ModuleGlobs(..) => { + // Already handled in `ModuleNonGlobs`. + } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( |(name, binding)| { @@ -2033,7 +2036,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } - if let Scope::Module(module, _) = scope { + if let Scope::ModuleNonGlobs(module, _) | Scope::ModuleGlobs(module, _) = scope { if module == self.graph_root { help_msgs.push(format!( "use `crate::{ident}` to refer to this {thing} unambiguously" diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8e5c15e88ca5..fcd058c5ae6d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -116,9 +116,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { - _ if module_and_extern_prelude => Scope::Module(module, None), + _ if module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), _ if extern_prelude => Scope::ExternPreludeItems, - TypeNS | ValueNS => Scope::Module(module, None), + TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -145,7 +145,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } true } - Scope::Module(..) => true, + Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..) => true, Scope::MacroUsePrelude => use_prelude || rust_2015, Scope::BuiltinAttrs => true, Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { @@ -186,20 +186,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module, None), + MacroRulesScope::Empty => Scope::ModuleNonGlobs(module, None), }, - Scope::Module(..) if module_and_extern_prelude => match ns { + Scope::ModuleNonGlobs(module, lint_id) => Scope::ModuleGlobs(module, lint_id), + Scope::ModuleGlobs(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); Scope::ExternPreludeItems } ValueNS | MacroNS => break, }, - Scope::Module(module, prev_lint_id) => { + Scope::ModuleGlobs(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { Some((parent_module, lint_id)) => { - Scope::Module(parent_module, lint_id.or(prev_lint_id)) + Scope::ModuleNonGlobs(parent_module, lint_id.or(prev_lint_id)) } None => { ctxt.adjust(ExpnId::root()); @@ -560,7 +561,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), }, - Scope::Module(module, derive_fallback_lint_id) => { + Scope::ModuleNonGlobs(module, derive_fallback_lint_id) => { let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { (parent_scope, finalize) @@ -570,7 +571,51 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = self.reborrow().resolve_ident_in_module_unadjusted( + let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( + module, + ident, + ns, + adjusted_parent_scope, + Shadowing::Restricted, + adjusted_finalize, + ignore_binding, + ignore_import, + ); + match binding { + Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + self.get_mut().lint_buffer.buffer_lint( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + errors::ProcMacroDeriveResolutionFallback { + span: orig_ident.span, + ns_descr: ns.descr(), + ident, + }, + ); + } + Ok(binding) + } + Err(ControlFlow::Continue(determinacy)) => Err(determinacy), + Err(ControlFlow::Break(Determinacy::Undetermined)) => { + return Err(ControlFlow::Break(Determinacy::determined(force))); + } + // Privacy errors, do not happen during in scope resolution. + Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), + } + } + Scope::ModuleGlobs(module, derive_fallback_lint_id) => { + let (adjusted_parent_scope, adjusted_finalize) = + if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; + let binding = self.reborrow().resolve_ident_in_module_globs_unadjusted( module, ident, ns, @@ -717,12 +762,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else if res == derive_helper_compat && innermost_res != derive_helper { span_bug!(orig_ident.span, "impossible inner resolution kind") } else if matches!(innermost_scope, Scope::MacroRules(_)) - && matches!(scope, Scope::Module(..)) + && matches!(scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) { Some(AmbiguityKind::MacroRulesVsModularized) } else if matches!(scope, Scope::MacroRules(_)) - && matches!(innermost_scope, Scope::Module(..)) + && matches!(innermost_scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) { // should be impossible because of visitation order in // visit_scopes @@ -1177,8 +1222,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: binding, b2: shadowed_glob, - scope1: Scope::Module(self.empty_module, None), - scope2: Scope::Module(self.empty_module, None), + scope1: Scope::ModuleGlobs(self.empty_module, None), + scope2: Scope::ModuleGlobs(self.empty_module, None), warning: false, }); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7cbf2088efce..fa53d57d175e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -123,10 +123,14 @@ enum Scope<'ra> { DeriveHelpersCompat, /// Textual `let`-like scopes introduced by `macro_rules!` items. MacroRules(MacroRulesScopeRef<'ra>), - /// Names declared in the given module. + /// Non-glob names declared in the given module. /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` /// lint if it should be reported. - Module(Module<'ra>, Option), + ModuleNonGlobs(Module<'ra>, Option), + /// Glob names declared in the given module. + /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + /// lint if it should be reported. + ModuleGlobs(Module<'ra>, Option), /// Names introduced by `#[macro_use]` attributes on `extern crate` items. MacroUsePrelude, /// Built-in attributes. @@ -1926,9 +1930,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let scope_set = ScopeSet::All(TypeNS); self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |this, scope, _, _| { match scope { - Scope::Module(module, _) => { + Scope::ModuleNonGlobs(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } + Scope::ModuleGlobs(..) => { + // Already handled in `ModuleNonGlobs` (but see #144993). + } Scope::StdLibPrelude => { if let Some(module) = this.prelude { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2061,8 +2068,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, b1: used_binding, b2, - scope1: Scope::Module(self.empty_module, None), - scope2: Scope::Module(self.empty_module, None), + scope1: Scope::ModuleGlobs(self.empty_module, None), + scope2: Scope::ModuleGlobs(self.empty_module, None), warning: warn_ambiguity, }; if !self.matches_previous_ambiguity_error(&ambiguity_error) { diff --git a/tests/ui/imports/issue-114682-1.rs b/tests/ui/imports/issue-114682-1.rs index 88fe05e51444..58b78508026d 100644 --- a/tests/ui/imports/issue-114682-1.rs +++ b/tests/ui/imports/issue-114682-1.rs @@ -22,4 +22,5 @@ mac!(); fn main() { A!(); //~^ ERROR `A` is ambiguous + //~| ERROR `A` is ambiguous } diff --git a/tests/ui/imports/issue-114682-1.stderr b/tests/ui/imports/issue-114682-1.stderr index 85fb7f7919e4..de8dc6cfb9ff 100644 --- a/tests/ui/imports/issue-114682-1.stderr +++ b/tests/ui/imports/issue-114682-1.stderr @@ -23,6 +23,32 @@ LL | pub use m::*; = help: consider adding an explicit import of `A` to disambiguate = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0659]: `A` is ambiguous + --> $DIR/issue-114682-1.rs:23:5 + | +LL | A!(); + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `A` could refer to the macro defined here + --> $DIR/issue-114682-1.rs:7:9 + | +LL | / pub macro A() { +LL | | println!("non import") +LL | | } + | |_________^ +... +LL | mac!(); + | ------ in this macro invocation + = help: use `crate::A` to refer to this macro unambiguously +note: `A` could also refer to the macro imported here + --> $DIR/issue-114682-1.rs:19:9 + | +LL | pub use m::*; + | ^^^^ + = help: use `crate::A` to refer to this macro unambiguously + = note: this error originates in the macro `mac` (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 E0659`. diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index ce700ae0de9b..bba26ee43a24 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -27,6 +27,7 @@ mod inner1 { } exported!(); //~ ERROR `exported` is ambiguous + //~| ERROR `exported` is ambiguous mod inner2 { define_exported!(); diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 52a01e8bcdfe..54d928f7c812 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -23,8 +23,34 @@ LL | use inner1::*; = help: consider adding an explicit import of `exported` to disambiguate = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0659]: `exported` is ambiguous + --> $DIR/local-modularized-tricky-fail-1.rs:29:1 + | +LL | exported!(); + | ^^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `exported` could refer to the macro defined here + --> $DIR/local-modularized-tricky-fail-1.rs:6:5 + | +LL | / macro_rules! exported { +LL | | () => () +LL | | } + | |_____^ +... +LL | define_exported!(); + | ------------------ in this macro invocation + = help: use `crate::exported` to refer to this macro unambiguously +note: `exported` could also refer to the macro imported here + --> $DIR/local-modularized-tricky-fail-1.rs:23:5 + | +LL | use inner1::*; + | ^^^^^^^^^ + = help: use `crate::exported` to refer to this macro unambiguously + = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:36:5 + --> $DIR/local-modularized-tricky-fail-1.rs:37:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -45,7 +71,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:47:1 + --> $DIR/local-modularized-tricky-fail-1.rs:48:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -65,6 +91,6 @@ LL | define_include!(); = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (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 For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/macro-paths.rs b/tests/ui/imports/macro-paths.rs index 916442a7c4ea..6fd426c34eff 100644 --- a/tests/ui/imports/macro-paths.rs +++ b/tests/ui/imports/macro-paths.rs @@ -11,6 +11,7 @@ mod foo { fn f() { use foo::*; bar::m! { //~ ERROR ambiguous + //~| ERROR `bar` is ambiguous mod bar { pub use two_macros::m; } } } diff --git a/tests/ui/imports/macro-paths.stderr b/tests/ui/imports/macro-paths.stderr index 5f113ce2bee5..5ba92072805e 100644 --- a/tests/ui/imports/macro-paths.stderr +++ b/tests/ui/imports/macro-paths.stderr @@ -6,7 +6,7 @@ LL | bar::m! { | = 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: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:14:9 + --> $DIR/macro-paths.rs:15:9 | LL | mod bar { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,20 +17,38 @@ LL | use foo::*; | ^^^^^^ = help: consider adding an explicit import of `bar` to disambiguate +error[E0659]: `bar` is ambiguous + --> $DIR/macro-paths.rs:13:5 + | +LL | bar::m! { + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `bar` could refer to the module defined here + --> $DIR/macro-paths.rs:15:9 + | +LL | mod bar { pub use two_macros::m; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: `bar` could also refer to the module imported here + --> $DIR/macro-paths.rs:12:9 + | +LL | use foo::*; + | ^^^^^^ + error[E0659]: `baz` is ambiguous - --> $DIR/macro-paths.rs:23:5 + --> $DIR/macro-paths.rs:24:5 | LL | baz::m! { | ^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `baz` could refer to the module defined here - --> $DIR/macro-paths.rs:24:9 + --> $DIR/macro-paths.rs:25:9 | LL | mod baz { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `baz` could also refer to the module defined here - --> $DIR/macro-paths.rs:18:1 + --> $DIR/macro-paths.rs:19:1 | LL | / pub mod baz { LL | | pub use two_macros::m; @@ -38,6 +56,6 @@ LL | | } | |_^ = help: use `crate::baz` to refer to this module unambiguously -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. From bcfbb5619c5f2f9d69d8b60b820a2b1db266d4af Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Dec 2025 22:46:42 +0300 Subject: [PATCH 084/340] resolve: Migrate a special ambiguity for glob vs non-glob bindings in the same module to the usual ambiguity infra in `resolve_ident_in_scope_set` --- compiler/rustc_resolve/src/ident.rs | 30 +++++++++-------------------- tests/ui/imports/macro-paths.rs | 1 - tests/ui/imports/macro-paths.stderr | 29 +++++----------------------- 3 files changed, 14 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index fcd058c5ae6d..61e98c60a5c9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -783,9 +783,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(AmbiguityKind::GlobVsOuter) } else if innermost_binding.may_appear_after(parent_scope.expansion, binding) { Some(AmbiguityKind::MoreExpandedVsOuter) + } else if innermost_binding.expansion != LocalExpnId::ROOT + && let Scope::ModuleGlobs(m1, _) = scope + && let Scope::ModuleNonGlobs(m2, _) = innermost_scope + && m1 == m2 + { + // FIXME: this error is too conservative and technically unnecessary now when module + // scope is split into two scopes, remove it with lang team approval. + Some(AmbiguityKind::GlobVsExpanded) } else { None }; + if let Some(kind) = ambiguity_error_kind { // Skip ambiguity errors for extern flag bindings "overridden" // by extern item bindings. @@ -1008,7 +1017,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.get_mut().finalize_module_binding( ident, binding, - if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, module, finalize, @@ -1070,7 +1078,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.get_mut().finalize_module_binding( ident, binding, - if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, module, finalize, @@ -1182,7 +1189,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, ident: Ident, binding: Option>, - shadowed_glob: Option>, parent_scope: &ParentScope<'ra>, module: Module<'ra>, finalize: Finalize, @@ -1210,24 +1216,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = shadowed_glob - && shadowing == Shadowing::Restricted - && finalize.stage == Stage::Early - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - scope1: Scope::ModuleGlobs(self.empty_module, None), - scope2: Scope::ModuleGlobs(self.empty_module, None), - warning: false, - }); - } - if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT && let NameBindingKind::Import { import, .. } = binding.kind diff --git a/tests/ui/imports/macro-paths.rs b/tests/ui/imports/macro-paths.rs index 6fd426c34eff..916442a7c4ea 100644 --- a/tests/ui/imports/macro-paths.rs +++ b/tests/ui/imports/macro-paths.rs @@ -11,7 +11,6 @@ mod foo { fn f() { use foo::*; bar::m! { //~ ERROR ambiguous - //~| ERROR `bar` is ambiguous mod bar { pub use two_macros::m; } } } diff --git a/tests/ui/imports/macro-paths.stderr b/tests/ui/imports/macro-paths.stderr index 5ba92072805e..56a40e908258 100644 --- a/tests/ui/imports/macro-paths.stderr +++ b/tests/ui/imports/macro-paths.stderr @@ -1,22 +1,3 @@ -error[E0659]: `bar` is ambiguous - --> $DIR/macro-paths.rs:13:5 - | -LL | bar::m! { - | ^^^ ambiguous name - | - = 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: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:15:9 - | -LL | mod bar { pub use two_macros::m; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: `bar` could also refer to the module imported here - --> $DIR/macro-paths.rs:12:9 - | -LL | use foo::*; - | ^^^^^^ - = help: consider adding an explicit import of `bar` to disambiguate - error[E0659]: `bar` is ambiguous --> $DIR/macro-paths.rs:13:5 | @@ -25,7 +6,7 @@ LL | bar::m! { | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `bar` could refer to the module defined here - --> $DIR/macro-paths.rs:15:9 + --> $DIR/macro-paths.rs:14:9 | LL | mod bar { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,19 +17,19 @@ LL | use foo::*; | ^^^^^^ error[E0659]: `baz` is ambiguous - --> $DIR/macro-paths.rs:24:5 + --> $DIR/macro-paths.rs:23:5 | LL | baz::m! { | ^^^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `baz` could refer to the module defined here - --> $DIR/macro-paths.rs:25:9 + --> $DIR/macro-paths.rs:24:9 | LL | mod baz { pub use two_macros::m; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: `baz` could also refer to the module defined here - --> $DIR/macro-paths.rs:19:1 + --> $DIR/macro-paths.rs:18:1 | LL | / pub mod baz { LL | | pub use two_macros::m; @@ -56,6 +37,6 @@ LL | | } | |_^ = help: use `crate::baz` to refer to this module unambiguously -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From cd7a58e4127a66f8a641c42c6a12c5419c8d5585 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 13:01:07 +0100 Subject: [PATCH 085/340] Pre-allocate intern storages with 64kb of data To reduce the amount of re-allocating the hashtables which can be expensive given the need to re-hash --- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 8 ++++---- .../crates/hir-ty/src/next_solver/infer/mod.rs | 8 +++++--- .../src/next_solver/infer/opaque_types/table.rs | 2 +- .../crates/hir-ty/src/tests/incremental.rs | 3 --- .../rust-analyzer/crates/hir-ty/src/variance.rs | 13 +++++++------ src/tools/rust-analyzer/crates/intern/src/intern.rs | 2 +- .../rust-analyzer/crates/intern/src/intern_slice.rs | 7 ++++++- 8 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..e45ef113a086 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1319,7 +1319,7 @@ fn type_for_struct_constructor( db: &dyn HirDatabase, def: StructId, ) -> Option> { - let struct_data = def.fields(db); + let struct_data = db.struct_signature(def); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 50dbd87d693e..3d7cc4ffbf8a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -731,6 +731,10 @@ impl TraitImpls { ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.impls() { + let trait_ref = match db.impl_trait(impl_id) { + Some(tr) => tr.instantiate_identity(), + None => continue, + }; // Reservation impls should be ignored during trait resolution, so we never need // them during type analysis. See rust-lang/rust#64631 for details. // @@ -742,10 +746,6 @@ impl TraitImpls { { continue; } - let trait_ref = match db.impl_trait(impl_id) { - Some(tr) => tr.instantiate_identity(), - None => continue, - }; let self_ty = trait_ref.self_ty(); let interner = DbInterner::new_no_crate(db); let entry = map.entry(trait_ref.def_id.0).or_default(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index 2926dc30def7..7d291f7ddbed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -878,9 +878,11 @@ impl<'db> InferCtxt<'db> { self.tainted_by_errors.set(Some(e)); } - #[instrument(level = "debug", skip(self), ret)] - pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)> { - self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() + #[instrument(level = "debug", skip(self))] + pub fn take_opaque_types( + &self, + ) -> impl IntoIterator, OpaqueHiddenType<'db>)> + use<'db> { + self.inner.borrow_mut().opaque_type_storage.take_opaque_types() } #[instrument(level = "debug", skip(self), ret)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs index 00177d21ac76..894fe5eb7b87 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs @@ -61,7 +61,7 @@ impl<'db> OpaqueTypeStorage<'db> { pub(crate) fn take_opaque_types( &mut self, - ) -> impl Iterator, OpaqueHiddenType<'db>)> { + ) -> impl IntoIterator, OpaqueHiddenType<'db>)> + use<'db> { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 1457bb2e1017..633ab43c4cec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -632,8 +632,6 @@ fn main() { "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", "value_ty_query", - "VariantFields::firewall_", - "VariantFields::query_", "InherentImpls::for_crate_", "impl_signature_shim", "impl_signature_with_source_map_shim", @@ -723,7 +721,6 @@ fn main() { "expr_scopes_shim", "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", - "VariantFields::query_", "InherentImpls::for_crate_", "impl_signature_with_source_map_shim", "impl_signature_shim", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index e5cfe85573b8..6f415a5289c9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -41,7 +41,6 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances )] fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf { tracing::debug!("variances_of(def={:?})", def); - let interner = DbInterner::new_no_crate(db); match def { GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { @@ -55,15 +54,17 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance } } } - _ => return VariancesOf::empty(interner).store(), + _ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(), } let generics = generics(db, def); let count = generics.len(); if count == 0 { - return VariancesOf::empty(interner).store(); + return VariancesOf::empty(DbInterner::new_no_crate(db)).store(); } - let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve(); + let variances = + Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db } + .solve(); VariancesOf::new_from_slice(&variances).store() } @@ -113,11 +114,11 @@ pub(crate) fn variances_of_cycle_initial( struct Context<'db> { db: &'db dyn HirDatabase, generics: Generics, - variances: Vec, + variances: Box<[Variance]>, } impl<'db> Context<'db> { - fn solve(mut self) -> Vec { + fn solve(mut self) -> Box<[Variance]> { tracing::debug!("solve(generics={:?})", self.generics); match self.generics.def() { GenericDefId::AdtId(adt) => { diff --git a/src/tools/rust-analyzer/crates/intern/src/intern.rs b/src/tools/rust-analyzer/crates/intern/src/intern.rs index b7acd6624b99..a96dfcfa9fe3 100644 --- a/src/tools/rust-analyzer/crates/intern/src/intern.rs +++ b/src/tools/rust-analyzer/crates/intern/src/intern.rs @@ -334,7 +334,7 @@ impl InternStorage { impl InternStorage { pub(crate) fn get(&self) -> &InternMap { - self.map.get_or_init(DashMap::default) + self.map.get_or_init(|| DashMap::with_capacity_and_hasher(1024, Default::default())) } } diff --git a/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs b/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs index 58de6e17bdff..8857771d2e01 100644 --- a/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs +++ b/src/tools/rust-analyzer/crates/intern/src/intern_slice.rs @@ -292,7 +292,12 @@ impl InternSliceStorage { impl InternSliceStorage { pub(crate) fn get(&self) -> &InternMap { - self.map.get_or_init(DashMap::default) + self.map.get_or_init(|| { + DashMap::with_capacity_and_hasher( + (64 * 1024) / std::mem::size_of::(), + Default::default(), + ) + }) } } From d7d49244ef9dafb7dff752b03561f369a9aab7e7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 4 Dec 2025 22:03:42 +0300 Subject: [PATCH 086/340] resolve: Introduce `ScopeSet::Module` for looking up a name in two scopes inside a module - non-glob and glob bindings. --- compiler/rustc_resolve/src/ident.rs | 187 ++++++++++++---------------- compiler/rustc_resolve/src/late.rs | 6 +- compiler/rustc_resolve/src/lib.rs | 2 + 3 files changed, 87 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 61e98c60a5c9..82a87b8a9ed6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -103,20 +103,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rust_2015 = ctxt.edition().is_rust_2015(); let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), + ScopeSet::All(ns) + | ScopeSet::Module(ns, _) + | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; let module = match scope_set { // Start with the specified module. - ScopeSet::ModuleAndExternPrelude(_, module) => module, + ScopeSet::Module(_, module) | ScopeSet::ModuleAndExternPrelude(_, module) => module, // Jump out of trait or enum modules, they do not act as scopes. _ => parent_scope.module.nearest_item_scope(), }; + let module_only = matches!(scope_set, ScopeSet::Module(..)); let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { - _ if module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), + _ if module_only || module_and_extern_prelude => Scope::ModuleNonGlobs(module, None), _ if extern_prelude => Scope::ExternPreludeItems, TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), @@ -189,6 +192,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Empty => Scope::ModuleNonGlobs(module, None), }, Scope::ModuleNonGlobs(module, lint_id) => Scope::ModuleGlobs(module, lint_id), + Scope::ModuleGlobs(..) if module_only => break, Scope::ModuleGlobs(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); @@ -336,13 +340,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ))); } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( - module, + && let Ok(binding) = self.cm().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, module), parent_scope, - Shadowing::Unrestricted, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), + finalize.is_some(), ignore_binding, None, ) @@ -395,12 +398,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. - if orig_ident.is_path_segment_keyword() { + if orig_ident.is_path_segment_keyword() && !matches!(scope_set, ScopeSet::Module(..)) { return Err(Determinacy::Determined); } let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), + ScopeSet::All(ns) + | ScopeSet::Module(ns, _) + | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; @@ -468,6 +473,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, + ns, + scope_set, parent_scope, binding, scope, @@ -562,21 +569,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::ModuleNonGlobs(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, adjusted_finalize) = - if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) - } else { - ( - &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), - ) - }; + let (adjusted_parent_scope, adjusted_finalize) = if matches!( + scope_set, + ScopeSet::Module(..) | ScopeSet::ModuleAndExternPrelude(..) + ) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( module, ident, ns, adjusted_parent_scope, - Shadowing::Restricted, + if matches!(scope_set, ScopeSet::Module(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, adjusted_finalize, ignore_binding, ignore_import, @@ -598,29 +611,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), - Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return Err(ControlFlow::Break(Determinacy::determined(force))); + Err(ControlFlow::Break(determinacy)) => { + return Err(ControlFlow::Break(Determinacy::determined( + determinacy == Determinacy::Determined || force, + ))); } - // Privacy errors, do not happen during in scope resolution. - Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), } } Scope::ModuleGlobs(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, adjusted_finalize) = - if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { - (parent_scope, finalize) - } else { - ( - &ParentScope { module, ..*parent_scope }, - finalize.map(|f| Finalize { used: Used::Scope, ..f }), - ) - }; + let (adjusted_parent_scope, adjusted_finalize) = if matches!( + scope_set, + ScopeSet::Module(..) | ScopeSet::ModuleAndExternPrelude(..) + ) { + (parent_scope, finalize) + } else { + ( + &ParentScope { module, ..*parent_scope }, + finalize.map(|f| Finalize { used: Used::Scope, ..f }), + ) + }; let binding = self.reborrow().resolve_ident_in_module_globs_unadjusted( module, ident, ns, adjusted_parent_scope, - Shadowing::Restricted, + if matches!(scope_set, ScopeSet::Module(..)) { + Shadowing::Unrestricted + } else { + Shadowing::Restricted + }, adjusted_finalize, ignore_binding, ignore_import, @@ -642,11 +661,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(binding) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), - Err(ControlFlow::Break(Determinacy::Undetermined)) => { - return Err(ControlFlow::Break(Determinacy::determined(force))); + Err(ControlFlow::Break(determinacy)) => { + return Err(ControlFlow::Break(Determinacy::determined( + determinacy == Determinacy::Determined || force, + ))); } - // Privacy errors, do not happen during in scope resolution. - Err(ControlFlow::Break(Determinacy::Determined)) => unreachable!(), } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { @@ -680,13 +699,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude - && let Ok(binding) = self.reborrow().resolve_ident_in_module_unadjusted( - prelude, + && let Ok(binding) = self.reborrow().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, prelude), parent_scope, - Shadowing::Unrestricted, None, + false, ignore_binding, ignore_import, ) @@ -738,6 +756,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn maybe_push_ambiguity( &mut self, orig_ident: Ident, + ns: Namespace, + scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, binding: NameBinding<'ra>, scope: Scope<'ra>, @@ -751,6 +771,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: Use `scope` instead of `res` to detect built-in attrs and derive helpers, // it will exclude imports, make slightly more code legal, and will require lang approval. + let module_only = matches!(scope_set, ScopeSet::Module(..)); let is_builtin = |res| matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))); let derive_helper = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); let derive_helper_compat = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); @@ -781,9 +802,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } else if innermost_binding.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) - } else if innermost_binding.may_appear_after(parent_scope.expansion, binding) { + } else if !module_only + && innermost_binding.may_appear_after(parent_scope.expansion, binding) + { Some(AmbiguityKind::MoreExpandedVsOuter) } else if innermost_binding.expansion != LocalExpnId::ROOT + && (!module_only || ns == MacroNS) && let Scope::ModuleGlobs(m1, _) = scope && let Scope::ModuleNonGlobs(m2, _) = innermost_scope && m1 == m2 @@ -887,18 +911,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import: Option>, ) -> Result, Determinacy> { match module { - ModuleOrUniformRoot::Module(module) => self - .resolve_ident_in_module_unadjusted( - module, - ident, - ns, - parent_scope, - Shadowing::Unrestricted, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|determinacy| determinacy.into_value()), + ModuleOrUniformRoot::Module(module) => self.resolve_ident_in_scope_set( + ident, + ScopeSet::Module(ns, module), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ignore_import, + ), ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( ident, ScopeSet::ModuleAndExternPrelude(ns, module), @@ -948,48 +969,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Attempts to resolve `ident` in namespace `ns` of `module`. - fn resolve_ident_in_module_unadjusted<'r>( - mut self: CmResolver<'r, 'ra, 'tcx>, - module: Module<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - shadowing: Shadowing, - finalize: Option, - // This binding should be ignored during in-module resolution, so that we don't get - // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, - ignore_import: Option>, - ) -> Result, ControlFlow> { - let res = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( - module, - ident, - ns, - parent_scope, - shadowing, - finalize, - ignore_binding, - ignore_import, - ); - - match res { - Ok(_) | Err(ControlFlow::Break(_)) => return res, - Err(ControlFlow::Continue(_)) => {} - } - - self.resolve_ident_in_module_globs_unadjusted( - module, - ident, - ns, - parent_scope, - shadowing, - finalize, - ignore_binding, - ignore_import, - ) - } - /// Attempts to resolve `ident` in namespace `ns` of non-glob bindings in `module`. fn resolve_ident_in_module_non_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, @@ -999,6 +978,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, + // This binding should be ignored during in-module resolution, so that we don't get + // "self-confirming" import resolutions during import validation and checking. ignore_binding: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { @@ -1156,28 +1137,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => {} None => continue, }; - let result = self.reborrow().resolve_ident_in_module_unadjusted( - module, + let result = self.reborrow().resolve_ident_in_scope_set( ident, - ns, + ScopeSet::Module(ns, module), adjusted_parent_scope, - Shadowing::Unrestricted, None, + false, ignore_binding, ignore_import, ); match result { - Err(ControlFlow::Break(Determined) | ControlFlow::Continue(Determined)) => continue, + Err(Determined) => continue, Ok(binding) if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => { continue; } - Ok(_) - | Err(ControlFlow::Break(Undetermined) | ControlFlow::Continue(Undetermined)) => { - return Err(ControlFlow::Continue(Undetermined)); - } + Ok(_) | Err(Undetermined) => return Err(ControlFlow::Continue(Undetermined)), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd80f5da508c..290d21cad4b9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -44,8 +44,8 @@ use tracing::{debug, instrument, trace}; use crate::{ BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, - Used, errors, path_names_to_string, rustdoc, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, + UseError, Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1514,7 +1514,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_ns, &self.parent_scope, Some(source), - finalize, + finalize.map(|finalize| Finalize { stage: Stage::Late, ..finalize }), Some(&self.ribs), None, None, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fa53d57d175e..1d462f173f4d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -153,6 +153,8 @@ enum Scope<'ra> { enum ScopeSet<'ra> { /// All scopes with the given namespace. All(Namespace), + /// Two scopes inside a module, for non-glob and glob bindings. + Module(Namespace, Module<'ra>), /// A module, then extern prelude (used for mixed 2015-2018 mode in macros). ModuleAndExternPrelude(Namespace, Module<'ra>), /// Just two extern prelude scopes. From f841758cf5136bd982631e497df35ddc5f80521a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 11:04:27 +0100 Subject: [PATCH 087/340] Remove unnecessary `ConstLiteralRef` enum --- .../crates/hir-def/src/expr_store/lower.rs | 1 - .../crates/hir-def/src/hir/type_ref.rs | 58 +------- .../crates/hir-ty/src/consteval.rs | 131 ++++++++++++++---- .../rust-analyzer/crates/hir-ty/src/lower.rs | 24 +--- .../crates/hir-ty/src/next_solver/ty.rs | 18 +++ 5 files changed, 132 insertions(+), 100 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index af274f1a485b..d3774ded39dc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2319,7 +2319,6 @@ impl<'db> ExprCollector<'db> { ast::Pat::SlicePat(p) => { let SlicePatComponents { prefix, slice, suffix } = p.components(); - // FIXME properly handle `RestPat` Pat::Slice { prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), slice: slice.map(|p| self.collect_pat(p, binding_list)), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index ad8535413d67..b64199fa2697 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -1,8 +1,6 @@ //! HIR for references to types. Paths in these are not yet resolved. They can //! be directly created from an ast::TypeRef, without further queries. -use std::fmt::Write; - use hir_expand::name::Name; use intern::Symbol; use la_arena::Idx; @@ -10,12 +8,11 @@ use thin_vec::ThinVec; use crate::{ LifetimeParamId, TypeParamId, - builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{ ExpressionStore, path::{GenericArg, Path}, }, - hir::{ExprId, Literal}, + hir::ExprId, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -275,56 +272,3 @@ impl TypeBound { pub struct ConstRef { pub expr: ExprId, } - -/// A literal constant value -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LiteralConstRef { - Int(i128), - UInt(u128), - Bool(bool), - Char(char), - - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl LiteralConstRef { - pub fn builtin_type(&self) -> BuiltinType { - match self { - LiteralConstRef::UInt(_) | LiteralConstRef::Unknown => { - BuiltinType::Uint(BuiltinUint::U128) - } - LiteralConstRef::Int(_) => BuiltinType::Int(BuiltinInt::I128), - LiteralConstRef::Char(_) => BuiltinType::Char, - LiteralConstRef::Bool(_) => BuiltinType::Bool, - } - } -} - -impl From for LiteralConstRef { - fn from(literal: Literal) -> Self { - match literal { - Literal::Char(c) => Self::Char(c), - Literal::Bool(flag) => Self::Bool(flag), - Literal::Int(num, _) => Self::Int(num), - Literal::Uint(num, _) => Self::UInt(num), - _ => Self::Unknown, - } - } -} - -impl std::fmt::Display for LiteralConstRef { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - LiteralConstRef::Int(num) => num.fmt(f), - LiteralConstRef::UInt(num) => num.fmt(f), - LiteralConstRef::Bool(flag) => flag.fmt(f), - LiteralConstRef::Char(c) => write!(f, "'{c}'"), - LiteralConstRef::Unknown => f.write_char('_'), - } - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index f11240e0f78c..5bc2446fdd2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -7,9 +7,9 @@ use base_db::Crate; use hir_def::{ ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, attrs::AttrFlags, + builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::Body, - hir::{Expr, ExprId}, - type_ref::LiteralConstRef, + hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; use rustc_type_ir::inherent::IntoKind; @@ -23,7 +23,7 @@ use crate::{ mir::{MirEvalError, MirLowerError}, next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamEnv, StoredConst, StoredGenericArgs, Ty, ValueConst, + StoredConst, StoredGenericArgs, Ty, ValueConst, }, traits::StoredParamEnvAndCrate, }; @@ -81,47 +81,122 @@ impl From for ConstEvalError { /// Interns a constant scalar with the given type pub fn intern_const_ref<'a>( db: &'a dyn HirDatabase, - value: &LiteralConstRef, + value: &Literal, ty: Ty<'a>, - krate: Crate, + _krate: Crate, ) -> Const<'a> { let interner = DbInterner::new_no_crate(db); - let layout = db - .layout_of_ty(ty.store(), ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }.store()); let kind = match value { - LiteralConstRef::Int(i) => { - // FIXME: We should handle failure of layout better. - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Uint(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Uint) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::UInt(i) => { - let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); + &Literal::Int(i, None) + if ty + .as_builtin() + .is_some_and(|builtin_ty| matches!(builtin_ty, BuiltinType::Uint(_))) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Uint(builtin_uint)) => match builtin_uint { + BuiltinUint::U8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()), + BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()), + BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()), + BuiltinUint::U128 => Box::new((i as u128).to_le_bytes()), + BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; rustc_type_ir::ConstKind::Value(ValueConst::new( ty, - ConstBytes { - memory: i.to_le_bytes()[0..size].into(), - memory_map: MemoryMap::default(), - }, + ConstBytes { memory, memory_map: MemoryMap::default() }, )) } - LiteralConstRef::Bool(b) => rustc_type_ir::ConstKind::Value(ValueConst::new( + &Literal::Int(i, builtin_ty) + if builtin_ty.is_none() || ty.as_builtin() == builtin_ty.map(BuiltinType::Int) => + { + let memory = match ty.as_builtin() { + Some(BuiltinType::Int(builtin_int)) => match builtin_int { + BuiltinInt::I8 => Box::new([i as u8]) as Box<[u8]>, + BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()), + BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()), + BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()), + BuiltinInt::I128 => Box::new((i).to_le_bytes()), + BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()), + }, + _ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Float(float_type_wrapper, builtin_float) + if builtin_float.is_none() + || ty.as_builtin() == builtin_float.map(BuiltinType::Float) => + { + let memory = match ty.as_builtin().unwrap() { + BuiltinType::Float(builtin_float) => match builtin_float { + // FIXME: + hir_def::builtin_type::BuiltinFloat::F16 => Box::new([0u8; 2]) as Box<[u8]>, + hir_def::builtin_type::BuiltinFloat::F32 => { + Box::new(float_type_wrapper.to_f32().to_le_bytes()) + } + hir_def::builtin_type::BuiltinFloat::F64 => { + Box::new(float_type_wrapper.to_f64().to_le_bytes()) + } + // FIXME: + hir_def::builtin_type::BuiltinFloat::F128 => Box::new([0; 16]), + }, + _ => unreachable!(), + }; + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory, memory_map: MemoryMap::default() }, + )) + } + Literal::Bool(b) if ty.is_bool() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: Box::new([*b as u8]), memory_map: MemoryMap::default() }, )), - LiteralConstRef::Char(c) => rustc_type_ir::ConstKind::Value(ValueConst::new( + Literal::Char(c) if ty.is_char() => rustc_type_ir::ConstKind::Value(ValueConst::new( ty, ConstBytes { memory: (*c as u32).to_le_bytes().into(), memory_map: MemoryMap::default(), }, )), - LiteralConstRef::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + Literal::String(symbol) if ty.is_str() => rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { + memory: symbol.as_str().as_bytes().into(), + memory_map: MemoryMap::default(), + }, + )), + Literal::ByteString(items) if ty.as_slice().is_some_and(|ty| ty.is_u8()) => { + rustc_type_ir::ConstKind::Value(ValueConst::new( + ty, + ConstBytes { memory: items.clone(), memory_map: MemoryMap::default() }, + )) + } + // FIXME + Literal::CString(_items) => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + _ => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), }; Const::new(interner, kind) } @@ -130,7 +205,15 @@ pub fn intern_const_ref<'a>( pub fn usize_const<'db>(db: &'db dyn HirDatabase, value: Option, krate: Crate) -> Const<'db> { intern_const_ref( db, - &value.map_or(LiteralConstRef::Unknown, LiteralConstRef::UInt), + &match value { + Some(value) => Literal::Uint(value, Some(BuiltinUint::Usize)), + None => { + return Const::new( + DbInterner::new_no_crate(db), + rustc_type_ir::ConstKind::Error(ErrorGuaranteed), + ); + } + }, Ty::new_uint(DbInterner::new_no_crate(db), rustc_type_ir::UintTy::Usize), krate, ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..6688cf3d6025 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -27,8 +27,8 @@ use hir_def::{ resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, - TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, + ConstRef, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, }, }; use hir_expand::name::Name; @@ -281,21 +281,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { hir_def::hir::Expr::Path(path) => { self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } - hir_def::hir::Expr::Literal(literal) => intern_const_ref( - self.db, - &match *literal { - hir_def::hir::Literal::Float(_, _) - | hir_def::hir::Literal::String(_) - | hir_def::hir::Literal::ByteString(_) - | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown, - hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c), - hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b), - hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val), - hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val), - }, - const_type, - self.resolver.krate(), - ), + hir_def::hir::Expr::Literal(literal) => { + intern_const_ref(self.db, literal, const_type, self.resolver.krate()) + } hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => { if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] { // Only handle negation for signed integers and floats @@ -304,7 +292,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { if let Some(negated_literal) = literal.clone().negate() { intern_const_ref( self.db, - &negated_literal.into(), + &negated_literal, const_type, self.resolver.krate(), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 030ba37015f2..66a24d394990 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -383,6 +383,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Bool) } + #[inline] + pub fn is_char(self) -> bool { + matches!(self.kind(), TyKind::Char) + } + /// A scalar type is one that denotes an atomic datum, with no sub-components. /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) @@ -422,6 +427,11 @@ impl<'db> Ty<'db> { matches!(self.kind(), TyKind::Tuple(tys) if tys.is_empty()) } + #[inline] + pub fn is_u8(self) -> bool { + matches!(self.kind(), TyKind::Uint(UintTy::U8)) + } + #[inline] pub fn is_raw_ptr(self) -> bool { matches!(self.kind(), TyKind::RawPtr(..)) @@ -456,6 +466,14 @@ impl<'db> Ty<'db> { } } + #[inline] + pub fn as_slice(self) -> Option> { + match self.kind() { + TyKind::Slice(ty) => Some(ty), + _ => None, + } + } + #[inline] pub fn ty_vid(self) -> Option { match self.kind() { From 0016a7174768082ea50187847e86b288ec28281a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 5 Dec 2025 16:31:04 +0300 Subject: [PATCH 088/340] resolve: Migrate one more special ambiguity for glob vs non-glob bindings in the same module to the usual ambiguity infra in `resolve_ident_in_scope_set` --- compiler/rustc_resolve/src/ident.rs | 3 +- compiler/rustc_resolve/src/imports.rs | 15 +----- .../ambiguous-glob-vs-expanded-extern.rs | 4 +- .../ambiguous-glob-vs-expanded-extern.stderr | 53 ------------------- tests/ui/imports/issue-114682-1.rs | 1 - tests/ui/imports/issue-114682-1.stderr | 27 +--------- .../local-modularized-tricky-fail-1.rs | 1 - .../local-modularized-tricky-fail-1.stderr | 31 ++--------- tests/ui/imports/macros.rs | 2 +- tests/ui/imports/macros.stderr | 21 +------- 10 files changed, 11 insertions(+), 147 deletions(-) delete mode 100644 tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 82a87b8a9ed6..512b35310539 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -813,7 +813,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && m1 == m2 { // FIXME: this error is too conservative and technically unnecessary now when module - // scope is split into two scopes, remove it with lang team approval. + // scope is split into two scopes, at least when not resolving in `ScopeSet::Module`, + // remove it with lang team approval. Some(AmbiguityKind::GlobVsExpanded) } else { None diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4e0f3db59821..a46ed5d8e69e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -389,20 +389,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if ns == MacroNS - && non_glob_binding.expansion != LocalExpnId::ROOT - && glob_binding.res() != non_glob_binding.res() - { - resolution.non_glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsExpanded, - non_glob_binding, - glob_binding, - false, - )); - } else { - resolution.non_glob_binding = Some(non_glob_binding); - } - + resolution.non_glob_binding = Some(non_glob_binding); if let Some(old_glob_binding) = resolution.glob_binding { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs index de632119ecba..0277da46f750 100644 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs +++ b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.rs @@ -1,6 +1,6 @@ +//@ check-pass //@ aux-crate: glob_vs_expanded=glob-vs-expanded.rs fn main() { - glob_vs_expanded::mac!(); //~ ERROR `mac` is ambiguous - //~| WARN this was previously accepted + glob_vs_expanded::mac!(); // OK } diff --git a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr b/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr deleted file mode 100644 index 4a9a6c99819b..000000000000 --- a/tests/ui/imports/ambiguous-glob-vs-expanded-extern.stderr +++ /dev/null @@ -1,53 +0,0 @@ -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: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 - | -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: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 - | -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/issue-114682-1.rs b/tests/ui/imports/issue-114682-1.rs index 58b78508026d..88fe05e51444 100644 --- a/tests/ui/imports/issue-114682-1.rs +++ b/tests/ui/imports/issue-114682-1.rs @@ -22,5 +22,4 @@ mac!(); fn main() { A!(); //~^ ERROR `A` is ambiguous - //~| ERROR `A` is ambiguous } diff --git a/tests/ui/imports/issue-114682-1.stderr b/tests/ui/imports/issue-114682-1.stderr index de8dc6cfb9ff..fd2776f50ad7 100644 --- a/tests/ui/imports/issue-114682-1.stderr +++ b/tests/ui/imports/issue-114682-1.stderr @@ -1,28 +1,3 @@ -error[E0659]: `A` is ambiguous - --> $DIR/issue-114682-1.rs:23:5 - | -LL | A!(); - | ^ ambiguous name - | - = 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: `A` could refer to the macro defined here - --> $DIR/issue-114682-1.rs:7:9 - | -LL | / pub macro A() { -LL | | println!("non import") -LL | | } - | |_________^ -... -LL | mac!(); - | ------ in this macro invocation -note: `A` could also refer to the macro imported here - --> $DIR/issue-114682-1.rs:19:9 - | -LL | pub use m::*; - | ^^^^ - = help: consider adding an explicit import of `A` to disambiguate - = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0659]: `A` is ambiguous --> $DIR/issue-114682-1.rs:23:5 | @@ -49,6 +24,6 @@ LL | pub use m::*; = help: use `crate::A` to refer to this macro unambiguously = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.rs b/tests/ui/imports/local-modularized-tricky-fail-1.rs index bba26ee43a24..ce700ae0de9b 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.rs +++ b/tests/ui/imports/local-modularized-tricky-fail-1.rs @@ -27,7 +27,6 @@ mod inner1 { } exported!(); //~ ERROR `exported` is ambiguous - //~| ERROR `exported` is ambiguous mod inner2 { define_exported!(); diff --git a/tests/ui/imports/local-modularized-tricky-fail-1.stderr b/tests/ui/imports/local-modularized-tricky-fail-1.stderr index 54d928f7c812..b5b3be5953f9 100644 --- a/tests/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/tests/ui/imports/local-modularized-tricky-fail-1.stderr @@ -1,28 +1,3 @@ -error[E0659]: `exported` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:29:1 - | -LL | exported!(); - | ^^^^^^^^ ambiguous name - | - = 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: `exported` could refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:6:5 - | -LL | / macro_rules! exported { -LL | | () => () -LL | | } - | |_____^ -... -LL | define_exported!(); - | ------------------ in this macro invocation -note: `exported` could also refer to the macro imported here - --> $DIR/local-modularized-tricky-fail-1.rs:23:5 - | -LL | use inner1::*; - | ^^^^^^^^^ - = help: consider adding an explicit import of `exported` to disambiguate - = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0659]: `exported` is ambiguous --> $DIR/local-modularized-tricky-fail-1.rs:29:1 | @@ -50,7 +25,7 @@ LL | use inner1::*; = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:37:5 + --> $DIR/local-modularized-tricky-fail-1.rs:36:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -71,7 +46,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:48:1 + --> $DIR/local-modularized-tricky-fail-1.rs:47:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -91,6 +66,6 @@ LL | define_include!(); = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/imports/macros.rs b/tests/ui/imports/macros.rs index cf67e08c87a3..e1db42abd28f 100644 --- a/tests/ui/imports/macros.rs +++ b/tests/ui/imports/macros.rs @@ -13,7 +13,7 @@ mod m1 { mod m2 { use two_macros::*; - m! { //~ ERROR ambiguous + m! { use crate::foo::m; } } diff --git a/tests/ui/imports/macros.stderr b/tests/ui/imports/macros.stderr index 25a678c6b375..08ebfa5b8151 100644 --- a/tests/ui/imports/macros.stderr +++ b/tests/ui/imports/macros.stderr @@ -1,22 +1,3 @@ -error[E0659]: `m` is ambiguous - --> $DIR/macros.rs:16:5 - | -LL | m! { - | ^ ambiguous name - | - = 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: `m` could refer to the macro imported here - --> $DIR/macros.rs:17:13 - | -LL | use crate::foo::m; - | ^^^^^^^^^^^^^ -note: `m` could also refer to the macro imported here - --> $DIR/macros.rs:15:9 - | -LL | use two_macros::*; - | ^^^^^^^^^^^^^ - = help: consider adding an explicit import of `m` to disambiguate - error[E0659]: `m` is ambiguous --> $DIR/macros.rs:29:9 | @@ -36,6 +17,6 @@ LL | use two_macros::m; | ^^^^^^^^^^^^^ = help: use `self::m` to refer to this macro unambiguously -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0659`. From 78c61beb4816a9f103429da9a5cf49eeb6610ec9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 5 Dec 2025 17:47:02 +0300 Subject: [PATCH 089/340] resolve: Patch up an inconsistent resolution ICE revealed by the previous commit --- compiler/rustc_resolve/src/ident.rs | 8 ++++++++ tests/ui/imports/macros.rs | 2 +- tests/ui/imports/macros.stderr | 22 +++++++++++++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 512b35310539..f400ae8f6439 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1249,6 +1249,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { + if let Some(binding) = resolution.non_glob_binding + && let NameBindingKind::Import { import, .. } = binding.kind + && import == *single_import + { + // Single import has already defined the name and we are aware of it, + // no need to block the globs. + continue; + } if ignore_import == Some(*single_import) { continue; } diff --git a/tests/ui/imports/macros.rs b/tests/ui/imports/macros.rs index e1db42abd28f..121f1f7ae043 100644 --- a/tests/ui/imports/macros.rs +++ b/tests/ui/imports/macros.rs @@ -13,7 +13,7 @@ mod m1 { mod m2 { use two_macros::*; - m! { + m! { //~ ERROR `m` is ambiguous use crate::foo::m; } } diff --git a/tests/ui/imports/macros.stderr b/tests/ui/imports/macros.stderr index 08ebfa5b8151..9c081cc7af8b 100644 --- a/tests/ui/imports/macros.stderr +++ b/tests/ui/imports/macros.stderr @@ -1,3 +1,23 @@ +error[E0659]: `m` is ambiguous + --> $DIR/macros.rs:16:5 + | +LL | m! { + | ^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `m` could refer to the macro imported here + --> $DIR/macros.rs:17:13 + | +LL | use crate::foo::m; + | ^^^^^^^^^^^^^ + = help: use `self::m` to refer to this macro unambiguously +note: `m` could also refer to the macro imported here + --> $DIR/macros.rs:15:9 + | +LL | use two_macros::*; + | ^^^^^^^^^^^^^ + = help: use `self::m` to refer to this macro unambiguously + error[E0659]: `m` is ambiguous --> $DIR/macros.rs:29:9 | @@ -17,6 +37,6 @@ LL | use two_macros::m; | ^^^^^^^^^^^^^ = help: use `self::m` to refer to this macro unambiguously -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From 2e123aef706ac12e1277b90c933055d0b4b79d9b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 Jan 2026 14:29:23 +0300 Subject: [PATCH 090/340] resolve: Avoid additional ambiguities from splitting modules into two scopes --- compiler/rustc_resolve/src/ident.rs | 15 ++++++++++++- tests/ui/imports/overwritten-glob-ambig.rs | 26 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/overwritten-glob-ambig.rs diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f400ae8f6439..c9f560d2a6fa 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -828,8 +828,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && innermost_results[1..].iter().any(|(b, s)| { matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding }); + // Skip ambiguity errors for nonglob module bindings "overridden" + // by glob module bindings in the same module. + // FIXME: Remove with lang team approval. + let issue_149681_hack = match scope { + Scope::ModuleGlobs(m1, _) + if innermost_results[1..] + .iter() + .any(|(_, s)| matches!(*s, Scope::ModuleNonGlobs(m2, _) if m1 == m2)) => + { + true + } + _ => false, + }; - if issue_145575_hack { + if issue_145575_hack || issue_149681_hack { self.issue_145575_hack_applied = true; } else { self.ambiguity_errors.push(AmbiguityError { diff --git a/tests/ui/imports/overwritten-glob-ambig.rs b/tests/ui/imports/overwritten-glob-ambig.rs new file mode 100644 index 000000000000..a5918568c62a --- /dev/null +++ b/tests/ui/imports/overwritten-glob-ambig.rs @@ -0,0 +1,26 @@ +// Test for a regression introduced by splitting module scope into two scopes +// (similar to issue #145575). + +//@ check-pass +//@ edition: 2018.. + +#[macro_use] +mod one { + // Macro that is in a different module, but still in scope due to `macro_use` + macro_rules! mac { () => {} } + pub(crate) use mac; +} + +mod other { + macro_rules! mac { () => {} } + pub(crate) use mac; +} + +// Single import of the same in the current module. +use one::mac; +// Glob import of a different macro in the current module (should be an ambiguity). +use other::*; + +fn main() { + mac!(); // OK for now, the ambiguity is not reported +} From 3f3db936514dca81c1e6ca6d004da9921450d981 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 Jan 2026 15:40:21 +0300 Subject: [PATCH 091/340] metadata: Stop keeping `AmbiguityKind` in name bindings It can only be `GlobVsGlob` now. --- compiler/rustc_middle/src/metadata.rs | 7 ----- .../rustc_resolve/src/build_reduced_graph.rs | 22 ++++++--------- compiler/rustc_resolve/src/imports.rs | 28 ++++++------------- compiler/rustc_resolve/src/lib.rs | 10 +++---- 4 files changed, 22 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index 2b0be9865799..b7848bc261d8 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -45,16 +45,9 @@ pub struct ModChild { 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_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index b9c945a440f8..241c13663ae5 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::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; -use rustc_middle::metadata::{AmbigModChildKind, ModChild, Reexport}; +use rustc_middle::metadata::{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::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - AmbiguityKind, BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - ResolutionError, Resolver, Segment, Used, VisResolutionError, errors, + BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, + Resolver, Segment, Used, VisResolutionError, errors, }; type Res = def::Res; @@ -82,7 +82,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: Visibility, span: Span, expansion: LocalExpnId, - ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, + ambiguity: Option>, ) { let binding = self.arenas.alloc_name_binding(NameBindingData { kind: NameBindingKind::Res(res), @@ -254,7 +254,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &child.main, parent_scope, children.len() + i, - Some((&child.second, child.kind)), + Some(&child.second), ) } } @@ -265,7 +265,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { child: &ModChild, parent_scope: ParentScope<'ra>, child_index: usize, - ambig_child: Option<(&ModChild, AmbigModChildKind)>, + ambig_child: Option<&ModChild>, ) { let parent = parent_scope.module; let child_span = |this: &Self, reexport_chain: &[Reexport], res: def::Res<_>| { @@ -280,15 +280,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { 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 ambig = ambig_child.map(|ambig_child| { 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) + self.arenas.new_res_binding(res, vis, span, expansion) }); // Record primary definitions. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a46ed5d8e69e..558f769eda19 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -9,7 +9,7 @@ use rustc_errors::codes::*; 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::{AmbigModChild, AmbigModChildKind, ModChild, Reexport}; +use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; @@ -32,10 +32,9 @@ use crate::errors::{ }; use crate::ref_mut::CmCell; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, - Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, - PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, - names_to_string, + AmbiguityError, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, + ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, + PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res; @@ -373,7 +372,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.glob_binding = Some(glob_binding); } else if res != old_glob_binding.res() { resolution.glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, old_glob_binding, glob_binding, warn_ambiguity, @@ -394,7 +392,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { resolution.glob_binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, old_glob_binding, glob_binding, false, @@ -424,12 +421,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn new_ambiguity_binding( &self, - ambiguity_kind: AmbiguityKind, primary_binding: NameBinding<'ra>, secondary_binding: NameBinding<'ra>, warn_ambiguity: bool, ) -> NameBinding<'ra> { - let ambiguity = Some((secondary_binding, ambiguity_kind)); + let ambiguity = Some(secondary_binding); let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; self.arenas.alloc_name_binding(data) } @@ -645,7 +641,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(binding) = resolution.best_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity + && let Some(amb_binding) = binding.ambiguity && binding.res() != Res::Err && exported_ambiguities.contains(&binding) { @@ -1553,9 +1549,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: binding.vis, reexport_chain, }; - if let Some((ambig_binding1, ambig_binding2, ambig_kind)) = - binding.descent_to_ambiguity() - { + if let Some((ambig_binding1, ambig_binding2)) = binding.descent_to_ambiguity() { let main = child(ambig_binding1.reexport_chain(this)); let second = ModChild { ident: ident.0, @@ -1563,13 +1557,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { 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!(), - }; - - ambig_children.push(AmbigModChild { main, second, kind }) + ambig_children.push(AmbigModChild { main, second }) } else { children.push(child(binding.reexport_chain(this))); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1d462f173f4d..fbd16072c2c0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -807,7 +807,7 @@ impl<'ra> fmt::Debug for Module<'ra> { #[derive(Clone, Copy, Debug)] struct NameBindingData<'ra> { kind: NameBindingKind<'ra>, - ambiguity: Option<(NameBinding<'ra>, AmbiguityKind)>, + ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, @@ -937,9 +937,9 @@ impl<'ra> NameBindingData<'ra> { fn descent_to_ambiguity( self: NameBinding<'ra>, - ) -> Option<(NameBinding<'ra>, NameBinding<'ra>, AmbiguityKind)> { + ) -> Option<(NameBinding<'ra>, NameBinding<'ra>)> { match self.ambiguity { - Some((ambig_binding, ambig_kind)) => Some((self, ambig_binding, ambig_kind)), + Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { NameBindingKind::Import { binding, .. } => binding.descent_to_ambiguity(), _ => None, @@ -2064,9 +2064,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { used: Used, warn_ambiguity: bool, ) { - if let Some((b2, kind)) = used_binding.ambiguity { + if let Some(b2) = used_binding.ambiguity { let ambiguity_error = AmbiguityError { - kind, + kind: AmbiguityKind::GlobVsGlob, ident, b1: used_binding, b2, From 8d5a7b685e63fe8e313da974b7e5b70117db1680 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Jan 2026 13:16:21 +0100 Subject: [PATCH 092/340] Reduce `impl_signature` query dependencies in method resolution --- .../crates/hir-def/src/item_scope.rs | 16 ++++++++++++---- .../crates/hir-def/src/item_tree.rs | 4 +++- .../crates/hir-def/src/item_tree/lower.rs | 2 +- .../crates/hir-def/src/item_tree/pretty.rs | 2 +- .../crates/hir-def/src/lang_item.rs | 2 +- .../crates/hir-def/src/nameres/collector.rs | 4 +++- .../crates/hir-ty/src/method_resolution.rs | 9 ++------- .../crates/hir-ty/src/tests/incremental.rs | 18 ++++++------------ src/tools/rust-analyzer/crates/hir/src/lib.rs | 11 +++++------ .../ide-completion/src/tests/flyimport.rs | 4 ++-- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 9e7868b273ef..a3278dd76c86 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -158,7 +158,7 @@ pub struct ItemScope { /// declared. declarations: ThinVec, - impls: ThinVec, + impls: ThinVec<(ImplId, /* trait impl */ bool)>, builtin_derive_impls: ThinVec, extern_blocks: ThinVec, unnamed_consts: ThinVec, @@ -327,7 +327,15 @@ impl ItemScope { } pub fn impls(&self) -> impl ExactSizeIterator + '_ { - self.impls.iter().copied() + self.impls.iter().map(|&(id, _)| id) + } + + pub fn trait_impls(&self) -> impl Iterator + '_ { + self.impls.iter().filter(|&&(_, is_trait_impl)| is_trait_impl).map(|&(id, _)| id) + } + + pub fn inherent_impls(&self) -> impl Iterator + '_ { + self.impls.iter().filter(|&&(_, is_trait_impl)| !is_trait_impl).map(|&(id, _)| id) } pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator + '_ { @@ -472,8 +480,8 @@ impl ItemScope { self.legacy_macros.get(name).map(|it| &**it) } - pub(crate) fn define_impl(&mut self, imp: ImplId) { - self.impls.push(imp); + pub(crate) fn define_impl(&mut self, imp: ImplId, is_trait_impl: bool) { + self.impls.push((imp, is_trait_impl)); } pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 2e838fad2e9f..a1707f17beb0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -614,7 +614,9 @@ pub struct Trait { } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct Impl {} +pub struct Impl { + pub is_trait_impl: bool, +} #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeAlias { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index d8519f7393df..3f19e001548e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -271,7 +271,7 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(impl_def); // Note that trait impls don't get implicit `Self` unlike traits, because here they are a // type alias rather than a type parameter, so this is handled by the resolver. - let res = Impl {}; + let res = Impl { is_trait_impl: impl_def.trait_().is_some() }; self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res)); ast_id } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index c89299e6d863..4113a778eaaf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -258,7 +258,7 @@ impl Printer<'_> { w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition)); } ModItemId::Impl(ast_id) => { - let Impl {} = &self.tree[ast_id]; + let Impl { is_trait_impl: _ } = &self.tree[ast_id]; self.print_ast_id(ast_id.erase()); w!(self, "impl {{ ... }}"); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 41d69c1fd624..d3f4480b207e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -41,7 +41,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option { let impl_id = ImplLoc { container: module_id, id: InFile::new(self.file_id(), imp) } .intern(db); - self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) + self.def_collector.def_map.modules[self.module_id] + .scope + .define_impl(impl_id, self.item_tree[imp].is_trait_impl) } ModItemId::Function(id) => { let it = &self.item_tree[id]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 3d7cc4ffbf8a..e4681b464fec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -609,12 +609,7 @@ impl InherentImpls { map: &mut FxHashMap>, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { - let data = db.impl_signature(impl_id); - if data.target_trait.is_some() { - continue; - } - + for impl_id in module_data.scope.inherent_impls() { let interner = DbInterner::new_no_crate(db); let self_ty = db.impl_self_ty(impl_id); let self_ty = self_ty.instantiate_identity(); @@ -730,7 +725,7 @@ impl TraitImpls { map: &mut FxHashMap, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { + for impl_id in module_data.scope.trait_impls() { let trait_ref = match db.impl_trait(impl_id) { Some(tr) => tr.instantiate_identity(), None => continue, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 633ab43c4cec..118f433a24e6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -539,12 +539,6 @@ impl SomeStruct { "AttrFlags::query_", "AttrFlags::query_", "AttrFlags::query_", - "impl_trait_with_diagnostics_query", - "impl_signature_shim", - "impl_signature_with_source_map_shim", - "impl_self_ty_with_diagnostics_query", - "struct_signature_shim", - "struct_signature_with_source_map_shim", ] "#]], ); @@ -617,7 +611,6 @@ fn main() { "lang_items", "crate_lang_items", "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -633,13 +626,14 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "value_ty_query", "InherentImpls::for_crate_", - "impl_signature_shim", - "impl_signature_with_source_map_shim", "callable_item_signature_query", "TraitImpls::for_crate_and_deps_", "TraitImpls::for_crate_", "impl_trait_with_diagnostics_query", + "impl_signature_shim", + "impl_signature_with_source_map_shim", "impl_self_ty_with_diagnostics_query", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", ] "#]], @@ -710,7 +704,6 @@ fn main() { "crate_lang_items", "AttrFlags::query_", "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -722,12 +715,13 @@ fn main() { "struct_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", - "impl_signature_with_source_map_shim", - "impl_signature_shim", "callable_item_signature_query", "TraitImpls::for_crate_", + "impl_signature_with_source_map_shim", + "impl_signature_shim", "impl_trait_with_diagnostics_query", "impl_self_ty_with_diagnostics_query", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", ] "#]], diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ab57c4489cf..527614d56a01 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -803,22 +803,21 @@ impl Module { emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db)); } - if impl_signature.target_trait.is_none() - && !is_inherent_impl_coherent(db, def_map, impl_id) - { + let trait_impl = impl_signature.target_trait.is_some(); + if !trait_impl && !is_inherent_impl_coherent(db, def_map, impl_id) { acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } - if !impl_def.check_orphan_rules(db) { + if trait_impl && !impl_def.check_orphan_rules(db) { acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } - let trait_ = impl_def.trait_(db); + let trait_ = trait_impl.then(|| impl_def.trait_(db)).flatten(); let mut trait_is_unsafe = trait_.is_some_and(|t| t.is_unsafe(db)); let impl_is_negative = impl_def.is_negative(db); let impl_is_unsafe = impl_def.is_unsafe(db); - let trait_is_unresolved = trait_.is_none() && impl_signature.target_trait.is_some(); + let trait_is_unresolved = trait_.is_none() && trait_impl; if trait_is_unresolved { // Ignore trait safety errors when the trait is unresolved, as otherwise we'll treat it as safe, // which may not be correct. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index aad881f8ce4f..2912457da1f7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -781,9 +781,9 @@ fn main() { } "#, expect![[r#" - fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED - ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED + ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED + fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED "#]], ); } From 7e425b898540c51f73f152a353e5a138ae8602eb Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Fri, 2 Jan 2026 16:05:42 +0100 Subject: [PATCH 093/340] Add specialization for `deque1.prepend(deque2.drain(range))` This is used when moving elements between `VecDeque`s This pattern is also used in examples of `VecDeque::prepend`. (see its docs) --- .../alloc/src/collections/vec_deque/drain.rs | 6 +- .../src/collections/vec_deque/spec_extend.rs | 78 +++++++++++-- library/alloctests/tests/vec_deque.rs | 110 ++++++++++++++++++ 3 files changed, 180 insertions(+), 14 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index eee7be674c95..a43853604a2d 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -25,10 +25,10 @@ pub struct Drain< // drain_start is stored in deque.len pub(super) drain_len: usize, // index into the logical array, not the physical one (always lies in [0..deque.len)) - idx: usize, + pub(super) idx: usize, // number of elements after the drained range pub(super) tail_len: usize, - remaining: usize, + pub(super) remaining: usize, // Needed to make Drain covariant over T _marker: PhantomData<&'a T>, } @@ -53,7 +53,7 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> { // Only returns pointers to the slices, as that's all we need // to drop them. May only be called if `self.remaining != 0`. - unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) { + pub(super) unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) { unsafe { let deque = self.deque.as_ref(); diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index f73ba795cbea..4ef854e8b327 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -1,7 +1,7 @@ use core::iter::{Copied, Rev, TrustedLen}; use core::slice; -use super::VecDeque; +use super::{Drain, VecDeque}; use crate::alloc::Allocator; #[cfg(not(test))] use crate::vec; @@ -157,7 +157,8 @@ impl SpecExtendFront> for VecDeque { #[track_caller] fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); - // SAFETY: elements in the slice are forgotten after this call + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call unsafe { prepend_reversed(self, slice) }; iterator.forget_remaining_elements(); } @@ -169,7 +170,8 @@ impl SpecExtendFront>> for VecDeque>) { let mut iterator = iterator.into_inner(); let slice = iterator.as_slice(); - // SAFETY: elements in the slice are forgotten after this call + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and elements in the slice are forgotten after this call unsafe { prepend(self, slice) }; iterator.forget_remaining_elements(); } @@ -182,7 +184,8 @@ where #[track_caller] fn spec_extend_front(&mut self, iter: Copied>) { let slice = iter.into_inner().as_slice(); - // SAFETY: T is Copy because Copied> is Iterator + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and T is Copy because Copied> is Iterator unsafe { prepend_reversed(self, slice) }; } } @@ -194,17 +197,69 @@ where #[track_caller] fn spec_extend_front(&mut self, iter: Rev>>) { let slice = iter.into_inner().into_inner().as_slice(); - // SAFETY: T is Copy because Rev>> is Iterator + self.reserve(slice.len()); + // SAFETY: `slice.len()` space was just reserved and T is Copy because Rev>> is Iterator unsafe { prepend(self, slice) }; } } +impl<'a, T, A1: Allocator, A2: Allocator> SpecExtendFront> for VecDeque { + #[track_caller] + fn spec_extend_front(&mut self, mut iter: Drain<'a, T, A2>) { + if iter.remaining == 0 { + return; + } + + self.reserve(iter.remaining); + unsafe { + // SAFETY: iter.remaining != 0. + let (left, right) = iter.as_slices(); + // SAFETY: + // - `iter.remaining` space was reserved, `iter.remaining == left.len() + right.len()`. + // - The elements in `left` and `right` are forgotten after these calls. + prepend_reversed(self, &*left); + prepend_reversed(self, &*right); + } + + iter.idx += iter.remaining; + iter.remaining = 0; + } +} + +impl<'a, T, A1: Allocator, A2: Allocator> SpecExtendFront>> + for VecDeque +{ + #[track_caller] + fn spec_extend_front(&mut self, iter: Rev>) { + let mut iter = iter.into_inner(); + + if iter.remaining == 0 { + return; + } + + self.reserve(iter.remaining); + unsafe { + // SAFETY: iter.remaining != 0. + let (left, right) = iter.as_slices(); + // SAFETY: + // - `iter.remaining` space was reserved, `iter.remaining == left.len() + right.len()`. + // - The elements in `left` and `right` are forgotten after these calls. + prepend(self, &*right); + prepend(self, &*left); + } + + iter.idx += iter.remaining; + iter.remaining = 0; + } +} + +/// Prepends elements of `slice` to `deque` using a copy. +/// /// # Safety /// -/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. +/// - `deque` must have space for `slice.len()` new elements. +/// - Elements of `slice` will be copied into the deque, make sure to forget the elements if `T` is not `Copy`. unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { - deque.reserve(slice.len()); - unsafe { deque.head = deque.wrap_sub(deque.head, slice.len()); deque.copy_slice(deque.head, slice); @@ -212,12 +267,13 @@ unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { } } +/// Prepends elements of `slice` to `deque` in reverse order using a copy. +/// /// # Safety /// -/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. +/// - `deque` must have space for `slice.len()` new elements. +/// - Elements of `slice` will be copied into the deque, make sure to forget the elements if `T` is not `Copy`. unsafe fn prepend_reversed(deque: &mut VecDeque, slice: &[T]) { - deque.reserve(slice.len()); - unsafe { deque.head = deque.wrap_sub(deque.head, slice.len()); deque.copy_slice_reversed(deque.head, slice); diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 82803c7a0dab..e9f860f8df9b 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -2156,6 +2156,116 @@ fn test_extend_front_specialization_copy_slice() { assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice())); } +#[test] +fn test_extend_front_specialization_deque_drain() { + // trigger 8 code paths: all combinations of prepend and extend_front, wrap and no wrap (src deque), wrap and no wrap (dst deque) + + /// Get deque containing `[1, 2, 3, 4]`, possibly wrapping in the middle (between the 2 and 3). + fn test_deque(wrap: bool) -> VecDeque { + if wrap { + let mut v = VecDeque::with_capacity(4); + v.extend([3, 4]); + v.prepend([1, 2]); + assert_eq!(v.as_slices(), ([1, 2].as_slice(), [3, 4].as_slice())); + v + } else { + VecDeque::from([1, 2, 3, 4]) + } + } + + // prepend, v2.head == 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(false); + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [1, 2, 3, 4]); + v1.pop_back(); + + let mut v2 = test_deque(false); + // this should wrap around the physical buffer + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([1].as_slice(), [2, 3, 4, 1, 2, 3].as_slice())); + + // extend_front, v2.head == 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(false); + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [4, 3, 2, 1]); + v1.pop_back(); + + let mut v2 = test_deque(false); + // this should wrap around the physical buffer + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([4].as_slice(), [3, 2, 1, 4, 3, 2].as_slice())); + + // prepend, v2.head != 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(true); + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [1, 2, 3, 4]); + v1.pop_back(); + + let mut v2 = test_deque(true); + // this should wrap around the physical buffer + v1.prepend(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([1].as_slice(), [2, 3, 4, 1, 2, 3].as_slice())); + + // extend_front, v2.head != 0 + + let mut v1 = VecDeque::with_capacity(7); + + let mut v2 = test_deque(true); + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + assert_eq!(v1, [4, 3, 2, 1]); + v1.pop_back(); + + let mut v2 = test_deque(true); + // this should wrap around the physical buffer + v1.extend_front(v2.drain(..)); + // drain removes all elements but keeps the buffer + assert_eq!(v2, []); + assert!(v2.capacity() >= 4); + + // check it really wrapped + assert_eq!(v1.as_slices(), ([4].as_slice(), [3, 2, 1, 4, 3, 2].as_slice())); +} + #[test] fn test_splice() { let mut v = VecDeque::from(vec![1, 2, 3, 4, 5]); From 9a170fedd792b3373ddf7b512cff0b1463ee30e0 Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Fri, 2 Jan 2026 16:15:40 +0100 Subject: [PATCH 094/340] make specialization of Vec::extend and VecDeque::extend_front work for vec::IntoIter with any Allocator, not just Global --- .../alloc/src/collections/vec_deque/spec_extend.rs | 14 ++++++++------ library/alloc/src/vec/spec_extend.rs | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index f73ba795cbea..b65e229361f2 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -77,8 +77,8 @@ where } #[cfg(not(test))] -impl SpecExtend> for VecDeque { - fn spec_extend(&mut self, mut iterator: vec::IntoIter) { +impl SpecExtend> for VecDeque { + fn spec_extend(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); self.reserve(slice.len()); @@ -153,9 +153,9 @@ where } #[cfg(not(test))] -impl SpecExtendFront> for VecDeque { +impl SpecExtendFront> for VecDeque { #[track_caller] - fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { + fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { let slice = iterator.as_slice(); // SAFETY: elements in the slice are forgotten after this call unsafe { prepend_reversed(self, slice) }; @@ -164,9 +164,11 @@ impl SpecExtendFront> for VecDeque { } #[cfg(not(test))] -impl SpecExtendFront>> for VecDeque { +impl SpecExtendFront>> + for VecDeque +{ #[track_caller] - fn spec_extend_front(&mut self, iterator: Rev>) { + fn spec_extend_front(&mut self, iterator: Rev>) { let mut iterator = iterator.into_inner(); let slice = iterator.as_slice(); // SAFETY: elements in the slice are forgotten after this call diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index f5bcd3ec9d82..7c908841c90e 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -28,8 +28,8 @@ where } } -impl SpecExtend> for Vec { - fn spec_extend(&mut self, mut iterator: IntoIter) { +impl SpecExtend> for Vec { + fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); } From c7bb49458f284421012f7e4c575d2747b19075d9 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 2 Jan 2026 23:13:52 +0900 Subject: [PATCH 095/340] Add tracking issue for sized_hierarchy --- compiler/rustc_feature/src/unstable.rs | 4 ++-- library/core/src/marker.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ca2ce2f18812..94e861787fc6 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -247,8 +247,6 @@ declare_features! ( (internal, profiler_runtime, "1.18.0", None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), - /// Introduces a hierarchy of `Sized` traits (RFC 3729). - (unstable, sized_hierarchy, "1.89.0", None), /// Allows using the `#[stable]` and `#[unstable]` attributes. (internal, staged_api, "1.0.0", None), /// Added for testing unstable lints; perma-unstable. @@ -305,6 +303,8 @@ declare_features! ( (internal, rustdoc_internals, "1.58.0", Some(90418)), /// Allows using the `rustdoc::missing_doc_code_examples` lint (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)), + /// Introduces a hierarchy of `Sized` traits (RFC 3729). + (unstable, sized_hierarchy, "1.89.0", Some(144404)), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library /// feature with the same name exists. diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 68f22767d6cf..5ecc2a63ea83 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -163,7 +163,7 @@ pub trait Sized: MetaSized { } /// Types with a size that can be determined from pointer metadata. -#[unstable(feature = "sized_hierarchy", issue = "none")] +#[unstable(feature = "sized_hierarchy", issue = "144404")] #[lang = "meta_sized"] #[diagnostic::on_unimplemented( message = "the size for values of type `{Self}` cannot be known", @@ -181,7 +181,7 @@ pub trait MetaSized: PointeeSized { } /// Types that may or may not have a size. -#[unstable(feature = "sized_hierarchy", issue = "none")] +#[unstable(feature = "sized_hierarchy", issue = "144404")] #[lang = "pointee_sized"] #[diagnostic::on_unimplemented( message = "values of type `{Self}` may or may not have a size", From da1ffbe181973aa47e384949a4498dd7fbd30721 Mon Sep 17 00:00:00 2001 From: alhubanov Date: Fri, 2 Jan 2026 18:02:52 +0200 Subject: [PATCH 096/340] fix: restrict match_bool to 2 arms --- clippy_lints/src/matches/match_bool.rs | 95 +++++++++++++------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index a2c8741f4f74..dc3457aa7a46 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -16,6 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] && arms .iter() .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..)))) + && arms.len() == 2 { span_lint_and_then( cx, @@ -23,59 +24,57 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] expr.span, "`match` on a boolean expression", move |diag| { - if arms.len() == 2 { - let mut app = Applicability::MachineApplicable; - let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { - let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); - if let PatExprKind::Lit { lit, .. } = arm_bool.kind { - match &lit.node { - LitKind::Bool(true) => Some(test), - LitKind::Bool(false) => Some(!test), - _ => None, - } - .map(|test| { - if let Some(guard) = &arms[0] - .guard - .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) - { - test.and(guard) - } else { - test - } - }) - } else { - None + let mut app = Applicability::MachineApplicable; + let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { + let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); + if let PatExprKind::Lit { lit, .. } = arm_bool.kind { + match &lit.node { + LitKind::Bool(true) => Some(test), + LitKind::Bool(false) => Some(!test), + _ => None, } + .map(|test| { + if let Some(guard) = &arms[0] + .guard + .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) + { + test.and(guard) + } else { + test + } + }) } else { None + } + } else { + None + }; + + if let Some(test_sugg) = test_sugg { + let ctxt = expr.span.ctxt(); + let (true_expr, false_expr) = (arms[0].body, arms[1].body); + let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { + (false, false) => Some(format!( + "if {} {} else {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (false, true) => Some(format!( + "if {} {}", + test_sugg, + expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, false) => Some(format!( + "if {} {}", + !test_sugg, + expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) + )), + (true, true) => None, }; - if let Some(test_sugg) = test_sugg { - let ctxt = expr.span.ctxt(); - let (true_expr, false_expr) = (arms[0].body, arms[1].body); - let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) { - (false, false) => Some(format!( - "if {} {} else {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app), - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (false, true) => Some(format!( - "if {} {}", - test_sugg, - expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, false) => Some(format!( - "if {} {}", - !test_sugg, - expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app) - )), - (true, true) => None, - }; - - if let Some(sugg) = sugg { - diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); - } + if let Some(sugg) = sugg { + diag.span_suggestion(expr.span, "consider using an `if`/`else` expression", sugg, app); } } }, From 0451cc012a4890abcbc217d4105b8ecf3daecf43 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 00:52:19 +0530 Subject: [PATCH 097/340] fix: add location links for generic type parameters in inlay hints --- .../crates/hir-ty/src/display.rs | 14 ++++++++++++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 8 ++++---- .../crates/ide/src/inlay_hints.rs | 19 +++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 44bbd84003da..4f9406908ffd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -10,7 +10,8 @@ use std::{ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, + FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, + ModuleId, TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -66,6 +67,7 @@ pub type Result = std::result::Result; pub trait HirWrite: fmt::Write { fn start_location_link(&mut self, _location: ModuleDefId) {} + fn start_location_link_generic(&mut self, _location: GenericParamId) {} fn end_location_link(&mut self) {} } @@ -147,6 +149,10 @@ impl<'db> HirFormatter<'_, 'db> { self.fmt.start_location_link(location); } + pub fn start_location_link_generic(&mut self, location: GenericParamId) { + self.fmt.start_location_link_generic(location); + } + pub fn end_location_link(&mut self) { self.fmt.end_location_link(); } @@ -1489,6 +1495,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + f.start_location_link_generic(param.id.into()); write!( f, "{}", @@ -1496,7 +1503,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> { .clone() .unwrap_or_else(Name::missing) .display(f.db, f.edition()) - )? + )?; + f.end_location_link(); } TypeParamProvenance::ArgumentImplTrait => { let bounds = GenericPredicates::query_all(f.db, param.id.parent()) @@ -1519,7 +1527,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } }, TypeOrConstParamData::ConstParamData(p) => { + f.start_location_link_generic(param.id.into()); write!(f, "{}", p.name.display(f.db, f.edition()))?; + f.end_location_link(); } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ab57c4489cf..65de6c0a554a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -50,9 +50,9 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, + TypeParamId, UnionId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, @@ -150,7 +150,7 @@ pub use { visibility::Visibility, // FIXME: This is here since some queries take it as input that are used // outside of hir. - {ModuleDefId, TraitId}, + {GenericParamId, ModuleDefId, TraitId}, }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 06ae0b1d73d1..a58dc6f03055 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -5,8 +5,8 @@ use std::{ use either::Either; use hir::{ - ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, - HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, + ClosureStyle, DisplayTarget, EditionedFileId, GenericParam, GenericParamId, HasVisibility, + HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; use ide_db::{ FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder, @@ -709,6 +709,21 @@ impl HirWrite for InlayHintLabelBuilder<'_> { }); } + fn start_location_link_generic(&mut self, def: GenericParamId) { + never!(self.location.is_some(), "location link is already started"); + self.make_new_part(); + + self.location = Some(if self.resolve { + LazyProperty::Lazy + } else { + LazyProperty::Computed({ + let Some(location) = GenericParam::from(def).try_to_nav(self.sema) else { return }; + let location = location.call_site(); + FileRange { file_id: location.file_id, range: location.focus_or_full_range() } + }) + }); + } + fn end_location_link(&mut self) { self.make_new_part(); } From 1222bbf29c7a0484c322006d8771dadcd47447c0 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 00:59:03 +0530 Subject: [PATCH 098/340] feat: added tests --- .../crates/ide/src/inlay_hints/bind_pat.rs | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 547004687c73..79cc2bdf8f7b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -183,7 +183,8 @@ mod tests { use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig}; use crate::inlay_hints::tests::{ - DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config, + DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit, + check_with_config, }; #[track_caller] @@ -1255,4 +1256,40 @@ where "#, ); } + + #[test] + fn generic_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn identity(t: T) -> T { + let x = t; + x +} +"#, + expect![[r#" + [ + ( + 36..37, + [ + InlayHintLabelPart { + text: "T", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 12..13, + }, + ), + ), + tooltip: "", + }, + ], + ), + ] + "#]], + ); + } } From 9a675c09cf65539e39e90d2adb6046870ec6a745 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Fri, 2 Jan 2026 20:40:04 +0100 Subject: [PATCH 099/340] alloc: Move Cow impl to existing ones Right now, the `borrow.rs` module starts with a `Cow` impl, although most of them can be found below. This hurts code readability because there is `ToOwned` alongside its impl directly below it. Moving it to the others down below makes sense here, given that the entire enum depends on `ToOwned` anyways. --- library/alloc/src/borrow.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index aa973e0bb024..d1c7cd47da0f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -16,19 +16,6 @@ use crate::fmt; #[cfg(not(no_global_oom_handling))] use crate::string::String; -// FIXME(inference): const bounds removed due to inference regressions found by crater; -// see https://github.com/rust-lang/rust/issues/147964 -// #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized + ToOwned> Borrow for Cow<'a, B> -// where -// B::Owned: [const] Borrow, -{ - fn borrow(&self) -> &B { - &**self - } -} - /// A generalization of `Clone` to borrowed data. /// /// Some types make it possible to go from borrowed to owned, usually by @@ -192,6 +179,19 @@ where Owned(#[stable(feature = "rust1", since = "1.0.0")] ::Owned), } +// FIXME(inference): const bounds removed due to inference regressions found by crater; +// see https://github.com/rust-lang/rust/issues/147964 +// #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, B: ?Sized + ToOwned> Borrow for Cow<'a, B> +// where +// B::Owned: [const] Borrow, +{ + fn borrow(&self) -> &B { + &**self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Cow<'_, B> { fn clone(&self) -> Self { From dd97e41d47b1bec301db3c334f4c378c946d9224 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 01:24:03 +0530 Subject: [PATCH 100/340] for filename, use localfilename first and then resort to other construction --- .../crates/load-cargo/src/lib.rs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) 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 5aa96582e9f3..023253f23f42 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -563,14 +563,23 @@ impl ProcMacroExpander for Expander { let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let name = source_root.path_for_file(&file).and_then(|path| { - path.name_and_extension().map(|(name, ext)| match ext { - Some(ext) => format!("{name}.{ext}"), - None => name.to_owned(), - }) - }); + let path = source_root.path_for_file(&file); - Ok(SubResponse::FileNameResult { name: name.unwrap_or_default() }) + let name = path + .and_then(|p| p.as_path()) + .and_then(|p| p.file_name()) + .map(|n| n.to_owned()) + .or_else(|| { + path.and_then(|p| { + p.name_and_extension().map(|(name, ext)| match ext { + Some(ext) => format!("{name}.{ext}"), + None => name.into(), + }) + }) + }) + .unwrap_or_default(); + + Ok(SubResponse::FileNameResult { name }) } }; match self.0.expand( From 3114decb04b1f4d8edb46a513df2f948ded778d2 Mon Sep 17 00:00:00 2001 From: benodiwal Date: Sat, 3 Jan 2026 01:58:48 +0530 Subject: [PATCH 101/340] fix: add location links for type, const, and lifetime parameters in inlay hints --- .../crates/hir-ty/src/display.rs | 4 + .../crates/ide/src/inlay_hints/bind_pat.rs | 92 ++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 4f9406908ffd..43b428c3fa51 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -692,7 +692,9 @@ impl<'db> HirDisplay<'db> for Const<'db> { ConstKind::Param(param) => { let generics = generics(f.db, param.id.parent()); let param_data = &generics[param.id.local_id()]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } ConstKind::Value(const_bytes) => render_const_scalar( @@ -2041,7 +2043,9 @@ impl<'db> HirDisplay<'db> for Region<'db> { RegionKind::ReEarlyParam(param) => { let generics = generics(f.db, param.id.parent); let param_data = &generics[param.id.local_id]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name.display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 79cc2bdf8f7b..c74e3104c14e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -1258,7 +1258,7 @@ where } #[test] - fn generic_param_inlay_hint_has_location_link() { + fn type_param_inlay_hint_has_location_link() { check_expect( InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, r#" @@ -1292,4 +1292,94 @@ fn identity(t: T) -> T { "#]], ); } + + #[test] + fn const_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn f() { + let x = [0; N]; +} +"#, + expect![[r#" + [ + ( + 33..34, + [ + "[i32; ", + InlayHintLabelPart { + text: "N", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 11..12, + }, + ), + ), + tooltip: "", + }, + "]", + ], + ), + ] + "#]], + ); + } + + #[test] + fn lifetime_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +struct S<'lt>(*mut &'lt ()); + +fn f<'a>() { + let x = S::<'a>(loop {}); +} +"#, + expect![[r#" + [ + ( + 51..52, + [ + InlayHintLabelPart { + text: "S", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 7..8, + }, + ), + ), + tooltip: "", + }, + "<", + InlayHintLabelPart { + text: "'a", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 35..37, + }, + ), + ), + tooltip: "", + }, + ">", + ], + ), + ] + "#]], + ); + } } From 0d366e098c2b389a2e573056f02b07bd92b7bca4 Mon Sep 17 00:00:00 2001 From: SSD <96286755+the-ssd@users.noreply.github.com> Date: Fri, 2 Jan 2026 22:30:25 +0100 Subject: [PATCH 102/340] Fix a typo in `libm::Libm::roundeven` --- library/compiler-builtins/libm/src/libm_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/libm/src/libm_helper.rs b/library/compiler-builtins/libm/src/libm_helper.rs index dfa1ff77bf2e..0bb669398657 100644 --- a/library/compiler-builtins/libm/src/libm_helper.rs +++ b/library/compiler-builtins/libm/src/libm_helper.rs @@ -168,7 +168,7 @@ libm_helper! { (fn remquo(x: f64, y: f64) -> (f64, i32); => remquo); (fn rint(x: f64) -> (f64); => rint); (fn round(x: f64) -> (f64); => round); - (fn roundevem(x: f64) -> (f64); => roundeven); + (fn roundeven(x: f64) -> (f64); => roundeven); (fn scalbn(x: f64, n: i32) -> (f64); => scalbn); (fn sin(x: f64) -> (f64); => sin); (fn sincos(x: f64) -> (f64, f64); => sincos); From 3fc32260694a0e71484ba5251bc4e9c22f74bac7 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 3 Jan 2026 10:24:02 +0900 Subject: [PATCH 103/340] Move `pattern_types` and `unqualified_local_imports` to the tracking issue group --- compiler/rustc_feature/src/unstable.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 94e861787fc6..f64702fc44b0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -239,8 +239,6 @@ declare_features! ( (internal, negative_bounds, "1.71.0", None), /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity_limit, "1.78.0", None), - /// Allows using pattern types. - (internal, pattern_types, "1.79.0", Some(123646)), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -251,8 +249,6 @@ declare_features! ( (internal, staged_api, "1.0.0", None), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), - /// Helps with formatting for `group_imports = "StdExternalCrate"`. - (unstable, unqualified_local_imports, "1.83.0", Some(138299)), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None), @@ -293,6 +289,8 @@ declare_features! ( (internal, needs_panic_runtime, "1.10.0", Some(32837)), /// Allows using the `#![panic_runtime]` attribute. (internal, panic_runtime, "1.10.0", Some(32837)), + /// Allows using pattern types. + (internal, pattern_types, "1.79.0", Some(123646)), /// Allows using `#[rustc_allow_const_fn_unstable]`. /// This is an attribute on `const fn` for the same /// purpose as `#[allow_internal_unstable]`. @@ -311,6 +309,8 @@ declare_features! ( (unstable, structural_match, "1.8.0", Some(31434)), /// Allows using the `rust-call` ABI. (unstable, unboxed_closures, "1.0.0", Some(29625)), + /// Helps with formatting for `group_imports = "StdExternalCrate"`. + (unstable, unqualified_local_imports, "1.83.0", Some(138299)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! From 6326896b0c42eea27125b78fbed455a035e5e064 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 09:12:32 +0530 Subject: [PATCH 104/340] emit same info via localfilename and filename --- .../rust-analyzer/crates/load-cargo/src/lib.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) 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 023253f23f42..4ffc8383b620 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -563,20 +563,10 @@ impl ProcMacroExpander for Expander { let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let path = source_root.path_for_file(&file); - - let name = path - .and_then(|p| p.as_path()) - .and_then(|p| p.file_name()) - .map(|n| n.to_owned()) - .or_else(|| { - path.and_then(|p| { - p.name_and_extension().map(|(name, ext)| match ext { - Some(ext) => format!("{name}.{ext}"), - None => name.into(), - }) - }) - }) + let name = source_root + .path_for_file(&file) + .and_then(|path| path.as_path()) + .and_then(|path| path.file_name().map(|filename| filename.to_owned())) .unwrap_or_default(); Ok(SubResponse::FileNameResult { name }) From c56c36ea7d1e0f15c41bfaf0dfe62b8e7954758e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 14:58:47 +0530 Subject: [PATCH 105/340] use fullpath instead of filename --- src/tools/rust-analyzer/crates/load-cargo/src/lib.rs | 12 ++++++------ .../proc-macro-api/src/bidirectional_protocol/msg.rs | 8 ++++---- .../crates/proc-macro-srv-cli/src/main_loop.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) 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 4ffc8383b620..e01ce0b129da 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -540,7 +540,7 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFileName { file_id } => { + SubRequest::LocalFilePath { file_id } => { let file = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); @@ -548,9 +548,9 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) .and_then(|path| path.as_path()) - .and_then(|path| path.file_name().map(|filename| filename.to_owned())); + .map(|path| path.to_string()); - Ok(SubResponse::LocalFileNameResult { name }) + Ok(SubResponse::LocalFilePathResult { name }) } SubRequest::SourceText { file_id, start, end } => { let file = FileId::from_raw(file_id); @@ -558,7 +558,7 @@ impl ProcMacroExpander for Expander { let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text: slice }) } - SubRequest::FileName { file_id } => { + SubRequest::FilePath { file_id } => { let file = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); @@ -566,10 +566,10 @@ impl ProcMacroExpander for Expander { let name = source_root .path_for_file(&file) .and_then(|path| path.as_path()) - .and_then(|path| path.file_name().map(|filename| filename.to_owned())) + .map(|path| path.to_string()) .unwrap_or_default(); - Ok(SubResponse::FileNameResult { name }) + Ok(SubResponse::FilePathResult { name }) } }; match self.0.expand( diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 2819a92fe33a..558954f7619d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -10,16 +10,16 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FileName { file_id: u32 }, + FilePath { file_id: u32 }, SourceText { file_id: u32, start: u32, end: u32 }, - LocalFileName { file_id: u32 }, + LocalFilePath { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] pub enum SubResponse { - FileNameResult { name: String }, + FilePathResult { name: String }, SourceTextResult { text: Option }, - LocalFileNameResult { name: Option }, + LocalFilePathResult { name: Option }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 77cb8760a100..8fe3e93e4702 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -186,9 +186,9 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FileName { file_id }) { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( - bidirectional::SubResponse::FileNameResult { name }, + bidirectional::SubResponse::FilePathResult { name }, )) => name, _ => String::new(), } @@ -204,9 +204,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFileName { file_id }) { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( - bidirectional::SubResponse::LocalFileNameResult { name }, + bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, _ => None, } From 7af3130d257bf06c4cb4ff4e160d69d8180b9c60 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 3 Jan 2026 10:47:41 +0100 Subject: [PATCH 106/340] perf: Only compute lang items for `#![feature(lang_items)]` crates --- .../crates/hir-def/src/lang_item.rs | 4 ++ .../crates/hir-ty/src/consteval/tests.rs | 3 ++ .../crates/hir-ty/src/tests/incremental.rs | 37 +++---------------- .../crates/hir-ty/src/tests/patterns.rs | 19 ++++++---- .../crates/hir-ty/src/tests/regression.rs | 1 + .../hir-ty/src/tests/regression/new_solver.rs | 1 + .../crates/hir-ty/src/tests/simple.rs | 36 ++++++++++-------- .../ide-completion/src/tests/flyimport.rs | 2 +- .../handlers/trait_impl_incorrect_safety.rs | 1 + .../crates/ide/src/hover/tests.rs | 1 + .../crates/ide/src/inlay_hints/bounds.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 1 + .../crates/test-utils/src/minicore.rs | 1 + 13 files changed, 51 insertions(+), 58 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index d3f4480b207e..eba4d87ec9f8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -40,6 +40,10 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option i32 { "trait_environment_query", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "expr_scopes_shim", "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", + "AttrFlags::query_", "body_shim", "body_with_source_map_shim", "trait_environment_query", @@ -149,6 +148,7 @@ fn baz() -> i32 { "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", + "AttrFlags::query_", "body_shim", "body_with_source_map_shim", "trait_environment_query", @@ -197,13 +197,13 @@ fn baz() -> i32 { "body_with_source_map_shim", "body_shim", "AttrFlags::query_", - "AttrFlags::query_", "function_signature_with_source_map_shim", "function_signature_shim", "body_with_source_map_shim", "body_shim", "InferenceResult::for_body_", "expr_scopes_shim", + "AttrFlags::query_", "function_signature_with_source_map_shim", "function_signature_shim", "body_with_source_map_shim", @@ -245,8 +245,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -284,9 +282,6 @@ pub struct NewStruct { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -324,8 +319,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -364,12 +357,6 @@ pub enum SomeEnum { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", - "EnumVariants::of_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -407,8 +394,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -444,8 +429,6 @@ fn bar() -> f32 { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -487,9 +470,6 @@ $0", "TraitImpls::for_crate_", "lang_items", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -533,12 +513,6 @@ impl SomeStruct { "crate_local_def_map", "TraitImpls::for_crate_", "crate_lang_items", - "AttrFlags::query_", - "ImplItems::of_", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", - "AttrFlags::query_", ] "#]], ); @@ -610,7 +584,6 @@ fn main() { "trait_environment_query", "lang_items", "crate_lang_items", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -623,6 +596,7 @@ fn main() { "expr_scopes_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "value_ty_query", "InherentImpls::for_crate_", @@ -702,8 +676,6 @@ fn main() { "body_with_source_map_shim", "body_shim", "crate_lang_items", - "AttrFlags::query_", - "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -713,6 +685,7 @@ fn main() { "ImplTraits::return_type_impl_traits_", "expr_scopes_shim", "struct_signature_with_source_map_shim", + "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", "callable_item_signature_query", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index c312b167596f..0b776938c5b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -794,6 +794,8 @@ fn slice_tail_pattern() { fn box_pattern() { check_infer( r#" + #![feature(lang_items)] + pub struct Global; #[lang = "owned_box"] pub struct Box(T); @@ -805,13 +807,13 @@ fn box_pattern() { } "#, expect![[r#" - 83..89 'params': Box - 101..155 '{ ... } }': () - 107..153 'match ... }': () - 113..119 'params': Box - 130..141 'box integer': Box - 134..141 'integer': i32 - 145..147 '{}': () + 108..114 'params': Box + 126..180 '{ ... } }': () + 132..178 'match ... }': () + 138..144 'params': Box + 155..166 'box integer': Box + 159..166 'integer': i32 + 170..172 '{}': () "#]], ); check_infer( @@ -831,7 +833,6 @@ fn box_pattern() { 76..122 'match ... }': () 82..88 'params': Box 99..110 'box integer': Box - 103..110 'integer': i32 114..116 '{}': () "#]], ); @@ -1142,6 +1143,7 @@ fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {} fn var_args() { check_types( r#" +#![feature(lang_items)] #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(foo: ...) {} @@ -1156,6 +1158,7 @@ fn my_fn2(bar: u32, foo: ...) {} fn var_args_cond() { check_types( r#" +#![feature(lang_items)] #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index f03f8d754f2a..c805f030446c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2374,6 +2374,7 @@ fn rust_destruct_option_clone() { check_types( r#" //- minicore: option, drop +#![feature(lang_items)] fn test(o: &Option) { o.my_clone(); //^^^^^^^^^^^^ Option diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index e11cc85e7ff1..a4554673cdd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -234,6 +234,7 @@ fn main() { // toolchains <= 1.88.0, before sized-hierarchy. check_no_mismatches( r#" +#![feature(lang_items)] #[lang = "sized"] pub trait Sized {} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index db557b75071f..6367521841ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2702,6 +2702,8 @@ fn box_into_vec() { check_infer( r#" //- /core.rs crate:core +#![feature(lang_items)] + #[lang = "sized"] pub trait Sized {} @@ -2745,22 +2747,22 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 614..618 'self': Box<[T], A> - 647..679 '{ ... }': Vec - 693..863 '{ ...])); }': () - 703..706 'vec': Vec - 709..724 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 709..755 '<[_]>:...i32]))': Vec - 725..754 '#[rust...1i32])': Box<[i32; 1], Global> - 747..753 '[1i32]': [i32; 1] - 748..752 '1i32': i32 - 765..766 'v': Vec, Global> - 786..803 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 786..860 '<[_]> ...ct)]))': Vec, Global> - 804..859 '#[rust...uct)])': Box<[Box; 1], Global> - 826..858 '[#[rus...ruct)]': [Box; 1] - 827..857 '#[rust...truct)': Box - 849..856 'Astruct': Astruct + 639..643 'self': Box<[T], A> + 672..704 '{ ... }': Vec + 718..888 '{ ...])); }': () + 728..731 'vec': Vec + 734..749 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec + 734..780 '<[_]>:...i32]))': Vec + 750..779 '#[rust...1i32])': Box<[i32; 1], Global> + 772..778 '[1i32]': [i32; 1] + 773..777 '1i32': i32 + 790..791 'v': Vec, Global> + 811..828 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 811..885 '<[_]> ...ct)]))': Vec, Global> + 829..884 '#[rust...uct)])': Box<[Box; 1], Global> + 851..883 '[#[rus...ruct)]': [Box; 1] + 852..882 '#[rust...truct)': Box + 874..881 'Astruct': Astruct "#]], ) } @@ -3647,6 +3649,8 @@ fn main() { fn cstring_literals() { check_types( r#" +#![feature(lang_items)] + #[lang = "CStr"] pub struct CStr; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 2912457da1f7..797df3f163da 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -781,9 +781,9 @@ fn main() { } "#, expect![[r#" - me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED + me random_method(…) (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs index 3414e972d5c9..c5b2f499d306 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_incorrect_safety.rs @@ -64,6 +64,7 @@ unsafe trait Unsafe {} fn drop_may_dangle() { check_diagnostics( r#" +#![feature(lang_items)] #[lang = "drop"] trait Drop {} struct S; diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index f42d3cf0dc41..0b518021e39e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -4089,6 +4089,7 @@ fn foo() { let fo$0o = async { S }; } //- /core.rs crate:core +#![feature(lang_items)] pub mod future { #[lang = "future_trait"] pub trait Future {} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index c9fbdf3ae754..045559fd7f46 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -143,7 +143,7 @@ fn foo() {} file_id: FileId( 1, ), - range: 446..451, + range: 470..475, }, ), ), diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 3e325b2f990d..b6efc599f181 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -297,6 +297,7 @@ define_symbols! { iterator, keyword, lang, + lang_items, le, Left, len, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index b7c09391ec37..01274a9835f4 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -80,6 +80,7 @@ //! offset_of: #![rustc_coherence_is_core] +#![feature(lang_items)] pub mod marker { // region:sized From b2e6e0374def640e09393a93b8a555925a7b8fe3 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 3 Jan 2026 11:17:29 +0000 Subject: [PATCH 107/340] mutex.rs: remove needless-maybe-unsized bounds --- library/std/src/sync/nonpoison/mutex.rs | 2 +- library/std/src/sync/poison/mutex.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index ed3f8cfed821..307bf8eaf512 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -422,7 +422,7 @@ impl From for Mutex { } #[unstable(feature = "nonpoison_mutex", issue = "134645")] -impl Default for Mutex { +impl Default for Mutex { /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 7f9e5fe62516..6eccd8a875ed 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -688,7 +688,7 @@ impl From for Mutex { } #[stable(feature = "mutex_default", since = "1.10.0")] -impl Default for Mutex { +impl Default for Mutex { /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) From 47798e261e13a905c6acae122a6111c8f1fd5eae Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sat, 3 Jan 2026 11:36:25 +0000 Subject: [PATCH 108/340] vec in-place-drop: avoid creating an intermediate slice --- library/alloc/src/vec/in_place_drop.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 997c4c7525b5..c8cc758ac15c 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -1,6 +1,5 @@ use core::marker::PhantomData; use core::ptr::{self, NonNull, drop_in_place}; -use core::slice::{self}; use crate::alloc::Global; use crate::raw_vec::RawVec; @@ -22,7 +21,7 @@ impl Drop for InPlaceDrop { #[inline] fn drop(&mut self) { unsafe { - ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.inner, self.len())); } } } From c99f9c249b017c6909ea44bba6fe3efcd56208ed Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:04:35 +0530 Subject: [PATCH 109/340] Replace sourcedb with expanddb --- .../hir-def/src/macro_expansion_tests/mod.rs | 4 ++-- .../crates/hir-expand/src/proc_macro.rs | 4 ++-- .../crates/load-cargo/src/lib.rs | 19 +++++++++--------- .../crates/test-fixture/src/lib.rs | 20 +++++++++---------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 3f136bc59172..c63f2c1d786b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,7 +16,7 @@ mod proc_macros; use std::{any::TypeId, iter, ops::Range, sync}; -use base_db::{RootQueryDb, SourceDatabase}; +use base_db::RootQueryDb; use expect_test::Expect; use hir_expand::{ AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind, @@ -387,7 +387,7 @@ struct IdentityWhenValidProcMacroExpander; impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &base_db::Env, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs index d2614aa5f149..467eae3122df 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs @@ -4,7 +4,7 @@ use core::fmt; use std::any::Any; use std::{panic::RefUnwindSafe, sync}; -use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase}; +use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError}; use intern::Symbol; use rustc_hash::FxHashMap; use span::Span; @@ -25,7 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any { /// [`ProcMacroKind::Attr`]), environment variables, and span information. fn expand( &self, - db: &dyn SourceDatabase, + db: &dyn ExpandDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, 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 e01ce0b129da..94fac0bd33f7 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -11,15 +11,16 @@ extern crate rustc_driver as _; use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync}; use crossbeam_channel::{Receiver, unbounded}; -use hir_expand::proc_macro::{ - ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, - ProcMacrosBuilder, +use hir_expand::{ + db::ExpandDatabase, + proc_macro::{ + ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult, + ProcMacrosBuilder, + }, }; use ide_db::{ - ChangeWithProcMacros, FxHashMap, RootDatabase, - base_db::{ - CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId, - }, + ChangeWithProcMacros, EditionedFileId, FxHashMap, RootDatabase, + base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, prime_caches, }; use itertools::Itertools; @@ -33,7 +34,7 @@ use proc_macro_api::{ use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; use vfs::{ - AbsPath, AbsPathBuf, FileId, VfsPath, + AbsPath, AbsPathBuf, VfsPath, file_set::FileSetConfig, loader::{Handle, LoadingProgress}, }; @@ -530,7 +531,7 @@ struct Expander(proc_macro_api::ProcMacro); impl ProcMacroExpander for Expander { fn expand( &self, - db: &dyn SourceDatabase, + db: &dyn ExpandDatabase, subtree: &tt::TopSubtree, attrs: Option<&tt::TopSubtree>, env: &Env, 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 b9c389c7694e..d81f27d7c3b1 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -738,7 +738,7 @@ struct IdentityProcMacroExpander; impl ProcMacroExpander for IdentityProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -761,7 +761,7 @@ struct Issue18089ProcMacroExpander; impl ProcMacroExpander for Issue18089ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -797,7 +797,7 @@ struct AttributeInputReplaceProcMacroExpander; impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, _: &TopSubtree, attrs: Option<&TopSubtree>, _: &Env, @@ -821,7 +821,7 @@ struct Issue18840ProcMacroExpander; impl ProcMacroExpander for Issue18840ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, fn_: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -858,7 +858,7 @@ struct MirrorProcMacroExpander; impl ProcMacroExpander for MirrorProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -897,7 +897,7 @@ struct ShortenProcMacroExpander; impl ProcMacroExpander for ShortenProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, input: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -942,7 +942,7 @@ struct Issue17479ProcMacroExpander; impl ProcMacroExpander for Issue17479ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -973,7 +973,7 @@ struct Issue18898ProcMacroExpander; impl ProcMacroExpander for Issue18898ProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1027,7 +1027,7 @@ struct DisallowCfgProcMacroExpander; impl ProcMacroExpander for DisallowCfgProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _: Option<&TopSubtree>, _: &Env, @@ -1059,7 +1059,7 @@ struct GenerateSuffixedTypeProcMacroExpander; impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { fn expand( &self, - _: &dyn SourceDatabase, + _: &dyn ExpandDatabase, subtree: &TopSubtree, _attrs: Option<&TopSubtree>, _env: &Env, From 38b2e9262075debeb7dfb125d9ef78268e0a069d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:06:26 +0530 Subject: [PATCH 110/340] added serde to span --- src/tools/rust-analyzer/Cargo.lock | 2 ++ .../rust-analyzer/crates/span/Cargo.toml | 1 + .../rust-analyzer/crates/span/src/ast_id.rs | 3 ++- .../rust-analyzer/crates/span/src/hygiene.rs | 5 +++- .../rust-analyzer/crates/span/src/lib.rs | 23 ++++++++++++++++--- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 42eaeb01f1f2..453c35a574d7 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1881,6 +1881,7 @@ dependencies = [ "postcard", "proc-macro-api", "proc-macro-srv", + "span", ] [[package]] @@ -2648,6 +2649,7 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 2.1.1", "salsa", + "serde", "stdx", "syntax", "text-size 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index cfb319d688b6..d331f63d0c53 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -21,6 +21,7 @@ text-size.workspace = true vfs.workspace = true syntax.workspace = true stdx.workspace = true +serde.workspace = true [dev-dependencies] syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 599b3c717522..37954ca0b062 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -29,6 +29,7 @@ use std::{ use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxBuildHasher, FxHashMap}; +use serde::{Deserialize, Serialize}; use syntax::{ AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, ast::{self, HasName}, @@ -54,7 +55,7 @@ pub const NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::NoDownmap as u32)); /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ErasedFileAstId(u32); impl fmt::Debug for ErasedFileAstId { diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 6805417177cd..1a82f221c6e4 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -21,11 +21,14 @@ //! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer. use std::fmt; +#[cfg(feature = "salsa")] +use serde::{Deserialize, Serialize}; + use crate::Edition; /// A syntax context describes a hierarchy tracking order of macro definitions. #[cfg(feature = "salsa")] -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub struct SyntaxContext( /// # Invariant /// diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index bfe7b2620d56..f6581de38ce2 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -20,6 +20,7 @@ pub use self::{ map::{RealSpanMap, SpanMap}, }; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; @@ -68,11 +69,12 @@ impl Span { /// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs /// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental /// friendly. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { /// The text range of this span, relative to the anchor. /// We need the anchor for incrementality, as storing absolute ranges will require /// recomputation on every change in a file at all times. + #[serde(serialize_with = "serialize_text_range", deserialize_with = "deserialize_text_range")] pub range: TextRange, /// The anchor this span is relative to. pub anchor: SpanAnchor, @@ -80,6 +82,21 @@ pub struct Span { pub ctx: SyntaxContext, } +fn serialize_text_range(range: &TextRange, serializer: S) -> Result +where + S: Serializer, +{ + (u32::from(range.start()), u32::from(range.end())).serialize(serializer) +} + +fn deserialize_text_range<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let (start, end) = <(u32, u32)>::deserialize(deserializer)?; + Ok(TextRange::new(TextSize::from(start), TextSize::from(end))) +} + impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { @@ -112,7 +129,7 @@ impl fmt::Display for Span { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct SpanAnchor { pub file_id: EditionedFileId, pub ast_id: ErasedFileAstId, @@ -126,7 +143,7 @@ impl fmt::Debug for SpanAnchor { /// A [`FileId`] and [`Edition`] bundled up together. /// The MSB is reserved for `HirFileId` encoding, more upper bits are used to then encode the edition. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { From 3941fed5017b6dce330fb14972fca968f80b3303 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:13:06 +0530 Subject: [PATCH 111/340] add span to proc-macro-srv-cliy --- src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 2c6e5a16ee06..875d9f6801a3 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -14,6 +14,7 @@ publish = false proc-macro-srv.workspace = true proc-macro-api.workspace = true postcard.workspace = true +span.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] From be566f4e6b0f3d160d060d0b0508256d549e24bb Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:15:42 +0530 Subject: [PATCH 112/340] refactor subreq/resp variants to carry span --- .../src/bidirectional_protocol/msg.rs | 7 ++++--- .../crates/proc-macro-srv-cli/src/main_loop.rs | 13 +++++++------ .../rust-analyzer/crates/proc-macro-srv/src/lib.rs | 6 +++--- .../src/server_impl/rust_analyzer_span.rs | 13 +++---------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 558954f7619d..73cf58bd9ec7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -2,6 +2,7 @@ use paths::Utf8PathBuf; use serde::{Deserialize, Serialize}; +use tt::Span; use crate::{ ProcMacroKind, @@ -10,9 +11,9 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FilePath { file_id: u32 }, - SourceText { file_id: u32, start: u32, end: u32 }, - LocalFilePath { file_id: u32 }, + FilePath { span: Span }, + SourceText { span: Span }, + LocalFilePath { span: Span }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 8fe3e93e4702..a5bf84df04de 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -6,6 +6,7 @@ use proc_macro_api::{ transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; +use span::Span; use std::io; use legacy::Message; @@ -185,8 +186,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { + fn file(&mut self, span: Span) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -194,8 +195,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, start, end }) { + fn source_text(&mut self, span: Span) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -203,8 +204,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { + fn local_file(&mut self, span: Span) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { span }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 8de712dbd386..6620800779bd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,9 +94,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, file_id: u32) -> String; - fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option; - fn local_file(&mut self, file_id: u32) -> Option; + fn file(&mut self, span: Span) -> String; + fn source_text(&mut self, span: Span) -> Option; + fn local_file(&mut self, span: Span) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 7a9d655431f5..c4392a9ae110 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,13 +128,10 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback - .as_mut() - .map(|cb| cb.file(span.anchor.file_id.file_id().index())) - .unwrap_or_default() + self.callback.as_mut().map(|cb| cb.file(span)).unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) + self.callback.as_mut().and_then(|cb| cb.local_file(span)) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -153,11 +150,7 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - let file_id = span.anchor.file_id; - let start: u32 = span.range.start().into(); - let end: u32 = span.range.end().into(); - - self.callback.as_mut()?.source_text(file_id.file_id().index(), start, end) + self.callback.as_mut()?.source_text(span) } fn parent(&mut self, _span: Self::Span) -> Option { From 4f5502e8fb2679b76390bc7bebf4b457e853176d Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 19:18:36 +0530 Subject: [PATCH 113/340] Add span to callbacks and correct the source_text implementation --- .../crates/load-cargo/src/lib.rs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) 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 94fac0bd33f7..474046ee2fa7 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -541,31 +541,37 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFilePath { file_id } => { - let file = FileId::from_raw(file_id); - let source_root_id = db.file_source_root(file).source_root_id(db); + SubRequest::LocalFilePath { span } => { + let file_id = span.anchor.file_id.file_id(); + let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); - let name = source_root - .path_for_file(&file) + .path_for_file(&file_id) .and_then(|path| path.as_path()) .map(|path| path.to_string()); Ok(SubResponse::LocalFilePathResult { name }) } - SubRequest::SourceText { file_id, start, end } => { - let file = FileId::from_raw(file_id); - let text = db.file_text(file).text(db); - let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned); - Ok(SubResponse::SourceTextResult { text: slice }) - } - SubRequest::FilePath { file_id } => { - let file = FileId::from_raw(file_id); - let source_root_id = db.file_source_root(file).source_root_id(db); - let source_root = db.source_root(source_root_id).source_root(db); + SubRequest::SourceText { span } => { + let anchor = span.anchor; + let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); + let range = db + .ast_id_map(hir_expand::HirFileId::FileId(file_id)) + .get_erased(anchor.ast_id) + .text_range(); + let source = db.file_text(anchor.file_id.file_id()).text(db); + let text = source + .get(usize::from(range.start())..usize::from(range.end())) + .map(ToOwned::to_owned); + Ok(SubResponse::SourceTextResult { text }) + } + SubRequest::FilePath { span } => { + let file_id = span.anchor.file_id.file_id(); + let source_root_id = db.file_source_root(file_id).source_root_id(db); + let source_root = db.source_root(source_root_id).source_root(db); let name = source_root - .path_for_file(&file) + .path_for_file(&file_id) .and_then(|path| path.as_path()) .map(|path| path.to_string()) .unwrap_or_default(); From ce19860f800c974dd1eb66a3aa9c2a6716d90bb7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 20:10:00 +0530 Subject: [PATCH 114/340] remove span related API from proc-macro-srv/cli/api and remove span from procmacrosrvcli --- src/tools/rust-analyzer/Cargo.lock | 1 - .../crates/load-cargo/src/lib.rs | 36 ++++++++++--------- .../src/bidirectional_protocol/msg.rs | 7 ++-- .../crates/proc-macro-srv-cli/Cargo.toml | 1 - .../proc-macro-srv-cli/src/main_loop.rs | 14 ++++---- .../crates/proc-macro-srv/src/lib.rs | 6 ++-- .../src/server_impl/rust_analyzer_span.rs | 19 ++++++++-- 7 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 453c35a574d7..fbaeff1eb560 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1881,7 +1881,6 @@ dependencies = [ "postcard", "proc-macro-api", "proc-macro-srv", - "span", ] [[package]] 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 474046ee2fa7..c302e266febd 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -34,7 +34,7 @@ use proc_macro_api::{ use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; use vfs::{ - AbsPath, AbsPathBuf, VfsPath, + AbsPath, AbsPathBuf, FileId, VfsPath, file_set::FileSetConfig, loader::{Handle, LoadingProgress}, }; @@ -541,8 +541,8 @@ impl ProcMacroExpander for Expander { current_dir: String, ) -> Result { let mut cb = |req| match req { - SubRequest::LocalFilePath { span } => { - let file_id = span.anchor.file_id.file_id(); + SubRequest::LocalFilePath { file_id } => { + let file_id = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); let name = source_root @@ -552,22 +552,26 @@ impl ProcMacroExpander for Expander { Ok(SubResponse::LocalFilePathResult { name }) } - SubRequest::SourceText { span } => { - let anchor = span.anchor; - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let range = db - .ast_id_map(hir_expand::HirFileId::FileId(file_id)) - .get_erased(anchor.ast_id) - .text_range(); - let source = db.file_text(anchor.file_id.file_id()).text(db); - let text = source - .get(usize::from(range.start())..usize::from(range.end())) - .map(ToOwned::to_owned); + SubRequest::SourceText { file_id, ast_id, start, end } => { + let raw_file_id = FileId::from_raw(file_id); + let editioned_file_id = span::EditionedFileId::from_raw(file_id); + let ast_id = span::ErasedFileAstId::from_raw(ast_id); + let hir_file_id = EditionedFileId::from_span_guess_origin(db, editioned_file_id); + let anchor_offset = db + .ast_id_map(hir_expand::HirFileId::FileId(hir_file_id)) + .get_erased(ast_id) + .text_range() + .start(); + let anchor_offset = u32::from(anchor_offset); + let abs_start = start + anchor_offset; + let abs_end = end + anchor_offset; + let source = db.file_text(raw_file_id).text(db); + let text = source.get(abs_start as usize..abs_end as usize).map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text }) } - SubRequest::FilePath { span } => { - let file_id = span.anchor.file_id.file_id(); + SubRequest::FilePath { file_id } => { + let file_id = FileId::from_raw(file_id); let source_root_id = db.file_source_root(file_id).source_root_id(db); let source_root = db.source_root(source_root_id).source_root(db); let name = source_root diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs index 73cf58bd9ec7..e41f8a5d7da7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs @@ -2,7 +2,6 @@ use paths::Utf8PathBuf; use serde::{Deserialize, Serialize}; -use tt::Span; use crate::{ ProcMacroKind, @@ -11,9 +10,9 @@ use crate::{ #[derive(Debug, Serialize, Deserialize)] pub enum SubRequest { - FilePath { span: Span }, - SourceText { span: Span }, - LocalFilePath { span: Span }, + FilePath { file_id: u32 }, + SourceText { file_id: u32, ast_id: u32, start: u32, end: u32 }, + LocalFilePath { file_id: u32 }, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 875d9f6801a3..2c6e5a16ee06 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -14,7 +14,6 @@ publish = false proc-macro-srv.workspace = true proc-macro-api.workspace = true postcard.workspace = true -span.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index a5bf84df04de..4891e073142d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -6,7 +6,6 @@ use proc_macro_api::{ transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; -use span::Span; use std::io; use legacy::Message; @@ -186,8 +185,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, span: Span) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { span }) { + fn file(&mut self, file_id: u32) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -195,8 +194,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, span: Span) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { span }) { + fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, ast_id, start, end }) + { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -204,8 +204,8 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, span: Span) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { span }) { + fn local_file(&mut self, file_id: u32) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 6620800779bd..d63aea947c1d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -94,9 +94,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, span: Span) -> String; - fn source_text(&mut self, span: Span) -> Option; - fn local_file(&mut self, span: Span) -> Option; + fn file(&mut self, file_id: u32) -> String; + fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option; + fn local_file(&mut self, file_id: u32) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index c4392a9ae110..2ce3b717cb0d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,10 +128,13 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback.as_mut().map(|cb| cb.file(span)).unwrap_or_default() + self.callback + .as_mut() + .map(|cb| cb.file(span.anchor.file_id.file_id().index())) + .unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span)) + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -150,7 +153,17 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - self.callback.as_mut()?.source_text(span) + let file_id = span.anchor.file_id; + let ast_id = span.anchor.ast_id; + let start: u32 = span.range.start().into(); + let end: u32 = span.range.end().into(); + + self.callback.as_mut()?.source_text( + file_id.file_id().index(), + ast_id.into_raw(), + start, + end, + ) } fn parent(&mut self, _span: Self::Span) -> Option { From f3b06a10f259fffd2ae92334f91fd0365e33f66a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sat, 3 Jan 2026 20:13:41 +0530 Subject: [PATCH 115/340] remove serde from span --- src/tools/rust-analyzer/Cargo.lock | 1 - .../rust-analyzer/crates/span/Cargo.toml | 1 - .../rust-analyzer/crates/span/src/ast_id.rs | 3 +-- .../rust-analyzer/crates/span/src/hygiene.rs | 8 ++----- .../rust-analyzer/crates/span/src/lib.rs | 23 +++---------------- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index fbaeff1eb560..42eaeb01f1f2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2648,7 +2648,6 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 2.1.1", "salsa", - "serde", "stdx", "syntax", "text-size 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml index d331f63d0c53..cfb319d688b6 100644 --- a/src/tools/rust-analyzer/crates/span/Cargo.toml +++ b/src/tools/rust-analyzer/crates/span/Cargo.toml @@ -21,7 +21,6 @@ text-size.workspace = true vfs.workspace = true syntax.workspace = true stdx.workspace = true -serde.workspace = true [dev-dependencies] syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index 37954ca0b062..599b3c717522 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -29,7 +29,6 @@ use std::{ use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxBuildHasher, FxHashMap}; -use serde::{Deserialize, Serialize}; use syntax::{ AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr, ast::{self, HasName}, @@ -55,7 +54,7 @@ pub const NO_DOWNMAP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId = ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::NoDownmap as u32)); /// This is a type erased FileAstId. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct ErasedFileAstId(u32); impl fmt::Debug for ErasedFileAstId { diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 1a82f221c6e4..ea4f4c5efb42 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -19,16 +19,12 @@ //! # The Call-site Hierarchy //! //! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer. -use std::fmt; - -#[cfg(feature = "salsa")] -use serde::{Deserialize, Serialize}; - use crate::Edition; +use std::fmt; /// A syntax context describes a hierarchy tracking order of macro definitions. #[cfg(feature = "salsa")] -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] pub struct SyntaxContext( /// # Invariant /// diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index f6581de38ce2..bfe7b2620d56 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -20,7 +20,6 @@ pub use self::{ map::{RealSpanMap, SpanMap}, }; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use syntax::Edition; pub use text_size::{TextRange, TextSize}; pub use vfs::FileId; @@ -69,12 +68,11 @@ impl Span { /// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs /// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental /// friendly. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct Span { /// The text range of this span, relative to the anchor. /// We need the anchor for incrementality, as storing absolute ranges will require /// recomputation on every change in a file at all times. - #[serde(serialize_with = "serialize_text_range", deserialize_with = "deserialize_text_range")] pub range: TextRange, /// The anchor this span is relative to. pub anchor: SpanAnchor, @@ -82,21 +80,6 @@ pub struct Span { pub ctx: SyntaxContext, } -fn serialize_text_range(range: &TextRange, serializer: S) -> Result -where - S: Serializer, -{ - (u32::from(range.start()), u32::from(range.end())).serialize(serializer) -} - -fn deserialize_text_range<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let (start, end) = <(u32, u32)>::deserialize(deserializer)?; - Ok(TextRange::new(TextSize::from(start), TextSize::from(end))) -} - impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { @@ -129,7 +112,7 @@ impl fmt::Display for Span { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct SpanAnchor { pub file_id: EditionedFileId, pub ast_id: ErasedFileAstId, @@ -143,7 +126,7 @@ impl fmt::Debug for SpanAnchor { /// A [`FileId`] and [`Edition`] bundled up together. /// The MSB is reserved for `HirFileId` encoding, more upper bits are used to then encode the edition. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { From 65c10702bdbbaa733858fa890a41d1f5892ab0de Mon Sep 17 00:00:00 2001 From: Sekar-C-Mca Date: Sat, 3 Jan 2026 22:41:01 +0530 Subject: [PATCH 116/340] Fix typo in pattern usefulness documentation Line 171 introduced `pt_1, .., pt_n` and `qt` as variable names, but line 172 incorrectly used `tp_1, .., tp_n, tq`. This commit fixes the inconsistency to use the correct variable names throughout. --- compiler/rustc_pattern_analysis/src/usefulness.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 971616b18914..bf236b7737d9 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -169,7 +169,7 @@ //! on pattern-tuples. //! //! Let `pt_1, .., pt_n` and `qt` be length-m tuples of patterns for the same type `(T_1, .., T_m)`. -//! We compute `usefulness(tp_1, .., tp_n, tq)` as follows: +//! We compute `usefulness(pt_1, .., pt_n, qt)` as follows: //! //! - Base case: `m == 0`. //! The pattern-tuples are all empty, i.e. they're all `()`. Thus `tq` is useful iff there are From d236b8a4f19b5c09f5cba0f5d69ac13c2c303d48 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 8 Sep 2025 13:24:24 -0400 Subject: [PATCH 117/340] Add Dir::open(_file) and some trait impls --- library/std/src/fs.rs | 118 +++++++++++++ library/std/src/fs/tests.rs | 31 ++++ library/std/src/sys/fs/common.rs | 25 ++- library/std/src/sys/fs/hermit.rs | 3 +- library/std/src/sys/fs/mod.rs | 2 +- library/std/src/sys/fs/solid.rs | 2 +- library/std/src/sys/fs/uefi.rs | 1 + library/std/src/sys/fs/unix.rs | 242 +++++++++++++++----------- library/std/src/sys/fs/unix/dir.rs | 114 ++++++++++++ library/std/src/sys/fs/unsupported.rs | 1 + library/std/src/sys/fs/windows.rs | 51 ++++-- library/std/src/sys/fs/windows/dir.rs | 153 ++++++++++++++++ 12 files changed, 619 insertions(+), 124 deletions(-) create mode 100644 library/std/src/sys/fs/unix/dir.rs create mode 100644 library/std/src/sys/fs/windows/dir.rs diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index f078dec21d0a..4edd35b310bd 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -152,6 +152,43 @@ pub enum TryLockError { WouldBlock, } +/// An object providing access to a directory on the filesystem. +/// +/// Directories are automatically closed when they go out of scope. Errors detected +/// on closing are ignored by the implementation of `Drop`. +/// +/// # Platform-specific behavior +/// +/// On supported systems (including Windows and some UNIX-based OSes), this function acquires a +/// handle/file descriptor for the directory. This allows functions like [`Dir::open_file`] to +/// avoid [TOCTOU] errors when the directory itself is being moved. +/// +/// On other systems, it stores an absolute path (see [`canonicalize()`]). In the latter case, no +/// [TOCTOU] guarantees are made. +/// +/// # Examples +/// +/// Opens a directory and then a file inside it. +/// +/// ```no_run +/// #![feature(dirfd)] +/// use std::{fs::Dir, io}; +/// +/// fn main() -> std::io::Result<()> { +/// let dir = Dir::open("foo")?; +/// let mut file = dir.open_file("bar.txt")?; +/// let contents = io::read_to_string(file)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } +/// ``` +/// +/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou +#[unstable(feature = "dirfd", issue = "120426")] +pub struct Dir { + inner: fs_imp::Dir, +} + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -1554,6 +1591,87 @@ impl Seek for Arc { } } +impl Dir { + /// Attempts to open a directory at `path` in read-only mode. + /// + /// # Errors + /// + /// This function will return an error if `path` does not point to an existing directory. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(dirfd)] + /// use std::{fs::Dir, io}; + /// + /// fn main() -> std::io::Result<()> { + /// let dir = Dir::open("foo")?; + /// let mut f = dir.open_file("bar.txt")?; + /// let contents = io::read_to_string(f)?; + /// assert_eq!(contents, "Hello, world!"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "dirfd", issue = "120426")] + pub fn open>(path: P) -> io::Result { + fs_imp::Dir::open(path.as_ref(), &OpenOptions::new().read(true).0) + .map(|inner| Self { inner }) + } + + /// Attempts to open a file in read-only mode relative to this directory. + /// + /// # Errors + /// + /// This function will return an error if `path` does not point to an existing file. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(dirfd)] + /// use std::{fs::Dir, io}; + /// + /// fn main() -> std::io::Result<()> { + /// let dir = Dir::open("foo")?; + /// let mut f = dir.open_file("bar.txt")?; + /// let contents = io::read_to_string(f)?; + /// assert_eq!(contents, "Hello, world!"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "dirfd", issue = "120426")] + pub fn open_file>(&self, path: P) -> io::Result { + self.inner + .open_file(path.as_ref(), &OpenOptions::new().read(true).0) + .map(|f| File { inner: f }) + } +} + +impl AsInner for Dir { + #[inline] + fn as_inner(&self) -> &fs_imp::Dir { + &self.inner + } +} +impl FromInner for Dir { + fn from_inner(f: fs_imp::Dir) -> Dir { + Dir { inner: f } + } +} +impl IntoInner for Dir { + fn into_inner(self) -> fs_imp::Dir { + self.inner + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + impl OpenOptions { /// Creates a blank new set of options ready for configuration. /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index f15efc7b2f0b..6a86705f2fad 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,11 @@ use rand::RngCore; +#[cfg(not(miri))] +use super::Dir; use crate::assert_matches::assert_matches; use crate::fs::{self, File, FileTimes, OpenOptions, TryLockError}; +#[cfg(not(miri))] +use crate::io; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; use crate::mem::MaybeUninit; @@ -2465,3 +2469,30 @@ fn test_fs_set_times_nofollow() { assert_ne!(target_metadata.accessed().unwrap(), accessed); assert_ne!(target_metadata.modified().unwrap(), modified); } + +#[test] +// FIXME: libc calls fail on miri +#[cfg(not(miri))] +fn test_dir_smoke_test() { + let tmpdir = tmpdir(); + let dir = Dir::open(tmpdir.path()); + check!(dir); +} + +#[test] +// FIXME: libc calls fail on miri +#[cfg(not(miri))] +fn test_dir_read_file() { + let tmpdir = tmpdir(); + let mut f = check!(File::create(tmpdir.join("foo.txt"))); + check!(f.write(b"bar")); + check!(f.flush()); + drop(f); + let dir = check!(Dir::open(tmpdir.path())); + let f = check!(dir.open_file("foo.txt")); + let buf = check!(io::read_to_string(f)); + assert_eq!("bar", &buf); + let f = check!(dir.open_file(tmpdir.join("foo.txt"))); + let buf = check!(io::read_to_string(f)); + assert_eq!("bar", &buf); +} diff --git a/library/std/src/sys/fs/common.rs b/library/std/src/sys/fs/common.rs index fbd075d57d61..4d47d392a826 100644 --- a/library/std/src/sys/fs/common.rs +++ b/library/std/src/sys/fs/common.rs @@ -1,9 +1,10 @@ #![allow(dead_code)] // not used on all platforms -use crate::fs; use crate::io::{self, Error, ErrorKind}; -use crate::path::Path; +use crate::path::{Path, PathBuf}; +use crate::sys::fs::{File, OpenOptions}; use crate::sys::helpers::ignore_notfound; +use crate::{fmt, fs}; pub(crate) const NOT_FILE_ERROR: Error = io::const_error!( ErrorKind::InvalidInput, @@ -58,3 +59,23 @@ pub fn exists(path: &Path) -> io::Result { Err(error) => Err(error), } } + +pub struct Dir { + path: PathBuf, +} + +impl Dir { + pub fn open(path: &Path, _opts: &OpenOptions) -> io::Result { + path.canonicalize().map(|path| Self { path }) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + File::open(&self.path.join(path), &opts) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Dir").field("path", &self.path).finish() + } +} diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index bb0c44d7e9a1..1e281eb0d9d1 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -10,7 +10,7 @@ use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Raw use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::{copy, exists}; +pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; @@ -18,6 +18,7 @@ use crate::{fmt, mem}; #[derive(Debug)] pub struct File(FileDesc); + #[derive(Clone)] pub struct FileAttr { stat_val: stat_struct, diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index fa046cb8e7da..0c297c5766b8 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -59,7 +59,7 @@ pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> i } pub use imp::{ - DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, + Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, ReadDir, }; diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index b6d41cc4bc84..114ffda57bc5 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -9,7 +9,7 @@ use crate::os::raw::{c_int, c_short}; use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; -pub use crate::sys::fs::common::exists; +pub use crate::sys::fs::common::{Dir, exists}; use crate::sys::helpers::ignore_notfound; use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index f5530962c570..14ee49e071c1 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,6 +6,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; +pub use crate::sys::fs::common::Dir; use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 1cc2edd0cf47..327b0eb7468a 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -257,7 +257,7 @@ cfg_has_statx! {{ // all DirEntry's will have a reference to this struct struct InnerReadDir { - dirp: Dir, + dirp: DirStream, root: PathBuf, } @@ -272,10 +272,134 @@ impl ReadDir { } } -struct Dir(*mut libc::DIR); +struct DirStream(*mut libc::DIR); -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} +// dir::Dir requires openat support +cfg_select! { + any( + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nto", + target_os = "vxworks", + ) => { + pub use crate::sys::fs::common::Dir; + } + _ => { + mod dir; + pub use dir::Dir; + } +} + +fn debug_path_fd<'a, 'b>( + fd: c_int, + f: &'a mut fmt::Formatter<'b>, + name: &str, +) -> fmt::DebugStruct<'a, 'b> { + let mut b = f.debug_struct(name); + + fn get_mode(fd: c_int) -> Option<(bool, bool)> { + let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; + if mode == -1 { + return None; + } + match mode & libc::O_ACCMODE { + libc::O_RDONLY => Some((true, false)), + libc::O_RDWR => Some((true, true)), + libc::O_WRONLY => Some((false, true)), + _ => None, + } + } + + b.field("fd", &fd); + if let Some(path) = get_path_from_fd(fd) { + b.field("path", &path); + } + if let Some((read, write)) = get_mode(fd) { + b.field("read", &read).field("write", &write); + } + + b +} + +fn get_path_from_fd(fd: c_int) -> Option { + #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] + fn get_path(fd: c_int) -> Option { + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + run_path_with_cstr(&p, &readlink).ok() + } + + #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] + fn get_path(fd: c_int) -> Option { + // FIXME: The use of PATH_MAX is generally not encouraged, but it + // is inevitable in this case because Apple targets and NetBSD define `fcntl` + // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // alternatives. If a better method is invented, it should be used + // instead. + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; + if n == -1 { + cfg_select! { + target_os = "netbsd" => { + // fallback to procfs as last resort + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + return run_path_with_cstr(&p, &readlink).ok() + } + _ => { + return None; + } + } + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + buf.shrink_to_fit(); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(target_os = "freebsd")] + fn get_path(fd: c_int) -> Option { + let info = Box::::new_zeroed(); + let mut info = unsafe { info.assume_init() }; + info.kf_structsize = size_of::() as libc::c_int; + let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; + if n == -1 { + return None; + } + let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(target_os = "vxworks")] + fn get_path(fd: c_int) -> Option { + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any( + target_os = "linux", + target_os = "vxworks", + target_os = "freebsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_vendor = "apple", + )))] + fn get_path(_fd: c_int) -> Option { + // FIXME(#24570): implement this for other Unix platforms + None + } + + get_path(fd) +} #[cfg(any( target_os = "aix", @@ -874,7 +998,7 @@ pub(crate) fn debug_assert_fd_is_open(fd: RawFd) { } } -impl Drop for Dir { +impl Drop for DirStream { fn drop(&mut self) { // dirfd isn't supported everywhere #[cfg(not(any( @@ -902,6 +1026,11 @@ impl Drop for Dir { } } +// SAFETY: `int dirfd (DIR *dirstream)` is MT-safe, implying that the pointer +// may be safely sent among threads. +unsafe impl Send for DirStream {} +unsafe impl Sync for DirStream {} + impl DirEntry { pub fn path(&self) -> PathBuf { self.dir.root.join(self.file_name_os_str()) @@ -1860,102 +1989,8 @@ impl FromRawFd for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] - fn get_path(fd: c_int) -> Option { - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - run_path_with_cstr(&p, &readlink).ok() - } - - #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] - fn get_path(fd: c_int) -> Option { - // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because Apple targets and NetBSD define `fcntl` - // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no - // alternatives. If a better method is invented, it should be used - // instead. - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; - if n == -1 { - cfg_select! { - target_os = "netbsd" => { - // fallback to procfs as last resort - let mut p = PathBuf::from("/proc/self/fd"); - p.push(&fd.to_string()); - return run_path_with_cstr(&p, &readlink).ok() - } - _ => { - return None; - } - } - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - buf.shrink_to_fit(); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(target_os = "freebsd")] - fn get_path(fd: c_int) -> Option { - let info = Box::::new_zeroed(); - let mut info = unsafe { info.assume_init() }; - info.kf_structsize = size_of::() as libc::c_int; - let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; - if n == -1 { - return None; - } - let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() }; - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(target_os = "vxworks")] - fn get_path(fd: c_int) -> Option { - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - Some(PathBuf::from(OsString::from_vec(buf))) - } - - #[cfg(not(any( - target_os = "linux", - target_os = "vxworks", - target_os = "freebsd", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris", - target_vendor = "apple", - )))] - fn get_path(_fd: c_int) -> Option { - // FIXME(#24570): implement this for other Unix platforms - None - } - - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None, - } - } - let fd = self.as_raw_fd(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } + let mut b = debug_path_fd(fd, f, "File"); b.finish() } } @@ -2033,7 +2068,7 @@ pub fn readdir(path: &Path) -> io::Result { Err(Error::last_os_error()) } else { let root = path.to_path_buf(); - let inner = InnerReadDir { dirp: Dir(ptr), root }; + let inner = InnerReadDir { dirp: DirStream(ptr), root }; Ok(ReadDir::new(inner)) } } @@ -2493,7 +2528,8 @@ mod remove_dir_impl { use libc::{fdopendir, openat64 as openat, unlinkat}; use super::{ - AsRawFd, Dir, DirEntry, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, lstat, + AsRawFd, DirEntry, DirStream, FromRawFd, InnerReadDir, IntoRawFd, OwnedFd, RawFd, ReadDir, + lstat, }; use crate::ffi::CStr; use crate::io; @@ -2517,7 +2553,7 @@ mod remove_dir_impl { if ptr.is_null() { return Err(io::Error::last_os_error()); } - let dirp = Dir(ptr); + let dirp = DirStream(ptr); // file descriptor is automatically closed by libc::closedir() now, so give up ownership let new_parent_fd = dir_fd.into_raw_fd(); // a valid root is not needed because we do not call any functions involving the full path diff --git a/library/std/src/sys/fs/unix/dir.rs b/library/std/src/sys/fs/unix/dir.rs new file mode 100644 index 000000000000..094d1bfd3168 --- /dev/null +++ b/library/std/src/sys/fs/unix/dir.rs @@ -0,0 +1,114 @@ +use libc::c_int; + +cfg_select! { + not( + any( + all(target_os = "linux", not(target_env = "musl")), + target_os = "l4re", + target_os = "android", + target_os = "hurd", + ) + ) => { + use libc::{open as open64, openat as openat64}; + } + _ => { + use libc::{open64, openat64}; + } +} + +use crate::ffi::CStr; +use crate::os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}; +#[cfg(target_family = "unix")] +use crate::os::unix::io::{AsRawFd, FromRawFd}; +#[cfg(target_os = "wasi")] +use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::path::Path; +use crate::sys::fd::FileDesc; +use crate::sys::fs::OpenOptions; +use crate::sys::fs::unix::{File, debug_path_fd}; +use crate::sys::helpers::run_path_with_cstr; +use crate::sys::{AsInner, FromInner, IntoInner, cvt_r}; +use crate::{fmt, fs, io}; + +pub struct Dir(OwnedFd); + +impl Dir { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + run_path_with_cstr(path, &|path| Self::open_with_c(path, opts)) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + run_path_with_cstr(path.as_ref(), &|path| self.open_file_c(path, &opts)) + } + + pub fn open_with_c(path: &CStr, opts: &OpenOptions) -> io::Result { + let flags = libc::O_CLOEXEC + | libc::O_DIRECTORY + | opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !libc::O_ACCMODE); + let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + Ok(Self(unsafe { OwnedFd::from_raw_fd(fd) })) + } + + fn open_file_c(&self, path: &CStr, opts: &OpenOptions) -> io::Result { + let flags = libc::O_CLOEXEC + | opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !libc::O_ACCMODE); + let fd = cvt_r(|| unsafe { + openat64(self.0.as_raw_fd(), path.as_ptr(), flags, opts.mode as c_int) + })?; + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let fd = self.0.as_raw_fd(); + let mut b = debug_path_fd(fd, f, "Dir"); + b.finish() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsRawFd for fs::Dir { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().0.as_raw_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl IntoRawFd for fs::Dir { + fn into_raw_fd(self) -> RawFd { + self.into_inner().0.into_raw_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl FromRawFd for fs::Dir { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self::from_inner(Dir(unsafe { FromRawFd::from_raw_fd(fd) })) + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsFd for fs::Dir { + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().0.as_fd() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl From for OwnedFd { + fn from(value: fs::Dir) -> Self { + value.into_inner().0 + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl From for fs::Dir { + fn from(value: OwnedFd) -> Self { + Self::from_inner(Dir(value)) + } +} diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index f222151d18e2..069b4fb8a29c 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -4,6 +4,7 @@ use crate::fs::TryLockError; use crate::hash::{Hash, Hasher}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; +pub use crate::sys::fs::common::Dir; use crate::sys::time::SystemTime; use crate::sys::unsupported; diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index b588b91c753b..2e3d50aa0e08 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -18,6 +18,8 @@ use crate::sys::time::SystemTime; use crate::sys::{Align8, AsInner, FromInner, IntoInner, c, cvt}; use crate::{fmt, ptr, slice}; +mod dir; +pub use dir::Dir; mod remove_dir_all; use remove_dir_all::remove_dir_all_iterative; @@ -274,7 +276,7 @@ impl OpenOptions { } } - fn get_creation_mode(&self) -> io::Result { + fn get_cmode_disposition(&self) -> io::Result<(u32, u32)> { match (self.write, self.append) { (true, false) => {} (false, false) => { @@ -296,16 +298,24 @@ impl OpenOptions { } Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => c::OPEN_EXISTING, - (true, false, false) => c::OPEN_ALWAYS, - (false, true, false) => c::TRUNCATE_EXISTING, + (false, false, false) => (c::OPEN_EXISTING, c::FILE_OPEN), + (true, false, false) => (c::OPEN_ALWAYS, c::FILE_OPEN_IF), + (false, true, false) => (c::TRUNCATE_EXISTING, c::FILE_OVERWRITE), // `CREATE_ALWAYS` has weird semantics so we emulate it using // `OPEN_ALWAYS` and a manual truncation step. See #115745. - (true, true, false) => c::OPEN_ALWAYS, - (_, _, true) => c::CREATE_NEW, + (true, true, false) => (c::OPEN_ALWAYS, c::FILE_OVERWRITE_IF), + (_, _, true) => (c::CREATE_NEW, c::FILE_CREATE), }) } + fn get_creation_mode(&self) -> io::Result { + self.get_cmode_disposition().map(|(mode, _)| mode) + } + + fn get_disposition(&self) -> io::Result { + self.get_cmode_disposition().map(|(_, mode)| mode) + } + fn get_flags_and_attributes(&self) -> u32 { self.custom_flags | self.attributes @@ -1019,14 +1029,23 @@ impl FromRawHandle for File { } } +fn debug_path_handle<'a, 'b>( + handle: BorrowedHandle<'a>, + f: &'a mut fmt::Formatter<'b>, + name: &str, +) -> fmt::DebugStruct<'a, 'b> { + // FIXME(#24570): add more info here (e.g., mode) + let mut b = f.debug_struct(name); + b.field("handle", &handle.as_raw_handle()); + if let Ok(path) = get_path(handle) { + b.field("path", &path); + } + b +} + impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME(#24570): add more info here (e.g., mode) - let mut b = f.debug_struct("File"); - b.field("handle", &self.handle.as_raw_handle()); - if let Ok(path) = get_path(self) { - b.field("path", &path); - } + let mut b = debug_path_handle(self.handle.as_handle(), f, "File"); b.finish() } } @@ -1292,8 +1311,8 @@ pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> { Layout::from_size_align(struct_size as usize, align_of::()) .unwrap(); - // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. let file_rename_info; + // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. unsafe { file_rename_info = alloc(layout).cast::(); if file_rename_info.is_null() { @@ -1530,10 +1549,10 @@ pub fn set_times_nofollow(p: &WCStr, times: FileTimes) -> io::Result<()> { file.set_times(times) } -fn get_path(f: &File) -> io::Result { +fn get_path(f: impl AsRawHandle) -> io::Result { fill_utf16_buf( |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, |buf| PathBuf::from(OsString::from_wide(buf)), ) @@ -1546,7 +1565,7 @@ pub fn canonicalize(p: &WCStr) -> io::Result { // This flag is so we can open directories too opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); let f = File::open_native(p, &opts)?; - get_path(&f) + get_path(f.handle) } pub fn copy(from: &WCStr, to: &WCStr) -> io::Result { diff --git a/library/std/src/sys/fs/windows/dir.rs b/library/std/src/sys/fs/windows/dir.rs new file mode 100644 index 000000000000..3f617806c6c3 --- /dev/null +++ b/library/std/src/sys/fs/windows/dir.rs @@ -0,0 +1,153 @@ +use crate::os::windows::io::{ + AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, HandleOrInvalid, IntoRawHandle, + OwnedHandle, RawHandle, +}; +use crate::path::Path; +use crate::sys::api::{UnicodeStrRef, WinError}; +use crate::sys::fs::windows::debug_path_handle; +use crate::sys::fs::{File, OpenOptions}; +use crate::sys::handle::Handle; +use crate::sys::path::{WCStr, with_native_path}; +use crate::sys::{AsInner, FromInner, IntoInner, IoResult, c, to_u16s}; +use crate::{fmt, fs, io, ptr}; + +pub struct Dir { + handle: Handle, +} + +/// A wrapper around a raw NtCreateFile call. +/// +/// This isn't completely safe because `OBJECT_ATTRIBUTES` contains raw pointers. +unsafe fn nt_create_file( + opts: &OpenOptions, + object_attributes: &c::OBJECT_ATTRIBUTES, + create_options: c::NTCREATEFILE_CREATE_OPTIONS, +) -> io::Result { + let mut handle = ptr::null_mut(); + let mut io_status = c::IO_STATUS_BLOCK::PENDING; + // SYNCHRONIZE is included in FILE_GENERIC_READ, but not GENERIC_READ, so we add it manually + let access = opts.get_access_mode()? | c::SYNCHRONIZE; + // one of FILE_SYNCHRONOUS_IO_{,NON}ALERT is required for later operations to succeed. + let options = create_options | c::FILE_SYNCHRONOUS_IO_NONALERT; + let status = unsafe { + c::NtCreateFile( + &mut handle, + access, + object_attributes, + &mut io_status, + ptr::null(), + c::FILE_ATTRIBUTE_NORMAL, + opts.share_mode, + opts.get_disposition()?, + options, + ptr::null(), + 0, + ) + }; + if c::nt_success(status) { + // SAFETY: nt_success guarantees that handle is no longer null + unsafe { Ok(Handle::from_raw_handle(handle)) } + } else { + Err(WinError::new(unsafe { c::RtlNtStatusToDosError(status) })).io_result() + } +} + +impl Dir { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + with_native_path(path, &|path| Self::open_with_native(path, opts)) + } + + pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result { + // NtCreateFile will fail if given an absolute path and a non-null RootDirectory + if path.is_absolute() { + return File::open(path, opts); + } + let path = to_u16s(path)?; + let path = &path[..path.len() - 1]; // trim 0 byte + self.open_file_native(&path, opts).map(|handle| File { handle }) + } + + fn open_with_native(path: &WCStr, opts: &OpenOptions) -> io::Result { + let creation = opts.get_creation_mode()?; + let sa = c::SECURITY_ATTRIBUTES { + nLength: size_of::() as u32, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: opts.inherit_handle as c::BOOL, + }; + let handle = unsafe { + c::CreateFileW( + path.as_ptr(), + opts.get_access_mode()?, + opts.share_mode, + &raw const sa, + creation, + // FILE_FLAG_BACKUP_SEMANTICS is required to open a directory + opts.get_flags_and_attributes() | c::FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut(), + ) + }; + match OwnedHandle::try_from(unsafe { HandleOrInvalid::from_raw_handle(handle) }) { + Ok(handle) => Ok(Self { handle: Handle::from_inner(handle) }), + Err(_) => Err(io::Error::last_os_error()), + } + } + + fn open_file_native(&self, path: &[u16], opts: &OpenOptions) -> io::Result { + let name = UnicodeStrRef::from_slice(path); + let object_attributes = c::OBJECT_ATTRIBUTES { + RootDirectory: self.handle.as_raw_handle(), + ObjectName: name.as_ptr(), + ..c::OBJECT_ATTRIBUTES::with_length() + }; + unsafe { nt_create_file(opts, &object_attributes, c::FILE_NON_DIRECTORY_FILE) } + } +} + +impl fmt::Debug for Dir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut b = debug_path_handle(self.handle.as_handle(), f, "Dir"); + b.finish() + } +} + +#[unstable(feature = "dirfd", issue = "120426")] +impl AsRawHandle for fs::Dir { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().handle.as_raw_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl IntoRawHandle for fs::Dir { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().handle.into_raw_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl FromRawHandle for fs::Dir { + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + Self::from_inner(Dir { handle: unsafe { FromRawHandle::from_raw_handle(handle) } }) + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl AsHandle for fs::Dir { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().handle.as_handle() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl From for OwnedHandle { + fn from(value: fs::Dir) -> Self { + value.into_inner().handle.into_inner() + } +} + +#[unstable(feature = "dirhandle", issue = "120426")] +impl From for fs::Dir { + fn from(value: OwnedHandle) -> Self { + Self::from_inner(Dir { handle: Handle::from_inner(value) }) + } +} From 52d65b8a626ae074f45e19c8d8cfe41a5f5e444b Mon Sep 17 00:00:00 2001 From: Alessio Date: Sun, 4 Jan 2026 03:53:26 +0100 Subject: [PATCH 118/340] library: clarify panic conditions in `Iterator::last` Now `Iterator::last`'s docs specify that it might panic only if the iterator is infinite, rather than if it has more than `usize::MAX` elements. --- library/core/src/iter/traits/iterator.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 84da778c3b91..f106900a3983 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -238,8 +238,7 @@ pub trait Iterator { /// /// # Panics /// - /// This function might panic if the iterator has more than [`usize::MAX`] - /// elements. + /// This function might panic if the iterator is infinite. /// /// # Examples /// From 759857cce3f0b4cb72de251595ecf8c28408cead Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 4 Jan 2026 11:53:31 +0800 Subject: [PATCH 119/340] Add missing translator resources for interface parse_cfg and parse_check_cfg --- compiler/rustc_interface/src/interface.rs | 12 ++++++++++-- tests/ui/cfg/invalid-cli-cfg-pred.rs | 5 +++++ tests/ui/cfg/invalid-cli-cfg-pred.stderr | 7 +++++++ tests/ui/cfg/invalid-cli-check-cfg-pred.rs | 5 +++++ tests/ui/cfg/invalid-cli-check-cfg-pred.stderr | 10 ++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/ui/cfg/invalid-cli-cfg-pred.rs create mode 100644 tests/ui/cfg/invalid-cli-cfg-pred.stderr create mode 100644 tests/ui/cfg/invalid-cli-check-cfg-pred.rs create mode 100644 tests/ui/cfg/invalid-cli-check-cfg-pred.stderr diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c0f8f33692e8..b2c4a9158197 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -55,7 +55,11 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { let psess = ParseSess::emitter_with_note( - vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], + vec![ + crate::DEFAULT_LOCALE_RESOURCE, + rustc_parse::DEFAULT_LOCALE_RESOURCE, + rustc_session::DEFAULT_LOCALE_RESOURCE, + ], format!("this occurred on the command line: `--cfg={s}`"), ); let filename = FileName::cfg_spec_source_code(&s); @@ -129,7 +133,11 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch for s in specs { let psess = ParseSess::emitter_with_note( - vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], + vec![ + crate::DEFAULT_LOCALE_RESOURCE, + rustc_parse::DEFAULT_LOCALE_RESOURCE, + rustc_session::DEFAULT_LOCALE_RESOURCE, + ], format!("this occurred on the command line: `--check-cfg={s}`"), ); let filename = FileName::cfg_spec_source_code(&s); diff --git a/tests/ui/cfg/invalid-cli-cfg-pred.rs b/tests/ui/cfg/invalid-cli-cfg-pred.rs new file mode 100644 index 000000000000..fdfb6b18d96b --- /dev/null +++ b/tests/ui/cfg/invalid-cli-cfg-pred.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --cfg foo=1x + +fn main() {} + +//~? ERROR invalid `--cfg` argument diff --git a/tests/ui/cfg/invalid-cli-cfg-pred.stderr b/tests/ui/cfg/invalid-cli-cfg-pred.stderr new file mode 100644 index 000000000000..2f5ed55a6423 --- /dev/null +++ b/tests/ui/cfg/invalid-cli-cfg-pred.stderr @@ -0,0 +1,7 @@ +error: invalid suffix `x` for number literal + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + = note: this occurred on the command line: `--cfg=foo=1x` + +error: invalid `--cfg` argument: `foo=1x` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\") + diff --git a/tests/ui/cfg/invalid-cli-check-cfg-pred.rs b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs new file mode 100644 index 000000000000..30417a912bfc --- /dev/null +++ b/tests/ui/cfg/invalid-cli-check-cfg-pred.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --check-cfg 'foo=1x' + +fn main() {} + +//~? ERROR invalid `--check-cfg` argument diff --git a/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr b/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr new file mode 100644 index 000000000000..be8299aa9edf --- /dev/null +++ b/tests/ui/cfg/invalid-cli-check-cfg-pred.stderr @@ -0,0 +1,10 @@ +error: invalid suffix `x` for number literal + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + = note: this occurred on the command line: `--check-cfg=foo=1x` + +error: invalid `--check-cfg` argument: `foo=1x` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details + From 46bb414d69749ad7afe3ea8e0e4fd09ae7fe3d6b Mon Sep 17 00:00:00 2001 From: enthropy7 <221884178+enthropy7@users.noreply.github.com> Date: Sat, 3 Jan 2026 16:22:29 +0300 Subject: [PATCH 120/340] Forbid generic parameters in types of #[type_const] items --- compiler/rustc_resolve/src/late.rs | 58 ++++++++++++++++++- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 1 + ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 4 +- .../assoc-const-eq-bound-var-in-ty.rs | 1 + .../assoc-const-eq-esc-bound-var-in-ty.rs | 7 ++- .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-param-in-ty.rs | 1 + .../assoc-const-eq-param-in-ty.stderr | 22 +++---- .../assoc-const-eq-supertraits.rs | 1 + ...pe_const-generic-param-in-type.gate.stderr | 38 ++++++++++++ ..._const-generic-param-in-type.nogate.stderr | 57 ++++++++++++++++++ .../mgca/type_const-generic-param-in-type.rs | 54 +++++++++++++++++ 12 files changed, 228 insertions(+), 18 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd80f5da508c..2bbaacce53f8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2855,6 +2855,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ref define_opaque, .. }) => { + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::Item( @@ -2873,7 +2874,22 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static), - |this| this.visit_ty(ty), + |this| { + if is_type_const + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } + }, ); if let Some(rhs) = rhs { @@ -3213,6 +3229,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { define_opaque, .. }) => { + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3227,7 +3244,20 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| { this.visit_generics(generics); - this.visit_ty(ty); + if is_type_const + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. @@ -3422,6 +3452,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .. }) => { debug!("resolve_implementation AssocItemKind::Const"); + let is_type_const = attr::contains_name(&item.attrs, sym::type_const); self.with_generic_param_rib( &generics.params, RibKind::AssocItem, @@ -3458,7 +3489,28 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); this.visit_generics(generics); - this.visit_ty(ty); + if is_type_const + && !this + .r + .tcx + .features() + .generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib( + ValueNS, + RibKind::ConstParamTy, + |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }, + ) + }); + } else { + this.visit_ty(ty); + } if let Some(rhs) = rhs { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. 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 7f8b3036c3e8..50914fb192ff 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 @@ -5,6 +5,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] 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 76868715b861..fd49e151b8e6 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,11 +1,11 @@ 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:22:13 | 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:22:13 | LL | K = const { () } | ^^^^^^^^^^^^ 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 d3975bc19ad3..54e199d702c9 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 @@ -8,6 +8,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] 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 2571af57e66b..7f9a04bbf0fc 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 @@ -1,6 +1,11 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature( + associated_const_equality, + min_generic_const_args, + unsized_const_params, + generic_const_parameter_types, +)] #![allow(incomplete_features)] trait Trait<'a> { 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 44304443ac54..e22d9bfed7ef 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,5 +1,5 @@ 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 + --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:16:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` 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 242ad385947a..ea2f60cd6187 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 @@ -5,6 +5,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] 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 b742e68044b0..ae6a35b4b9f2 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,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | -- the lifetime parameter `'r` is defined here @@ -10,7 +10,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the type parameter `A` is defined here @@ -21,7 +21,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:22:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the const parameter `Q` is defined here @@ -32,7 +32,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:39:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:40:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------------ @@ -41,7 +41,7 @@ LL | fn take1(_: impl Project) {} | 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:44:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:45:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -51,7 +51,7 @@ 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -62,7 +62,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -70,7 +70,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -80,7 +80,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -92,7 +92,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -101,7 +101,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:53:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:54:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs index d9b8a8cd43d7..c092285dfcd4 100644 --- a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -8,6 +8,7 @@ min_generic_const_args, adt_const_params, unsized_const_params, + generic_const_parameter_types, )] #![allow(incomplete_features)] diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr new file mode 100644 index 000000000000..8a64af285da5 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.gate.stderr @@ -0,0 +1,38 @@ +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:9:53 + | +LL | const FOO: [T; 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:14:38 + | +LL | const BAR: [(); N] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants with lifetimes in their type are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:19:30 + | +LL | const BAZ<'a>: [&'a (); 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:39:59 + | +LL | const ASSOC: [T; 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants referencing generics are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:44:50 + | +LL | const ASSOC_CONST: [(); N] = const { [] }; + | ^^^^^^^^^^^^ + +error: anonymous constants with lifetimes in their type are not yet supported + --> $DIR/type_const-generic-param-in-type.rs:49:39 + | +LL | const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + | ^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr new file mode 100644 index 000000000000..14ae276324ad --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.nogate.stderr @@ -0,0 +1,57 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:9:45 + | +LL | const FOO: [T; 0] = const { [] }; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:14:33 + | +LL | const BAR: [(); N] = const { [] }; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:19:18 + | +LL | const BAZ<'a>: [&'a (); 0] = const { [] }; + | ^^ the type must not depend on the parameter `'a` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:25:51 + | +LL | const ASSOC: [T; 0]; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:29:45 + | +LL | const ASSOC_CONST: [(); N]; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:33:27 + | +LL | const ASSOC_LT<'a>: [&'a (); 0]; + | ^^ the type must not depend on the parameter `'a` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:39:51 + | +LL | const ASSOC: [T; 0] = const { [] }; + | ^ the type must not depend on the parameter `T` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:44:45 + | +LL | const ASSOC_CONST: [(); N] = const { [] }; + | ^ the type must not depend on the parameter `N` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/type_const-generic-param-in-type.rs:49:27 + | +LL | const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + | ^^ the type must not depend on the parameter `'a` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs new file mode 100644 index 000000000000..f1a4aba9bcee --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-generic-param-in-type.rs @@ -0,0 +1,54 @@ +//@ revisions: nogate gate +//@ [gate] check-fail +// FIXME(generic_const_parameter_types): this should pass +#![expect(incomplete_features)] +#![feature(adt_const_params, unsized_const_params, min_generic_const_args, generic_const_items)] +#![cfg_attr(gate, feature(generic_const_parameter_types))] + +#[type_const] +const FOO: [T; 0] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + +#[type_const] +const BAR: [(); N] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + +#[type_const] +const BAZ<'a>: [&'a (); 0] = const { [] }; +//[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +//[gate]~^^ ERROR anonymous constants with lifetimes in their type are not yet supported + +trait Tr { + #[type_const] + const ASSOC: [T; 0]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + + #[type_const] + const ASSOC_CONST: [(); N]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + + #[type_const] + const ASSOC_LT<'a>: [&'a (); 0]; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters +} + +impl Tr for () { + #[type_const] + const ASSOC: [T; 0] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + + #[type_const] + const ASSOC_CONST: [(); N] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants referencing generics are not yet supported + + #[type_const] + const ASSOC_LT<'a>: [&'a (); 0] = const { [] }; + //[nogate]~^ ERROR the type of const parameters must not depend on other generic parameters + //[gate]~^^ ERROR anonymous constants with lifetimes in their type are not yet supported +} + +fn main() {} From de377241fb6490ed92fc8c9b6d9d2a0428da26f8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 4 Jan 2026 14:12:40 +1100 Subject: [PATCH 121/340] Prefer to pass HIR nodes instead of loose types/spans This should make it easier to keep track of where the types/spans came from. --- .../rustc_mir_build/src/thir/pattern/mod.rs | 91 +++++++++++++------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0310003e7d58..988baae49141 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -4,6 +4,7 @@ mod check_match; mod const_to_pat; mod migration; +use std::assert_matches::assert_matches; use std::cmp::Ordering; use std::sync::Arc; @@ -21,7 +22,7 @@ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::ErrorGuaranteed; use tracing::{debug, instrument}; pub(crate) use self::check_match::check_match; @@ -129,15 +130,20 @@ impl<'tcx> PatCtxt<'tcx> { fn lower_pattern_range_endpoint( &mut self, + pat: &'tcx hir::Pat<'tcx>, // Range pattern containing the endpoint expr: Option<&'tcx hir::PatExpr<'tcx>>, // Out-parameter collecting extra data to be reapplied by the caller ascriptions: &mut Vec>, ) -> Result>, ErrorGuaranteed> { + assert_matches!(pat.kind, hir::PatKind::Range(..)); + + // For partly-bounded ranges like `X..` or `..X`, an endpoint will be absent. + // Return None in that case; the caller will use NegInfinity or PosInfinity instead. let Some(expr) = expr else { return Ok(None) }; // Lower the endpoint into a temporary `PatKind` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(expr, None); + let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr); // Unpeel any ascription or inline-const wrapper nodes. loop { @@ -214,12 +220,14 @@ impl<'tcx> PatCtxt<'tcx> { fn lower_pattern_range( &mut self, + pat: &'tcx hir::Pat<'tcx>, lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, - ty: Ty<'tcx>, - span: Span, ) -> Result, ErrorGuaranteed> { + let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; + if lo_expr.is_none() && hi_expr.is_none() { let msg = "found twice-open range pattern (`..`) outside of error recovery"; self.tcx.dcx().span_bug(span, msg); @@ -227,7 +235,8 @@ impl<'tcx> PatCtxt<'tcx> { // Collect extra data while lowering the endpoints, to be reapplied later. let mut ascriptions = vec![]; - let mut lower_endpoint = |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions); + let mut lower_endpoint = + |expr| self.lower_pattern_range_endpoint(pat, expr, &mut ascriptions); let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity); let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); @@ -299,12 +308,10 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(value, Some(ty)), + hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value), - hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { - let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); - self.lower_pattern_range(lo_expr, hi_expr, end, ty, span) - .unwrap_or_else(PatKind::Error) + hir::PatKind::Range(lo_expr, hi_expr, end) => { + self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error) } hir::PatKind::Deref(subpattern) => { @@ -327,7 +334,7 @@ impl<'tcx> PatCtxt<'tcx> { }, hir::PatKind::Slice(prefix, slice, suffix) => { - self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) + self.slice_or_array_pattern(pat, prefix, slice, suffix) } hir::PatKind::Tuple(pats, ddpos) => { @@ -389,7 +396,7 @@ impl<'tcx> PatCtxt<'tcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(pat, None, res, subpatterns) } hir::PatKind::Struct(ref qpath, fields, _) => { @@ -406,7 +413,7 @@ impl<'tcx> PatCtxt<'tcx> { }) .collect(); - self.lower_variant_or_leaf(res, pat.hir_id, pat.span, ty, subpatterns) + self.lower_variant_or_leaf(pat, None, res, subpatterns) } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -445,12 +452,13 @@ impl<'tcx> PatCtxt<'tcx> { fn slice_or_array_pattern( &mut self, - span: Span, - ty: Ty<'tcx>, + pat: &'tcx hir::Pat<'tcx>, prefix: &'tcx [hir::Pat<'tcx>], slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], ) -> PatKind<'tcx> { + let ty = self.typeck_results.node_type(pat.hir_id); + let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); @@ -465,18 +473,32 @@ impl<'tcx> PatCtxt<'tcx> { assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } - _ => span_bug!(span, "bad slice pattern type {:?}", ty), + _ => span_bug!(pat.span, "bad slice pattern type {ty:?}"), } } fn lower_variant_or_leaf( &mut self, + pat: &'tcx hir::Pat<'tcx>, + expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, - hir_id: hir::HirId, - span: Span, - ty: Ty<'tcx>, subpatterns: Vec>, ) -> PatKind<'tcx> { + // Check whether the caller should have provided an `expr` for this pattern kind. + assert_matches!( + (pat.kind, expr), + (hir::PatKind::Expr(..) | hir::PatKind::Range(..), Some(_)) + | (hir::PatKind::Struct(..) | hir::PatKind::TupleStruct(..), None) + ); + + // Use the id/span of the `hir::PatExpr`, if provided. + // Otherwise, use the id/span of the `hir::Pat`. + let (hir_id, span) = match expr { + Some(expr) => (expr.hir_id, expr.span), + None => (pat.hir_id, pat.span), + }; + let ty = self.typeck_results.node_type(hir_id); + let res = match res { Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { let variant_id = self.tcx.parent(variant_ctor_id); @@ -563,7 +585,16 @@ impl<'tcx> PatCtxt<'tcx> { /// it to `const_to_pat`. Any other path (like enum variants without fields) /// is converted to the corresponding pattern via `lower_variant_or_leaf`. #[instrument(skip(self), level = "debug")] - fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box> { + fn lower_path( + &mut self, + pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` + expr: &'tcx hir::PatExpr<'tcx>, + qpath: &hir::QPath<'_>, + ) -> Box> { + assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); + + let id = expr.hir_id; + let span = expr.span; let ty = self.typeck_results.node_type(id); let res = self.typeck_results.qpath_res(qpath, id); @@ -575,7 +606,7 @@ impl<'tcx> PatCtxt<'tcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - let kind = self.lower_variant_or_leaf(res, id, span, ty, vec![]); + let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); return Box::new(Pat { span, ty, kind }); } }; @@ -615,24 +646,26 @@ impl<'tcx> PatCtxt<'tcx> { /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`) fn lower_pat_expr( &mut self, + pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` expr: &'tcx hir::PatExpr<'tcx>, - pat_ty: Option>, ) -> PatKind<'tcx> { + assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); match &expr.kind { - hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind, + hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind, hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the // pattern's type means we'll properly translate it to a slice reference pattern. This works // because slices and arrays have the same valtree representation. - let ct_ty = match pat_ty { - Some(pat_ty) => pat_ty, - None => self.typeck_results.node_type(expr.hir_id), - }; - let lit_input = LitToConstInput { lit: lit.node, ty: ct_ty, neg: *negated }; + // + // Under `feature(deref_patterns)`, this adjustment can also convert string literal + // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`. + + let pat_ty = self.typeck_results.node_type(pat.hir_id); + let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind + self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind } } } From 7c02e3c6ebfaa9d70d7a358dfe3209d110b2c618 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 4 Jan 2026 17:44:15 +0900 Subject: [PATCH 122/340] Fix ambig-unambig-ty-and-consts link --- compiler/rustc_hir/src/hir.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index da3e79efd6df..817eddefe5e8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -440,7 +440,7 @@ impl<'hir> ConstItemRhs<'hir> { /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(C)] pub struct ConstArg<'hir, Unambig = ()> { @@ -3374,7 +3374,7 @@ pub enum AmbigArg {} /// Represents a type in the `HIR`. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// #[derive(Debug, Clone, Copy, HashStable_Generic)] #[repr(C)] pub struct Ty<'hir, Unambig = ()> { @@ -3713,7 +3713,7 @@ pub enum InferDelegationKind { /// The various kinds of types recognized by the compiler. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// +/// // SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind` are layout compatible #[repr(u8, C)] #[derive(Debug, Clone, Copy, HashStable_Generic)] From 65639fe0dcca82defbcc3dac91a33c94ccddf303 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 4 Jan 2026 04:15:05 -0500 Subject: [PATCH 123/340] ci: Move the dependency installs and wall time benchmarks to scripts Make it easier to run the same steps outside of GitHub Actions. --- .../.github/workflows/main.yaml | 21 +++---------------- library/compiler-builtins/ci/bench-runtime.sh | 9 ++++++++ .../ci/install-bench-deps.sh | 11 ++++++++++ 3 files changed, 23 insertions(+), 18 deletions(-) create mode 100755 library/compiler-builtins/ci/bench-runtime.sh create mode 100755 library/compiler-builtins/ci/install-bench-deps.sh diff --git a/library/compiler-builtins/.github/workflows/main.yaml b/library/compiler-builtins/.github/workflows/main.yaml index 38995cf0f0ff..699a9c417dde 100644 --- a/library/compiler-builtins/.github/workflows/main.yaml +++ b/library/compiler-builtins/.github/workflows/main.yaml @@ -203,7 +203,7 @@ jobs: # Unlike rustfmt, stable clippy does not work on code with nightly features. - name: Install nightly `clippy` run: | - rustup set profile minimal + rustup update nightly --no-self-update rustup default nightly rustup component add clippy - uses: Swatinem/rust-cache@v2 @@ -247,16 +247,7 @@ jobs: - uses: taiki-e/install-action@cargo-binstall - name: Set up dependencies - run: | - sudo apt-get update - sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun - rustup update "$BENCHMARK_RUSTC" --no-self-update - rustup default "$BENCHMARK_RUSTC" - # Install the version of gungraun-runner that is specified in Cargo.toml - gungraun_version="$(cargo metadata --format-version=1 --features icount | - jq -r '.packages[] | select(.name == "gungraun").version')" - cargo binstall -y gungraun-runner --version "$gungraun_version" - sudo apt-get install valgrind + run: ./ci/install-bench-deps.sh - uses: Swatinem/rust-cache@v2 with: key: ${{ matrix.target }} @@ -276,13 +267,7 @@ jobs: path: ${{ env.BASELINE_NAME }}.tar.xz - name: Run wall time benchmarks - run: | - # Always use the same seed for benchmarks. Ideally we should switch to a - # non-random generator. - export LIBM_SEED=benchesbenchesbenchesbencheswoo! - cargo bench --package libm-test \ - --no-default-features \ - --features short-benchmarks,build-musl,libm/force-soft-floats + run: ./ci/bench-runtime.sh - name: Print test logs if available if: always() diff --git a/library/compiler-builtins/ci/bench-runtime.sh b/library/compiler-builtins/ci/bench-runtime.sh new file mode 100755 index 000000000000..d272cf33463e --- /dev/null +++ b/library/compiler-builtins/ci/bench-runtime.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# Run wall time benchmarks as we do on CI. + +# Always use the same seed for benchmarks. Ideally we should switch to a +# non-random generator. +export LIBM_SEED=benchesbenchesbenchesbencheswoo! +cargo bench --package libm-test \ + --no-default-features \ + --features short-benchmarks,build-musl,libm/force-soft-floats diff --git a/library/compiler-builtins/ci/install-bench-deps.sh b/library/compiler-builtins/ci/install-bench-deps.sh new file mode 100755 index 000000000000..61f4723c0358 --- /dev/null +++ b/library/compiler-builtins/ci/install-bench-deps.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Install needed dependencies for gungraun. + +sudo apt-get update +sudo apt-get install -y valgrind gdb libc6-dbg # Needed for gungraun +rustup update "$BENCHMARK_RUSTC" --no-self-update +rustup default "$BENCHMARK_RUSTC" +# Install the version of gungraun-runner that is specified in Cargo.toml +gungraun_version="$(cargo metadata --format-version=1 --features icount | + jq -r '.packages[] | select(.name == "gungraun").version')" +cargo binstall -y gungraun-runner --version "$gungraun_version" From d4b9ea2e865f8de6fe994f1e9a7c0fa80b83dcbf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 4 Jan 2026 11:44:42 +0100 Subject: [PATCH 124/340] internal: Clean up proc-macro-srv callback trait --- .../crates/base-db/src/editioned_file_id.rs | 3 ++ .../rust-analyzer/crates/hir-expand/src/db.rs | 14 +++++++-- .../crates/hir-expand/src/lib.rs | 24 ++++----------- .../crates/load-cargo/src/lib.rs | 29 +++++++++---------- .../crates/proc-macro-srv-cli/Cargo.toml | 1 + .../proc-macro-srv-cli/src/main_loop.rs | 22 +++++++++----- .../crates/proc-macro-srv/src/lib.rs | 7 +++-- .../src/server_impl/rust_analyzer_span.rs | 19 ++---------- 8 files changed, 58 insertions(+), 61 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs index e2791ffe6f0a..13fb05d56547 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs @@ -26,6 +26,9 @@ const _: () = { krate: Crate, } + // FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a + // different crate then whatever the input of a memo used, it will invalidate the memo causing + // it to recompute even if the crate is not really used. /// We like to include the origin crate in an `EditionedFileId` (for use in the item tree), /// but this poses us a problem. /// diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 40d44cd1dba2..51767f87ffb9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -9,8 +9,8 @@ use triomphe::Arc; use crate::{ AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, - EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId, - MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, + EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, FileRange, HirFileId, + MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, attrs::Meta, builtin::pseudo_derive_attr_expansion, cfg_process::attr_macro_input_to_token_tree, @@ -61,6 +61,9 @@ pub trait ExpandDatabase: RootQueryDb { #[salsa::lru(1024)] fn ast_id_map(&self, file_id: HirFileId) -> Arc; + #[salsa::transparent] + fn resolve_span(&self, span: Span) -> FileRange; + #[salsa::transparent] fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode; @@ -158,6 +161,13 @@ fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> } } +fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) -> FileRange { + let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); + let anchor_offset = + db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); + FileRange { file_id, range: range + anchor_offset } +} + /// This expands the given macro call, but with different arguments. This is /// used for completion, where we want to see what 'would happen' if we insert a /// token. The `token_to_map` mapped down into the expansion, with the mapped diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 7b6a6135b350..05541e782efd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -901,11 +901,8 @@ impl ExpansionInfo { let span = self.exp_map.span_at(token.start()); match &self.arg_map { SpanMap::RealSpanMap(_) => { - let file_id = - EditionedFileId::from_span_guess_origin(db, span.anchor.file_id).into(); - let anchor_offset = - db.ast_id_map(file_id).get_erased(span.anchor.ast_id).text_range().start(); - InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] } + let range = db.resolve_span(span); + InFile { file_id: range.file_id.into(), value: smallvec::smallvec![range.range] } } SpanMap::ExpansionSpanMap(arg_map) => { let Some(arg_node) = &self.arg.value else { @@ -947,7 +944,7 @@ pub fn map_node_range_up_rooted( range: TextRange, ) -> Option { let mut spans = exp_map.spans_for_range(range).filter(|span| span.ctx.is_root()); - let Span { range, anchor, ctx: _ } = spans.next()?; + let Span { range, anchor, ctx } = spans.next()?; let mut start = range.start(); let mut end = range.end(); @@ -958,10 +955,7 @@ pub fn map_node_range_up_rooted( start = start.min(span.range.start()); end = end.max(span.range.end()); } - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); - Some(FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }) + Some(db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx })) } /// Maps up the text range out of the expansion hierarchy back into the original file its from. @@ -984,10 +978,7 @@ pub fn map_node_range_up( start = start.min(span.range.start()); end = end.max(span.range.end()); } - let file_id = EditionedFileId::from_span_guess_origin(db, anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(anchor.ast_id).text_range().start(); - Some((FileRange { file_id, range: TextRange::new(start, end) + anchor_offset }, ctx)) + Some((db.resolve_span(Span { range: TextRange::new(start, end), anchor, ctx }), ctx)) } /// Looks up the span at the given offset. @@ -997,10 +988,7 @@ pub fn span_for_offset( offset: TextSize, ) -> (FileRange, SyntaxContext) { let span = exp_map.span_at(offset); - let file_id = EditionedFileId::from_span_guess_origin(db, span.anchor.file_id); - let anchor_offset = - db.ast_id_map(file_id.into()).get_erased(span.anchor.ast_id).text_range().start(); - (FileRange { file_id, range: span.range + anchor_offset }, span.ctx) + (db.resolve_span(span), span.ctx) } /// In Rust, macros expand token trees to token trees. When we want to turn a 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 c302e266febd..e8d98b1ce661 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -19,7 +19,7 @@ use hir_expand::{ }, }; use ide_db::{ - ChangeWithProcMacros, EditionedFileId, FxHashMap, RootDatabase, + ChangeWithProcMacros, FxHashMap, RootDatabase, base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId}, prime_caches, }; @@ -32,7 +32,8 @@ use proc_macro_api::{ }, }; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; -use span::Span; +use span::{Span, SpanAnchor, SyntaxContext}; +use tt::{TextRange, TextSize}; use vfs::{ AbsPath, AbsPathBuf, FileId, VfsPath, file_set::FileSetConfig, @@ -553,20 +554,18 @@ impl ProcMacroExpander for Expander { Ok(SubResponse::LocalFilePathResult { name }) } SubRequest::SourceText { file_id, ast_id, start, end } => { - let raw_file_id = FileId::from_raw(file_id); - let editioned_file_id = span::EditionedFileId::from_raw(file_id); let ast_id = span::ErasedFileAstId::from_raw(ast_id); - let hir_file_id = EditionedFileId::from_span_guess_origin(db, editioned_file_id); - let anchor_offset = db - .ast_id_map(hir_expand::HirFileId::FileId(hir_file_id)) - .get_erased(ast_id) - .text_range() - .start(); - let anchor_offset = u32::from(anchor_offset); - let abs_start = start + anchor_offset; - let abs_end = end + anchor_offset; - let source = db.file_text(raw_file_id).text(db); - let text = source.get(abs_start as usize..abs_end as usize).map(ToOwned::to_owned); + let editioned_file_id = span::EditionedFileId::from_raw(file_id); + let span = Span { + range: TextRange::new(TextSize::from(start), TextSize::from(end)), + anchor: SpanAnchor { file_id: editioned_file_id, ast_id }, + ctx: SyntaxContext::root(editioned_file_id.edition()), + }; + let range = db.resolve_span(span); + let source = db.file_text(range.file_id.file_id(db)).text(db); + let text = source + .get(usize::from(range.range.start())..usize::from(range.range.end())) + .map(ToOwned::to_owned); Ok(SubResponse::SourceTextResult { text }) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 2c6e5a16ee06..6b2db0b269d5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -18,6 +18,7 @@ clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] default = [] +# default = ["sysroot-abi"] sysroot-abi = ["proc-macro-srv/sysroot-abi", "proc-macro-api/sysroot-abi"] in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 4891e073142d..b2f4b96bd255 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -185,8 +185,8 @@ impl<'a, C: Codec> ProcMacroClientHandle<'a, C> { } impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { - fn file(&mut self, file_id: u32) -> String { - match self.roundtrip(bidirectional::SubRequest::FilePath { file_id }) { + fn file(&mut self, file_id: proc_macro_srv::span::FileId) -> String { + match self.roundtrip(bidirectional::SubRequest::FilePath { file_id: file_id.index() }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::FilePathResult { name }, )) => name, @@ -194,9 +194,16 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::SourceText { file_id, ast_id, start, end }) - { + fn source_text( + &mut self, + proc_macro_srv::span::Span { range, anchor, ctx: _ }: proc_macro_srv::span::Span, + ) -> Option { + match self.roundtrip(bidirectional::SubRequest::SourceText { + file_id: anchor.file_id.as_u32(), + ast_id: anchor.ast_id.into_raw(), + start: range.start().into(), + end: range.end().into(), + }) { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::SourceTextResult { text }, )) => text, @@ -204,8 +211,9 @@ impl proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandl } } - fn local_file(&mut self, file_id: u32) -> Option { - match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id }) { + fn local_file(&mut self, file_id: proc_macro_srv::span::FileId) -> Option { + match self.roundtrip(bidirectional::SubRequest::LocalFilePath { file_id: file_id.index() }) + { Some(bidirectional::BidirectionalMessage::SubResponse( bidirectional::SubResponse::LocalFilePathResult { name }, )) => name, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index d63aea947c1d..f2d1dfbba4cc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -53,6 +53,7 @@ use temp_dir::TempDir; pub use crate::server_impl::token_id::SpanId; pub use proc_macro::Delimiter; +pub use span; pub use crate::bridge::*; pub use crate::server_impl::literal_from_str; @@ -94,9 +95,9 @@ impl<'env> ProcMacroSrv<'env> { pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send); pub trait ProcMacroClientInterface { - fn file(&mut self, file_id: u32) -> String; - fn source_text(&mut self, file_id: u32, ast_id: u32, start: u32, end: u32) -> Option; - fn local_file(&mut self, file_id: u32) -> Option; + fn file(&mut self, file_id: span::FileId) -> String; + fn source_text(&mut self, span: Span) -> Option; + fn local_file(&mut self, file_id: span::FileId) -> Option; } const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 2ce3b717cb0d..32725afc5527 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -128,13 +128,10 @@ impl server::Span for RaSpanServer<'_> { format!("{:?}", span) } fn file(&mut self, span: Self::Span) -> String { - self.callback - .as_mut() - .map(|cb| cb.file(span.anchor.file_id.file_id().index())) - .unwrap_or_default() + self.callback.as_mut().map(|cb| cb.file(span.anchor.file_id.file_id())).unwrap_or_default() } fn local_file(&mut self, span: Self::Span) -> Option { - self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id().index())) + self.callback.as_mut().and_then(|cb| cb.local_file(span.anchor.file_id.file_id())) } fn save_span(&mut self, _span: Self::Span) -> usize { // FIXME, quote is incompatible with third-party tools @@ -153,17 +150,7 @@ impl server::Span for RaSpanServer<'_> { /// See PR: /// https://github.com/rust-lang/rust/pull/55780 fn source_text(&mut self, span: Self::Span) -> Option { - let file_id = span.anchor.file_id; - let ast_id = span.anchor.ast_id; - let start: u32 = span.range.start().into(); - let end: u32 = span.range.end().into(); - - self.callback.as_mut()?.source_text( - file_id.file_id().index(), - ast_id.into_raw(), - start, - end, - ) + self.callback.as_mut()?.source_text(span) } fn parent(&mut self, _span: Self::Span) -> Option { From 50b78f1bb4c8bd3a0c2d5cb5b4323be16121354d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 4 Jan 2026 12:08:50 +0100 Subject: [PATCH 125/340] Add a README.md to proc-macro-srv-cli --- .../crates/proc-macro-srv-cli/README.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md new file mode 100644 index 000000000000..02a67ac3ecc1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/README.md @@ -0,0 +1,65 @@ +# proc-macro-srv-cli + +A standalone binary for the `proc-macro-srv` crate that provides procedural macro expansion for rust-analyzer. + +## Overview + +rust-analyzer uses a RPC (via stdio) client-server architecture for procedural macro expansion. This is necessary because: + +1. Proc macros are dynamic libraries that can segfault, bringing down the entire process, so running them out of process allows rust-analyzer to recover from fatal errors. +2. Proc macro dylibs are compiled against a specific rustc version and require matching internal APIs to load and execute, as such having this binary shipped as a rustup component allows us to always match the rustc version irrespective of the rust-analyzer version used. + +## The `sysroot-abi` Feature + +**The `sysroot-abi` feature is required for the binary to actually function.** Without it, the binary will return an error: + +``` +proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function +``` + +This feature is necessary because the proc-macro server needs access to unstable rustc internals (`proc_macro_internals`, `proc_macro_diagnostic`, `proc_macro_span`) which are only available on nightly or with `RUSTC_BOOTSTRAP=1`. +rust-analyzer is a stable toolchain project though, so the feature flag is used to have it remain compilable on stable by default. + +### Building + +```bash +# Using nightly toolchain +cargo build -p proc-macro-srv-cli --features sysroot-abi + +# Or with RUSTC_BOOTSTRAP on stable +RUSTC_BOOTSTRAP=1 cargo build -p proc-macro-srv-cli --features sysroot-abi +``` + +### Installing the proc-macro server + +For local testing purposes, you can install the proc-macro server using the xtask command: + +```bash +# Recommended: use the xtask command +cargo xtask install --proc-macro-server +``` + +## Testing + +```bash +cargo test --features sysroot-abi -p proc-macro-srv -p proc-macro-srv-cli -p proc-macro-api +``` + +The tests use a test proc macro dylib built by the `proc-macro-test` crate, which compiles a small proc macro implementation during build time. + +**Note**: Tests only compile on nightly toolchains (or with `RUSTC_BOOTSTRAP=1`). + +## Usage + +The binary requires the `RUST_ANALYZER_INTERNALS_DO_NOT_USE` environment variable to be set. This is intentional—the binary is an implementation detail of rust-analyzer and its API is still unstable: + +```bash +RUST_ANALYZER_INTERNALS_DO_NOT_USE=1 rust-analyzer-proc-macro-srv --version +``` + +## Related Crates + +- `proc-macro-srv`: The core server library that handles loading dylibs and expanding macros, but not the RPC protocol. +- `proc-macro-api`: The client library used by rust-analyzer to communicate with this server as well as the protocol definitions. +- `proc-macro-test`: Test harness with sample proc macros for testing +- `proc-macro-srv-cli`: The actual server binary that handles the RPC protocol. From d7fa6e527fef7337dc25b1e824664dd5847ba4a2 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 4 Jan 2026 22:56:17 +0900 Subject: [PATCH 126/340] enrich error info when tries to dlopen Enzyme --- compiler/rustc_codegen_llvm/messages.ftl | 3 ++- compiler/rustc_codegen_llvm/src/errors.rs | 5 ++++- compiler/rustc_codegen_llvm/src/lib.rs | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index a637ae8184b4..018d240b2ae5 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,4 +1,5 @@ -codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. Did you install it via rustup? +codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. + .note = load error: {$err} codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index c73140e041b6..439664b8b9a2 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -34,7 +34,10 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_component_unavailable)] -pub(crate) struct AutoDiffComponentUnavailable; +#[note] +pub(crate) struct AutoDiffComponentUnavailable { + pub err: String, +} #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_lto)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 095274744993..801d23342973 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -249,8 +249,10 @@ impl CodegenBackend for LlvmCodegenBackend { use crate::back::lto::enable_autodiff_settings; if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { - if let Err(_) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable); + if let Err(err) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { + err: format!("{err:?}"), + }); } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } From fa584faca5387010e37bc8172529be3b3776e0cc Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Sun, 4 Jan 2026 06:56:48 -0800 Subject: [PATCH 127/340] Update test and verify that tgt_(un)register_lib have the right type --- compiler/rustc_codegen_llvm/src/base.rs | 9 +++- .../src/builder/gpu_offload.rs | 5 ++- compiler/rustc_session/src/config.rs | 2 + compiler/rustc_session/src/options.rs | 10 ++++- tests/codegen-llvm/gpu_offload/gpu_host.rs | 42 +++++++++---------- 5 files changed, 40 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 388118f9b4f1..d00e70638b45 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -93,8 +93,13 @@ pub(crate) fn compile_codegen_unit( // They are necessary for correct offload execution. We do this here to simplify the // `offload` intrinsic, avoiding the need for tracking whether it's the first // intrinsic call or not. - let has_host_offload = - cx.sess().opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Host(_))); + let has_host_offload = cx + .sess() + .opts + .unstable_opts + .offload + .iter() + .any(|o| matches!(o, Offload::Host(_) | Offload::Test)); if has_host_offload && !cx.sess().target.is_like_gpu { cx.offload_globals.replace(Some(OffloadGlobals::declare(&cx))); } diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index fba92f996aa6..b8eb4f038216 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -49,8 +49,9 @@ impl<'ll> OffloadGlobals<'ll> { let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc"); cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false); - let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", mapper_fn_ty); - let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", mapper_fn_ty); + let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void()); + let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl); + let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl); let init_ty = cx.type_func(&[], cx.type_void()); let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fe96dabf6330..8c492fcf8f15 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -196,6 +196,8 @@ pub enum Offload { Device, /// Second step in the offload pipeline, generates the host code to call kernels. Host(String), + /// Test is similar to Host, but allows testing without a device artifact. + Test, } /// The different settings that the `-Z autodiff` flag can have. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f11ad12fb9dd..21fa3321a30a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -794,7 +794,8 @@ mod desc { pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`, `NoTT`"; - pub(crate) const parse_offload: &str = "a comma separated list of settings: `Enable`"; + pub(crate) const parse_offload: &str = + "a comma separated list of settings: `Host=`, `Device`, `Test`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1471,6 +1472,13 @@ pub mod parse { } Offload::Device } + "Test" => { + if let Some(_) = arg { + // Test does not accept a value + return false; + } + Offload::Test + } _ => { // FIXME(ZuseZ4): print an error saying which value is not recognized return false; diff --git a/tests/codegen-llvm/gpu_offload/gpu_host.rs b/tests/codegen-llvm/gpu_offload/gpu_host.rs index b4d17143720a..dcbd65b14427 100644 --- a/tests/codegen-llvm/gpu_offload/gpu_host.rs +++ b/tests/codegen-llvm/gpu_offload/gpu_host.rs @@ -1,15 +1,10 @@ -//@ compile-flags: -Zoffload=Enable -Zunstable-options -C opt-level=3 -Clto=fat +//@ compile-flags: -Zoffload=Test -Zunstable-options -C opt-level=3 -Clto=fat //@ no-prefer-dynamic -//@ needs-enzyme +//@ needs-offload // This test is verifying that we generate __tgt_target_data_*_mapper before and after a call to the // kernel_1. Better documentation to what each global or variable means is available in the gpu -// offlaod code, or the LLVM offload documentation. This code does not launch any GPU kernels yet, -// and will be rewritten once a proper offload frontend has landed. -// -// We currently only handle memory transfer for specific calls to functions named `kernel_{num}`, -// when inside of a function called main. This, too, is a temporary workaround for not having a -// frontend. +// offload code, or the LLVM offload documentation. #![feature(rustc_attrs)] #![feature(core_intrinsics)] @@ -22,6 +17,20 @@ fn main() { core::hint::black_box(&x); } +#[unsafe(no_mangle)] +#[inline(never)] +pub fn kernel_1(x: &mut [f32; 256]) { + core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) +} + +#[unsafe(no_mangle)] +#[inline(never)] +pub fn _kernel_1(x: &mut [f32; 256]) { + for i in 0..256 { + x[i] = 21.0; + } +} + // CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr } // CHECK: %struct.__tgt_offload_entry = type { i64, i16, i16, i32, ptr, ptr, i64, i64, ptr } // CHECK: %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr } @@ -36,8 +45,9 @@ fn main() { // CHECK: @.offloading.entry_name._kernel_1 = internal unnamed_addr constant [10 x i8] c"_kernel_1\00", section ".llvm.rodata.offloading", align 1 // CHECK: @.offloading.entry._kernel_1 = internal constant %struct.__tgt_offload_entry { i64 0, i16 1, i16 1, i32 0, ptr @._kernel_1.region_id, ptr @.offloading.entry_name._kernel_1, i64 0, i64 0, ptr null }, section "llvm_offload_entries", align 8 -// CHECK: Function Attrs: nounwind // CHECK: declare i32 @__tgt_target_kernel(ptr, i64, i32, i32, ptr, ptr) +// CHECK: declare void @__tgt_register_lib(ptr) local_unnamed_addr +// CHECK: declare void @__tgt_unregister_lib(ptr) local_unnamed_addr // CHECK: define{{( dso_local)?}} void @main() // CHECK-NEXT: start: @@ -94,17 +104,3 @@ fn main() { // CHECK-NEXT: call void @__tgt_unregister_lib(ptr nonnull %EmptyDesc) // CHECK-NEXT: ret void // CHECK-NEXT: } - -#[unsafe(no_mangle)] -#[inline(never)] -pub fn kernel_1(x: &mut [f32; 256]) { - core::intrinsics::offload(_kernel_1, [256, 1, 1], [32, 1, 1], (x,)) -} - -#[unsafe(no_mangle)] -#[inline(never)] -pub fn _kernel_1(x: &mut [f32; 256]) { - for i in 0..256 { - x[i] = 21.0; - } -} From a767bf74624b000064b08993148a78f1e06090a4 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 1 Jan 2026 02:16:49 +0000 Subject: [PATCH 128/340] init impl --- clippy_lints/src/utils/author.rs | 1 + clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 90fa976fda38..f515f9987a80 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.body(field!(anon_const.body)); }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), + ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 78e3d6d192a0..a44cd31dc123 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 03853b5b4af5..f1ee534c500d 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*inits_b) .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) - }, + } + (ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => { + self.eq_qpath(path_a, path_b) + && args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) + | ConstArgKind::TupleCall(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(init.expr); } }, + ConstArgKind::TupleCall(path, args) => { + self.hash_qpath(path); + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } From 05afcb6d26567d481119c8f6f4a58ccce225f224 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 1 Jan 2026 02:16:49 +0000 Subject: [PATCH 129/340] init impl --- compiler/rustc_ast_lowering/src/lib.rs | 34 ++++- compiler/rustc_hir/src/hir.rs | 3 + compiler/rustc_hir/src/intravisit.rs | 7 + .../src/hir_ty_lowering/mod.rs | 135 +++++++++++++++++- compiler/rustc_hir_pretty/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 2 +- src/librustdoc/clean/mod.rs | 7 +- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 16 ++- tests/crashes/136379.rs | 11 -- tests/crashes/138132.rs | 10 -- .../mgca/tuple_ctor_arg_simple.rs | 52 +++++++ .../mgca/tuple_ctor_complex_args.rs | 19 +++ .../mgca/tuple_ctor_complex_args.stderr | 14 ++ .../mgca/tuple_ctor_erroneous.rs | 46 ++++++ .../mgca/tuple_ctor_erroneous.stderr | 68 +++++++++ .../mgca/tuple_ctor_in_array_len.rs | 16 +++ .../mgca/tuple_ctor_in_array_len.stderr | 23 +++ .../const-generics/mgca/tuple_ctor_nested.rs | 38 +++++ .../mgca/tuple_ctor_type_relative.rs | 26 ++++ .../mgca/type_as_const_in_array_len.rs | 14 ++ .../mgca/type_as_const_in_array_len.stderr | 19 +++ 24 files changed, 537 insertions(+), 28 deletions(-) delete mode 100644 tests/crashes/136379.rs delete mode 100644 tests/crashes/138132.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_nested.rs create mode 100644 tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs create mode 100644 tests/ui/const-generics/mgca/type_as_const_in_array_len.rs create mode 100644 tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 416fef8e3af3..9a459156aba1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2396,6 +2396,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; match &expr.kind { + ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => { + let qpath = self.lower_qpath( + func.id, + qself, + path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| { + let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind { + let def_id = self.local_def_id(anon_const.id); + let def_kind = self.tcx.def_kind(def_id); + assert_eq!(DefKind::AnonConst, def_kind); + self.lower_anon_const_to_const_arg_direct(anon_const) + } else { + self.lower_expr_to_const_arg_direct(arg) + }; + + &*self.arena.alloc(const_arg) + })); + + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), + } + } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( expr.id, @@ -2460,7 +2489,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && let StmtKind::Expr(expr) = &stmt.kind && matches!( expr.kind, - ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..) + ExprKind::Block(..) + | ExprKind::Path(..) + | ExprKind::Struct(..) + | ExprKind::Call(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index da3e79efd6df..252d32fa3365 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -499,6 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { match self.kind { ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), + ConstArgKind::TupleCall(path, _) => path.span(), ConstArgKind::Anon(anon) => anon.span, ConstArgKind::Error(span, _) => span, ConstArgKind::Infer(span, _) => span, @@ -519,6 +520,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Anon(&'hir AnonConst), /// Represents construction of struct/struct variants Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), + /// Tuple constructor variant + TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), /// Error const Error(Span, ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e636b3fff654..853e7db0757a 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1090,6 +1090,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( V::Result::output() } + ConstArgKind::TupleCall(qpath, args) => { + try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); + for arg in *args { + try_visit!(visitor.visit_const_arg_unambig(*arg)); + } + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 23110d2c5c87..680c44e80480 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -314,6 +314,7 @@ pub enum PermitVariants { enum TypeRelativePath<'tcx> { AssocItem(DefId, GenericArgsRef<'tcx>), Variant { adt: Ty<'tcx>, variant_did: DefId }, + Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> }, } /// New-typed boolean indicating whether explicit late-bound lifetimes @@ -1261,6 +1262,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { TypeRelativePath::Variant { adt, variant_did } => { Ok((adt, DefKind::Variant, variant_did)) } + TypeRelativePath::Ctor { .. } => { + let e = tcx.dcx().span_err(span, "expected type, found tuple constructor"); + Err(e) + } } } @@ -1294,6 +1299,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } (def_id, args) } + TypeRelativePath::Ctor { ctor_def_id, args } => { + return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))); + } // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { @@ -1326,6 +1334,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did())); if let Some(variant_def) = variant_def { + // FIXME(mgca): do we want constructor resolutions to take priority over + // other possible resolutions? + if matches!(mode, LowerTypeRelativePathMode::Const) + && let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor + { + tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); + let _ = self.prohibit_generic_args( + slice::from_ref(segment).iter(), + GenericsArgsErrExtend::EnumVariant { + qself: hir_self_ty, + assoc_segment: segment, + adt_def, + }, + ); + let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() }; + return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args }); + } if let PermitVariants::Yes = mode.permit_variants() { tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( @@ -2266,12 +2291,106 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::Struct(qpath, inits) => { self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span()) } + hir::ConstArgKind::TupleCall(qpath, args) => { + self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span()) + } hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), } } + fn lower_const_arg_tuple_call( + &self, + hir_id: HirId, + qpath: hir::QPath<'tcx>, + args: &'tcx [&'tcx hir::ConstArg<'tcx>], + span: Span, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let non_adt_or_variant_res = || { + let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path"); + ty::Const::new_error(tcx, e) + }; + + let ctor_const = match qpath { + hir::QPath::Resolved(maybe_qself, path) => { + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + self.lower_resolved_const_path(opt_self_ty, path, hir_id) + } + hir::QPath::TypeRelative(hir_self_ty, segment) => { + let self_ty = self.lower_ty(hir_self_ty); + match self.lower_type_relative_const_path( + self_ty, + hir_self_ty, + segment, + hir_id, + span, + ) { + Ok(c) => c, + Err(_) => return non_adt_or_variant_res(), + } + } + }; + + let Some(value) = ctor_const.try_to_value() else { + return non_adt_or_variant_res(); + }; + + let (adt_def, adt_args, variant_did) = match value.ty.kind() { + ty::FnDef(def_id, fn_args) + if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) => + { + let parent_did = tcx.parent(*def_id); + let enum_did = tcx.parent(parent_did); + (tcx.adt_def(enum_did), fn_args, parent_did) + } + ty::FnDef(def_id, fn_args) + if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) => + { + let parent_did = tcx.parent(*def_id); + (tcx.adt_def(parent_did), fn_args, parent_did) + } + _ => return non_adt_or_variant_res(), + }; + + let variant_def = adt_def.variant_with_id(variant_did); + let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32(); + + if args.len() != variant_def.fields.len() { + let e = tcx.dcx().span_err( + span, + format!( + "tuple constructor has {} arguments but {} were provided", + variant_def.fields.len(), + args.len() + ), + ); + return ty::Const::new_error(tcx, e); + } + + let fields = variant_def + .fields + .iter() + .zip(args) + .map(|(field_def, arg)| { + self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args)) + }) + .collect::>(); + + let opt_discr_const = if adt_def.is_enum() { + let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into()); + Some(ty::Const::new_value(tcx, valtree, tcx.types.u32)) + } else { + None + }; + + let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields)); + let adt_ty = Ty::new_adt(tcx, adt_def, adt_args); + ty::Const::new_value(tcx, valtree, adt_ty) + } + fn lower_const_arg_struct( &self, hir_id: HirId, @@ -2403,6 +2522,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = self.lower_generic_args_of_path_segment(span, did, segment); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } + Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => { + assert_eq!(opt_self_ty, None); + let [leading_segments @ .., segment] = path.segments else { bug!() }; + let _ = self + .prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None); + let parent_did = tcx.parent(did); + let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) { + tcx.parent(parent_did) + } else { + parent_did + }; + let args = self.lower_generic_args_of_path_segment(span, generics_did, segment); + ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) + } Res::Def(DefKind::AssocConst, did) => { let trait_segment = if let [modules @ .., trait_, _item] = path.segments { let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); @@ -2438,9 +2571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { DefKind::Mod | DefKind::Enum | DefKind::Variant - | DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) | DefKind::Struct - | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) | DefKind::OpaqueTy | DefKind::TyAlias | DefKind::TraitAlias diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c03135ee1bf..533afc372063 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1139,6 +1139,7 @@ impl<'a> State<'a> { match &const_arg.kind { // FIXME(mgca): proper printing for struct exprs ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), + ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 920c896d5a47..d79ab9eaf759 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b50fc201bdb8..f7b85453448c 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) => return visit::walk_expr(self, expr), + ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr), // FIXME(mgca): we may want to handle block labels in some manner ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { // FIXME(mgca): this probably means that mac calls that expand diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 707b48b355ba..d75a93606ea2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -323,6 +323,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind // FIXME(mgca): proper printing :3 ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() } } + hir::ConstArgKind::TupleCall(..) => { + ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1804,7 +1807,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) } - hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => { + hir::ConstArgKind::Struct(..) + | hir::ConstArgKind::Path(..) + | hir::ConstArgKind::TupleCall(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 90fa976fda38..f515f9987a80 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.body(field!(anon_const.body)); }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), + ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 78e3d6d192a0..a44cd31dc123 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 03853b5b4af5..f1ee534c500d 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -671,11 +671,19 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*inits_b) .all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr)) - }, + } + (ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => { + self.eq_qpath(path_a, path_b) + && args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) + | ConstArgKind::TupleCall(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1546,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(init.expr); } }, + ConstArgKind::TupleCall(path, args) => { + self.hash_qpath(path); + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/tests/crashes/136379.rs b/tests/crashes/136379.rs deleted file mode 100644 index 077b373e3b5d..000000000000 --- a/tests/crashes/136379.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #136379 -#![feature(min_generic_const_args)] -pub struct S(); - -impl S { - pub fn f() -> [u8; S] { - [] - } -} - -pub fn main() {} diff --git a/tests/crashes/138132.rs b/tests/crashes/138132.rs deleted file mode 100644 index 3e31117c526a..000000000000 --- a/tests/crashes/138132.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #138132 -#![feature(min_generic_const_args)] -struct b(Box<[u8; c]>); -impl b { - fn d(self) { - self.0.e() - } -} -struct c<'a>(&'a u8); -fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs b/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs new file mode 100644 index 000000000000..a5b3d3d0d5b6 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_arg_simple.rs @@ -0,0 +1,52 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum MyEnum { + Variant(T), + Other, +} + +trait Trait { + #[type_const] + const ASSOC: u32; +} + +fn with_point() -> Point { + P +} + +fn with_enum>() -> MyEnum { + E +} + +fn test() { + with_point::<{ Point(::ASSOC, N) }>(); +} + +fn test_basic() { + with_point::<{ Point(N, N) }>(); + with_point::<{ Point(const { 5 }, const { 10 }) }>(); + + with_enum::<{ MyEnum::Variant::(N) }>(); + with_enum::<{ MyEnum::Variant::(const { 42 }) }>(); + + with_enum::<{ >::Variant(N) }>(); +} + +fn main() { + test_basic::<5>(); + + let p = with_point::<{ Point(const { 1 }, const { 2 }) }>(); + assert_eq!(p, Point(1, 2)); + + let e = with_enum::<{ MyEnum::Variant::(const { 10 }) }>(); + assert_eq!(e, MyEnum::Variant(10)); +} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs new file mode 100644 index 000000000000..2e39f8952b11 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.rs @@ -0,0 +1,19 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +fn with_point() {} + +fn test() { + with_point::<{ Point(N + 1, N) }>(); + //~^ ERROR complex const arguments must be placed inside of a `const` block + + with_point::<{ Point(const { N + 1 }, N) }>(); + //~^ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr new file mode 100644 index 000000000000..e0ea3fd5560c --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_complex_args.stderr @@ -0,0 +1,14 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/tuple_ctor_complex_args.rs:12:26 + | +LL | with_point::<{ Point(N + 1, N) }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/tuple_ctor_complex_args.rs:15:34 + | +LL | with_point::<{ Point(const { N + 1 }, N) }>(); + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs new file mode 100644 index 000000000000..84ded05fdd0e --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs @@ -0,0 +1,46 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Point(u32, u32); + +#[derive(Eq, PartialEq, ConstParamTy)] +enum MyEnum { + Variant(T), + Unit, +} + +const CONST_ITEM: u32 = 42; + +fn accepts_point() {} +fn accepts_enum>() {} + +fn non_ctor() {} + +fn test_errors() { + accepts_point::<{ Point(N) }>(); + //~^ ERROR tuple constructor has 2 arguments but 1 were provided + + accepts_point::<{ Point(N, N, N) }>(); + //~^ ERROR tuple constructor has 2 arguments but 3 were provided + + accepts_point::<{ UnresolvedIdent(N, N) }>(); + //~^ ERROR cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope + //~| ERROR tuple constructor with invalid base path + + accepts_point::<{ non_ctor(N, N) }>(); + //~^ ERROR tuple constructor with invalid base path + + accepts_point::<{ CONST_ITEM(N, N) }>(); + //~^ ERROR tuple constructor with invalid base path + + accepts_point::<{ Point }>(); + //~^ ERROR the constant `Point` is not of type `Point` + + accepts_enum::<{ MyEnum::Variant:: }>(); + //~^ ERROR the constant `MyEnum::::Variant` is not of type `MyEnum` +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr new file mode 100644 index 000000000000..fbcdf35461ec --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr @@ -0,0 +1,68 @@ +error[E0425]: cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope + --> $DIR/tuple_ctor_erroneous.rs:29:23 + | +LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); + | ^^^^^^^^^^^^^^^ not found in this scope + | +help: you might be missing a const parameter + | +LL | fn test_errors() { + | +++++++++++++++++++++++++++++++++++ + +error: tuple constructor has 2 arguments but 1 were provided + --> $DIR/tuple_ctor_erroneous.rs:23:23 + | +LL | accepts_point::<{ Point(N) }>(); + | ^^^^^ + +error: tuple constructor has 2 arguments but 3 were provided + --> $DIR/tuple_ctor_erroneous.rs:26:23 + | +LL | accepts_point::<{ Point(N, N, N) }>(); + | ^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:29:23 + | +LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); + | ^^^^^^^^^^^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:33:23 + | +LL | accepts_point::<{ non_ctor(N, N) }>(); + | ^^^^^^^^ + +error: tuple constructor with invalid base path + --> $DIR/tuple_ctor_erroneous.rs:36:23 + | +LL | accepts_point::<{ CONST_ITEM(N, N) }>(); + | ^^^^^^^^^^ + +error: the constant `Point` is not of type `Point` + --> $DIR/tuple_ctor_erroneous.rs:39:23 + | +LL | accepts_point::<{ Point }>(); + | ^^^^^ expected `Point`, found struct constructor + | +note: required by a const generic parameter in `accepts_point` + --> $DIR/tuple_ctor_erroneous.rs:17:18 + | +LL | fn accepts_point() {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point` + +error: the constant `MyEnum::::Variant` is not of type `MyEnum` + --> $DIR/tuple_ctor_erroneous.rs:42:22 + | +LL | accepts_enum::<{ MyEnum::Variant:: }>(); + | ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum`, found enum constructor + | +note: required by a const generic parameter in `accepts_enum` + --> $DIR/tuple_ctor_erroneous.rs:18:17 + | +LL | fn accepts_enum>() {} + | ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs new file mode 100644 index 000000000000..5c7290b40be2 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.rs @@ -0,0 +1,16 @@ +//! Regression test for + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +pub struct S(); + +impl S { + pub fn f() -> [u8; S] { + //~^ ERROR the constant `S` is not of type `usize` + [] + //~^ ERROR mismatched types [E0308] + } +} + +pub fn main() {} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr new file mode 100644 index 000000000000..64c3cecd4fb5 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_in_array_len.stderr @@ -0,0 +1,23 @@ +error: the constant `S` is not of type `usize` + --> $DIR/tuple_ctor_in_array_len.rs:9:19 + | +LL | pub fn f() -> [u8; S] { + | ^^^^^^^ expected `usize`, found struct constructor + | + = note: the length of array `[u8; S]` must be type `usize` + +error[E0308]: mismatched types + --> $DIR/tuple_ctor_in_array_len.rs:11:9 + | +LL | pub fn f() -> [u8; S] { + | ------- expected `[u8; S]` because of return type +LL | +LL | [] + | ^^ expected an array with a size of S, found one with a size of 0 + | + = note: expected array `[u8; S]` + found array `[_; 0]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/tuple_ctor_nested.rs b/tests/ui/const-generics/mgca/tuple_ctor_nested.rs new file mode 100644 index 000000000000..49a31ea3e527 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_nested.rs @@ -0,0 +1,38 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Inner(u32); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +struct Outer(Inner); + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum Container { + Wrap(T), +} + +fn with_outer() -> Outer { + O +} + +fn with_container>() -> Container { + C +} + +fn test() { + with_outer::<{ Outer(Inner(N)) }>(); + with_outer::<{ Outer(Inner(const { 42 })) }>(); + + with_container::<{ Container::Wrap::(Inner(N)) }>(); +} + +fn main() { + test::<5>(); + + let o = with_outer::<{ Outer(Inner(const { 10 })) }>(); + assert_eq!(o, Outer(Inner(10))); +} diff --git a/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs b/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs new file mode 100644 index 000000000000..d5a07cbb7d70 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_ctor_type_relative.rs @@ -0,0 +1,26 @@ +//@ run-pass +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, Eq, PartialEq, ConstParamTy)] +enum Option { + Some(T), +} + +fn with_option>() -> Option { + O +} + +fn test() { + with_option::<{ >::Some(N) }>(); + with_option::<{ >::Some(const { 42 }) }>(); +} + +fn main() { + test::<5>(); + + let o = with_option::<{ >::Some(const { 10 }) }>(); + assert_eq!(o, Option::Some(10)); +} diff --git a/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs b/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs new file mode 100644 index 000000000000..b6b76fe3fc91 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_as_const_in_array_len.rs @@ -0,0 +1,14 @@ +//! Regression test for + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct B(Box<[u8; C]>); +//~^ ERROR missing generics for struct `C` +impl B { + fn d(self) { + self.0.e() + } +} +struct C<'a>(&'a u8); +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr b/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr new file mode 100644 index 000000000000..482fd730a71c --- /dev/null +++ b/tests/ui/const-generics/mgca/type_as_const_in_array_len.stderr @@ -0,0 +1,19 @@ +error[E0107]: missing generics for struct `C` + --> $DIR/type_as_const_in_array_len.rs:6:19 + | +LL | struct B(Box<[u8; C]>); + | ^ expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/type_as_const_in_array_len.rs:13:8 + | +LL | struct C<'a>(&'a u8); + | ^ -- +help: add missing lifetime argument + | +LL | struct B(Box<[u8; C<'a>]>); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. From 08e0400116f8fd5ccb84ac7c0839ae4afc465449 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 4 Jan 2026 12:50:21 +0000 Subject: [PATCH 130/340] add unit test for ExtraCheckArg::from_str --- src/tools/tidy/src/extra_checks/mod.rs | 50 ++++++++------ src/tools/tidy/src/extra_checks/tests.rs | 86 ++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 src/tools/tidy/src/extra_checks/tests.rs diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 2d654339e883..fd3dfbcf19b8 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -28,6 +28,9 @@ use crate::{CiInfo, ensure_version}; mod rustdoc_js; +#[cfg(test)] +mod tests; + const MIN_PY_REV: (u32, u32) = (3, 9); const MIN_PY_REV_STR: &str = "≥3.9"; @@ -735,7 +738,7 @@ impl From for Error { } } -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum ExtraCheckParseError { #[allow(dead_code, reason = "shown through Debug")] UnknownKind(String), @@ -752,6 +755,7 @@ enum ExtraCheckParseError { IfInstalledRequiresLang, } +#[derive(PartialEq, Debug)] struct ExtraCheckArg { /// Only run the check if files to check have been modified. auto: bool, @@ -854,30 +858,32 @@ impl FromStr for ExtraCheckArg { let mut auto = false; let mut if_installed = false; let mut parts = s.split(':'); - let Some(mut first) = parts.next() else { - return Err(ExtraCheckParseError::Empty); + let mut first = match parts.next() { + Some("") | None => return Err(ExtraCheckParseError::Empty), + Some(part) => part, }; + // The loop allows users to specify `auto` and `if-installed` in any order. // Both auto:if-installed: and if-installed:auto: are valid. loop { - if !auto && first == "auto" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::AutoRequiresLang); - }; - auto = true; - first = part; - continue; + match (first, auto, if_installed) { + ("auto", false, _) => { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::AutoRequiresLang); + }; + auto = true; + first = part; + } + ("if-installed", _, false) => { + let Some(part) = parts.next() else { + return Err(ExtraCheckParseError::IfInstalledRequiresLang); + }; + if_installed = true; + first = part; + continue; + } + _ => break, } - - if !if_installed && first == "if-installed" { - let Some(part) = parts.next() else { - return Err(ExtraCheckParseError::IfInstalledRequiresLang); - }; - if_installed = true; - first = part; - continue; - } - break; } let second = parts.next(); if parts.next().is_some() { @@ -897,7 +903,7 @@ impl FromStr for ExtraCheckArg { } } -#[derive(PartialEq, Copy, Clone)] +#[derive(PartialEq, Copy, Clone, Debug)] enum ExtraCheckLang { Py, Shell, @@ -921,7 +927,7 @@ impl FromStr for ExtraCheckLang { } } -#[derive(PartialEq, Copy, Clone)] +#[derive(PartialEq, Copy, Clone, Debug)] enum ExtraCheckKind { Lint, Fmt, diff --git a/src/tools/tidy/src/extra_checks/tests.rs b/src/tools/tidy/src/extra_checks/tests.rs new file mode 100644 index 000000000000..62501803b255 --- /dev/null +++ b/src/tools/tidy/src/extra_checks/tests.rs @@ -0,0 +1,86 @@ +use std::str::FromStr; + +use crate::extra_checks::{ExtraCheckArg, ExtraCheckKind, ExtraCheckLang, ExtraCheckParseError}; + +#[test] +fn test_extra_check_arg_from_str_ok() { + let test_cases = [ + ( + "auto:if-installed:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "if-installed:auto:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "auto:spellcheck", + Ok(ExtraCheckArg { + auto: true, + if_installed: false, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "if-installed:spellcheck", + Ok(ExtraCheckArg { + auto: false, + if_installed: true, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "spellcheck", + Ok(ExtraCheckArg { + auto: false, + if_installed: false, + lang: ExtraCheckLang::Spellcheck, + kind: None, + }), + ), + ( + "js:lint", + Ok(ExtraCheckArg { + auto: false, + if_installed: false, + lang: ExtraCheckLang::Js, + kind: Some(ExtraCheckKind::Lint), + }), + ), + ]; + + for (s, expected) in test_cases { + assert_eq!(ExtraCheckArg::from_str(s), expected); + } +} + +#[test] +fn test_extra_check_arg_from_str_err() { + let test_cases = [ + ("some:spellcheck", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), + ("spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), + ("spellcheck:lint", Err(ExtraCheckParseError::UnsupportedKindForLang)), + ("auto:spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), + ("auto:js:lint:some", Err(ExtraCheckParseError::TooManyParts)), + ("some", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), + ("auto", Err(ExtraCheckParseError::AutoRequiresLang)), + ("if-installed", Err(ExtraCheckParseError::IfInstalledRequiresLang)), + ("", Err(ExtraCheckParseError::Empty)), + ]; + + for (s, expected) in test_cases { + assert_eq!(ExtraCheckArg::from_str(s), expected); + } +} From 359f060175a99e73d576c08aa9f6140a13df0f4a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Sun, 4 Jan 2026 17:06:39 +0000 Subject: [PATCH 131/340] relate.rs: tiny cleanup: eliminate temp vars --- compiler/rustc_type_ir/src/relate.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 4954ebc51cfc..9e14bf6b60ad 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -155,11 +155,10 @@ impl Relate for ty::FnSig { let cx = relation.cx(); if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch({ - let a = a.c_variadic; - let b = b.c_variadic; - ExpectedFound::new(a, b) - })); + return Err(TypeError::VariadicMismatch(ExpectedFound::new( + a.c_variadic, + b.c_variadic, + ))); } if a.safety != b.safety { From dfe7d8a9b647d1e6b9bd51bc81bdbba067a69e13 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Sun, 4 Jan 2026 16:24:00 +0000 Subject: [PATCH 132/340] move ensure_version/ensure_version_or_cargo_install to extra_checks --- src/tools/tidy/src/extra_checks/mod.rs | 103 ++++++++++++++++++++++--- src/tools/tidy/src/lib.rs | 81 ------------------- 2 files changed, 93 insertions(+), 91 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index fd3dfbcf19b8..a1d9ad436885 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -21,10 +21,12 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; -use std::{fmt, fs, io}; +use std::{env, fmt, fs, io}; +use build_helper::ci::CiEnv; + +use crate::CiInfo; use crate::diagnostics::TidyCtx; -use crate::{CiInfo, ensure_version}; mod rustdoc_js; @@ -630,13 +632,8 @@ fn spellcheck_runner( cargo: &Path, args: &[&str], ) -> Result<(), Error> { - let bin_path = crate::ensure_version_or_cargo_install( - outdir, - cargo, - "typos-cli", - "typos", - SPELLCHECK_VER, - )?; + let bin_path = + ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", SPELLCHECK_VER)?; match Command::new(bin_path).current_dir(src_root).args(args).status() { Ok(status) => { if status.success() { @@ -690,6 +687,83 @@ fn find_with_extension( Ok(output) } +/// Check if the given executable is installed and the version is expected. +fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> Result { + let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); + + match Command::new(&bin_path).arg("--version").output() { + Ok(output) => { + let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() + else { + return Err(Error::Generic("version check failed".to_string())); + }; + + if v != version { + return Err(Error::Version { program: "", required: "", installed: v.to_string() }); + } + Ok(bin_path) + } + Err(e) => Err(Error::Io(e)), + } +} + +/// If the given executable is installed with the given version, use that, +/// otherwise install via cargo. +fn ensure_version_or_cargo_install( + build_dir: &Path, + cargo: &Path, + pkg_name: &str, + bin_name: &str, + version: &str, +) -> Result { + if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { + return Ok(bin_path); + } + + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); + + // use --force to ensure that if the required version is bumped, we update it. + // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. + // modify PATH so that cargo doesn't print a warning telling the user to modify the path. + let mut cmd = Command::new(cargo); + cmd.args(["install", "--locked", "--force", "--quiet"]) + .arg("--root") + .arg(&tool_root_dir) + .arg("--target-dir") + .arg(tool_root_dir.join("target")) + .arg(format!("{pkg_name}@{version}")) + .env( + "PATH", + env::join_paths( + env::split_paths(&env::var("PATH").unwrap()) + .chain(std::iter::once(tool_bin_dir.clone())), + ) + .expect("build dir contains invalid char"), + ); + + // On CI, we set opt-level flag for quicker installation. + // Since lower opt-level decreases the tool's performance, + // we don't set this option on local. + if CiEnv::is_ci() { + cmd.env("RUSTFLAGS", "-Copt-level=0"); + } + + let cargo_exit_code = cmd.spawn()?.wait()?; + if !cargo_exit_code.success() { + return Err(Error::Generic("cargo install failed".to_string())); + } + assert!( + matches!(bin_path.try_exists(), Ok(true)), + "cargo install did not produce the expected binary" + ); + eprintln!("finished building tool {bin_name}"); + Ok(bin_path) +} + #[derive(Debug)] enum Error { Io(io::Error), @@ -778,7 +852,16 @@ impl ExtraCheckArg { match self.lang { ExtraCheckLang::Spellcheck => { - ensure_version(build_dir, "typos", SPELLCHECK_VER).is_ok() + match ensure_version(build_dir, "typos", SPELLCHECK_VER) { + Ok(_) => true, + Err(Error::Version { installed, .. }) => { + eprintln!( + "warning: the tool `typos` is detected, but version {installed} doesn't match with the expected version {SPELLCHECK_VER}" + ); + false + } + _ => false, + } } ExtraCheckLang::Shell => has_shellcheck().is_ok(), ExtraCheckLang::Js => { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 62da0191da9e..425f43e42b7f 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -4,9 +4,7 @@ //! to be used by tools. use std::ffi::OsStr; -use std::path::{Path, PathBuf}; use std::process::Command; -use std::{env, io}; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -158,85 +156,6 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } -/// Check if the given executable is installed and the version is expected. -pub fn ensure_version(build_dir: &Path, bin_name: &str, version: &str) -> io::Result { - let bin_path = build_dir.join("misc-tools").join("bin").join(bin_name); - - match Command::new(&bin_path).arg("--version").output() { - Ok(output) => { - let Some(v) = str::from_utf8(&output.stdout).unwrap().trim().split_whitespace().last() - else { - return Err(io::Error::other("version check failed")); - }; - - if v != version { - eprintln!( - "warning: the tool `{bin_name}` is detected, but version {v} doesn't match with the expected version {version}" - ); - } - Ok(bin_path) - } - Err(e) => Err(e), - } -} - -/// If the given executable is installed with the given version, use that, -/// otherwise install via cargo. -pub fn ensure_version_or_cargo_install( - build_dir: &Path, - cargo: &Path, - pkg_name: &str, - bin_name: &str, - version: &str, -) -> io::Result { - if let Ok(bin_path) = ensure_version(build_dir, bin_name, version) { - return Ok(bin_path); - } - - eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); - - let tool_root_dir = build_dir.join("misc-tools"); - let tool_bin_dir = tool_root_dir.join("bin"); - let bin_path = tool_bin_dir.join(bin_name).with_extension(env::consts::EXE_EXTENSION); - - // use --force to ensure that if the required version is bumped, we update it. - // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. - // modify PATH so that cargo doesn't print a warning telling the user to modify the path. - let mut cmd = Command::new(cargo); - cmd.args(["install", "--locked", "--force", "--quiet"]) - .arg("--root") - .arg(&tool_root_dir) - .arg("--target-dir") - .arg(tool_root_dir.join("target")) - .arg(format!("{pkg_name}@{version}")) - .env( - "PATH", - env::join_paths( - env::split_paths(&env::var("PATH").unwrap()) - .chain(std::iter::once(tool_bin_dir.clone())), - ) - .expect("build dir contains invalid char"), - ); - - // On CI, we set opt-level flag for quicker installation. - // Since lower opt-level decreases the tool's performance, - // we don't set this option on local. - if CiEnv::is_ci() { - cmd.env("RUSTFLAGS", "-Copt-level=0"); - } - - let cargo_exit_code = cmd.spawn()?.wait()?; - if !cargo_exit_code.success() { - return Err(io::Error::other("cargo install failed")); - } - assert!( - matches!(bin_path.try_exists(), Ok(true)), - "cargo install did not produce the expected binary" - ); - eprintln!("finished building tool {bin_name}"); - Ok(bin_path) -} - pub mod alphabetical; pub mod bins; pub mod debug_artifacts; From 7dbe12ec729ed3ce6d7b228cbb213d8e73df30b4 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 5 Jan 2026 00:37:40 +0900 Subject: [PATCH 133/340] fix: Suppress false positive missing assoc item diag on specialization --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 42 +++++++++++++++++++ .../handlers/trait_impl_missing_assoc_item.rs | 18 ++++++++ 2 files changed, 60 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ef35694774e0..78be5a7e8fa9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -920,6 +920,48 @@ impl Module { } } + // HACK: When specialization is enabled in the current crate, and there exists + // *any* blanket impl that provides a default implementation for the missing item, + // suppress the missing associated item diagnostic. + // This can lead to false negatives when the impl in question does not actually + // specialize that blanket impl, but determining the exact specialization + // relationship here would be significantly more expensive. + if !missing.is_empty() { + let krate = self.krate(db).id; + let def_map = crate_def_map(db, krate); + if def_map.is_unstable_feature_enabled(&sym::specialization) + || def_map.is_unstable_feature_enabled(&sym::min_specialization) + { + missing.retain(|(assoc_name, assoc_item)| { + let AssocItem::Function(_) = assoc_item else { + return true; + }; + + for &impl_ in TraitImpls::for_crate(db, krate).blanket_impls(trait_.id) + { + if impl_ == impl_id { + continue; + } + + for (name, item) in &impl_.impl_items(db).items { + let AssocItemId::FunctionId(fn_) = item else { + continue; + }; + if name != assoc_name { + continue; + } + + if db.function_signature(*fn_).is_default() { + return false; + } + } + } + + true + }); + } + } + if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 0e18ce967404..2c0554470187 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -156,4 +156,22 @@ impl Trait for dyn OtherTrait {} "#, ) } + + #[test] + fn no_false_positive_on_specialization() { + check_diagnostics( + r#" +#![feature(specialization)] + +pub trait Foo { + fn foo(); +} + +impl Foo for T { + default fn foo() {} +} +impl Foo for bool {} +"#, + ); + } } From 814ee134f7ffb50369e46e94bf2829108cff0baf Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 4 Jan 2026 22:07:40 +0000 Subject: [PATCH 134/340] Bump `askama` to 0.15 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 67078adea2b4..7379dcbb7b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ walkdir = "2.3" filetime = "0.2.9" itertools = "0.12" pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] } -askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } +askama = { version = "0.15", default-features = false, features = ["alloc", "config", "derive"] } [dev-dependencies.toml] version = "0.9.7" From 9ba5b5e7f7b99bc9579d4893b5dd7582924ac68c Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Tue, 29 Jul 2025 11:10:17 +0200 Subject: [PATCH 135/340] add experimental `oneshot` channel The `oneshot` channel is gated under the `oneshot_channel` feature. Signed-off-by: Connor Tsui --- library/std/src/sync/mod.rs | 2 + library/std/src/sync/mpmc/mod.rs | 4 +- library/std/src/sync/mpsc.rs | 6 +- library/std/src/sync/oneshot.rs | 466 +++++++++++++++++++++++++++++++ 4 files changed, 474 insertions(+), 4 deletions(-) create mode 100644 library/std/src/sync/oneshot.rs diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 19b3040dcb27..5da50480c723 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -184,6 +184,8 @@ pub use alloc_crate::sync::{Arc, Weak}; #[unstable(feature = "mpmc_channel", issue = "126840")] pub mod mpmc; pub mod mpsc; +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub mod oneshot; pub(crate) mod once; // `pub(crate)` for the `sys::sync::once` implementations and `LazyLock`. diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index ee9795a52812..8df81a580f7b 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -654,7 +654,7 @@ impl Clone for Sender { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Sender { .. }") + f.debug_struct("Sender").finish_non_exhaustive() } } @@ -1380,7 +1380,7 @@ impl Clone for Receiver { #[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Receiver { .. }") + f.debug_struct("Receiver").finish_non_exhaustive() } } diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index f91c26aa22cf..0ae23f6e13bf 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -1114,8 +1114,10 @@ impl error::Error for SendError {} impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - TrySendError::Full(..) => "Full(..)".fmt(f), - TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + TrySendError::Full(..) => f.debug_tuple("TrySendError::Full").finish_non_exhaustive(), + TrySendError::Disconnected(..) => { + f.debug_tuple("TrySendError::Disconnected").finish_non_exhaustive() + } } } } diff --git a/library/std/src/sync/oneshot.rs b/library/std/src/sync/oneshot.rs new file mode 100644 index 000000000000..b2c9ba34c0ff --- /dev/null +++ b/library/std/src/sync/oneshot.rs @@ -0,0 +1,466 @@ +//! A single-producer, single-consumer (oneshot) channel. +//! +//! This is an experimental module, so the API will likely change. + +use crate::sync::mpmc; +use crate::sync::mpsc::{RecvError, SendError}; +use crate::time::{Duration, Instant}; +use crate::{error, fmt}; + +/// Creates a new oneshot channel, returning the sender/receiver halves. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// // Spawn off an expensive computation. +/// thread::spawn(move || { +/// # fn expensive_computation() -> i32 { 42 } +/// sender.send(expensive_computation()).unwrap(); +/// // `sender` is consumed by `send`, so we cannot use it anymore. +/// }); +/// +/// # fn do_other_work() -> i32 { 42 } +/// do_other_work(); +/// +/// // Let's see what that answer was... +/// println!("{:?}", receiver.recv().unwrap()); +/// // `receiver` is consumed by `recv`, so we cannot use it anymore. +/// ``` +#[must_use] +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub fn channel() -> (Sender, Receiver) { + // Using a `sync_channel` with capacity 1 means that the internal implementation will use the + // `Array`-flavored channel implementation. + let (sender, receiver) = mpmc::sync_channel(1); + (Sender { inner: sender }, Receiver { inner: receiver }) +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Sender +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The sending half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// sender.send("Hello from thread!").unwrap(); +/// }); +/// +/// assert_eq!(receiver.recv().unwrap(), "Hello from thread!"); +/// ``` +/// +/// `Sender` cannot be sent between threads if it is sending non-`Send` types. +/// +/// ```compile_fail +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::ptr; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// thread::spawn(move || { +/// sender.send(NotSend(ptr::null_mut())); +/// }); +/// +/// let reply = receiver.try_recv().unwrap(); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Sender { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Sender, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Sender`], it is perfectly safe to share a `&Sender` between threads (as it is effectively +// useless without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Sender {} + +impl Sender { + /// Attempts to send a value through this channel. This can only fail if the corresponding + /// [`Receiver`] has been dropped. + /// + /// This method is non-blocking (wait-free). + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// // Perform some computation. + /// let result = 2 + 2; + /// tx.send(result).unwrap(); + /// }); + /// + /// assert_eq!(rx.recv().unwrap(), 4); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn send(self, t: T) -> Result<(), SendError> { + self.inner.send(t) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Sender").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// The receiving half of a oneshot channel. +/// +/// # Examples +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(100)); +/// sender.send("Hello after delay!").unwrap(); +/// }); +/// +/// println!("Waiting for message..."); +/// println!("{}", receiver.recv().unwrap()); +/// ``` +/// +/// `Receiver` cannot be sent between threads if it is receiving non-`Send` types. +/// +/// ```compile_fail +/// # #![feature(oneshot_channel)] +/// # use std::sync::oneshot; +/// # use std::thread; +/// # use std::ptr; +/// # +/// let (sender, receiver) = oneshot::channel(); +/// +/// struct NotSend(*mut ()); +/// sender.send(NotSend(ptr::null_mut())); +/// +/// thread::spawn(move || { +/// let reply = receiver.try_recv().unwrap(); +/// }); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub struct Receiver { + /// The `oneshot` channel is simply a wrapper around a `mpmc` channel. + inner: mpmc::Receiver, +} + +// SAFETY: Since the only methods in which synchronization must occur take full ownership of the +// [`Receiver`], it is perfectly safe to share a `&Receiver` between threads (as it is unable to +// receive any values without ownership). +#[unstable(feature = "oneshot_channel", issue = "143674")] +unsafe impl Sync for Receiver {} + +impl Receiver { + /// Receives the value from the sending end, blocking the calling thread until it gets it. + /// + /// Can only fail if the corresponding [`Sender`] has been dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (tx, rx) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// tx.send("Done!").unwrap(); + /// }); + /// + /// // This will block until the message arrives. + /// println!("{}", rx.recv().unwrap()); + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv(self) -> Result { + self.inner.recv() + } + + // Fallible methods. + + /// Attempts to return a pending value on this receiver without blocking. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, mut receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send(42).unwrap(); + /// }); + /// + /// // Keep trying until we get the message, doing other work in the process. + /// loop { + /// match receiver.try_recv() { + /// Ok(value) => { + /// assert_eq!(value, 42); + /// break; + /// } + /// Err(oneshot::TryRecvError::Empty(rx)) => { + /// // Retake ownership of the receiver. + /// receiver = rx; + /// # fn do_other_work() { thread::sleep(Duration::from_millis(25)); } + /// do_other_work(); + /// } + /// Err(oneshot::TryRecvError::Disconnected) => panic!("Sender disconnected"), + /// } + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn try_recv(self) -> Result> { + self.inner.try_recv().map_err(|err| match err { + mpmc::TryRecvError::Empty => TryRecvError::Empty(self), + mpmc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if it waits more than `timeout`. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// sender.send("Success!").unwrap(); + /// }); + /// + /// // Wait up to 1 second for the message + /// match receiver.recv_timeout(Duration::from_secs(1)) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Timed out!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_timeout(self, timeout: Duration) -> Result> { + self.inner.recv_timeout(timeout).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + /// Attempts to wait for a value on this receiver, returning an error if the corresponding + /// [`Sender`] half of this channel has been dropped, or if `deadline` is reached. + /// + /// # Examples + /// + /// ``` + /// #![feature(oneshot_channel)] + /// use std::sync::oneshot; + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// + /// let (sender, receiver) = oneshot::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// sender.send("Just in time!").unwrap(); + /// }); + /// + /// let deadline = Instant::now() + Duration::from_millis(500); + /// match receiver.recv_deadline(deadline) { + /// Ok(msg) => println!("Received: {}", msg), + /// Err(oneshot::RecvTimeoutError::Timeout(_)) => println!("Missed deadline!"), + /// Err(oneshot::RecvTimeoutError::Disconnected) => println!("Sender dropped!"), + /// } + /// ``` + #[unstable(feature = "oneshot_channel", issue = "143674")] + pub fn recv_deadline(self, deadline: Instant) -> Result> { + self.inner.recv_deadline(deadline).map_err(|err| match err { + mpmc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout(self), + mpmc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Receiver").finish_non_exhaustive() + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Receiver Errors +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// An error returned from the [`try_recv`](Receiver::try_recv) method. +/// +/// See the documentation for [`try_recv`] for more information on how to use this error. +/// +/// [`try_recv`]: Receiver::try_recv +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum TryRecvError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that [`try_recv`](Receiver::try_recv) + /// took ownership over. + Empty(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +/// An error returned from the [`recv_timeout`](Receiver::recv_timeout) or +/// [`recv_deadline`](Receiver::recv_deadline) methods. +/// +/// # Examples +/// +/// Usage of this error is similar to [`TryRecvError`]. +/// +/// ``` +/// #![feature(oneshot_channel)] +/// use std::sync::oneshot::{self, RecvTimeoutError}; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = oneshot::channel(); +/// +/// let send_failure = thread::spawn(move || { +/// // Simulate a long computation that takes longer than our timeout. +/// thread::sleep(Duration::from_millis(250)); +/// +/// // This will likely fail to send because we drop the receiver in the main thread. +/// sender.send("Goodbye!".to_string()).unwrap(); +/// }); +/// +/// // Try to receive the message with a short timeout. +/// match receiver.recv_timeout(Duration::from_millis(10)) { +/// Ok(msg) => println!("Received: {}", msg), +/// Err(RecvTimeoutError::Timeout(rx)) => { +/// println!("Timed out waiting for message!"); +/// +/// // Note that you can reuse the receiver without dropping it. +/// drop(rx); +/// }, +/// Err(RecvTimeoutError::Disconnected) => println!("Sender dropped!"), +/// } +/// +/// send_failure.join().unwrap_err(); +/// ``` +#[unstable(feature = "oneshot_channel", issue = "143674")] +pub enum RecvTimeoutError { + /// The [`Sender`] has not sent a message yet, but it might in the future (as it has not yet + /// disconnected). This variant contains the [`Receiver`] that either + /// [`recv_timeout`](Receiver::recv_timeout) or [`recv_deadline`](Receiver::recv_deadline) took + /// ownership over. + Timeout(Receiver), + /// The corresponding [`Sender`] half of this channel has become disconnected, and there will + /// never be any more data sent over the channel. + Disconnected, +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("TryRecvError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + TryRecvError::Empty(..) => "receiving on an empty oneshot channel".fmt(f), + TryRecvError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for TryRecvError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// + /// This conversion always returns `TryRecvError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Debug for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("RecvTimeoutError").finish_non_exhaustive() + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout(..) => "timed out waiting on oneshot channel".fmt(f), + RecvTimeoutError::Disconnected => "receiving on a closed oneshot channel".fmt(f), + } + } +} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl error::Error for RecvTimeoutError {} + +#[unstable(feature = "oneshot_channel", issue = "143674")] +impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// + /// No data is allocated on the heap. + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} From b481ecd8b51eba60c7223cef2453a0a9d4c554c0 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Tue, 29 Jul 2025 11:11:18 +0200 Subject: [PATCH 136/340] add `oneshot` tests Tests inspired by tests in the `oneshot` third-party crate. --- library/std/tests/sync/lib.rs | 3 + library/std/tests/sync/oneshot.rs | 342 ++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 library/std/tests/sync/oneshot.rs diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 7ade9f623147..32a7efde2a25 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -1,5 +1,6 @@ #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] +#![feature(oneshot_channel)] #![feature(once_cell_try)] #![feature(lock_value_accessors)] #![feature(reentrant_lock)] @@ -26,6 +27,8 @@ mod mutex; mod once; mod once_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] +mod oneshot; +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod reentrant_lock; #[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] mod rwlock; diff --git a/library/std/tests/sync/oneshot.rs b/library/std/tests/sync/oneshot.rs new file mode 100644 index 000000000000..6a87c72b9cb5 --- /dev/null +++ b/library/std/tests/sync/oneshot.rs @@ -0,0 +1,342 @@ +//! Inspired by tests from + +use std::sync::mpsc::RecvError; +use std::sync::oneshot; +use std::sync::oneshot::{RecvTimeoutError, TryRecvError}; +use std::time::{Duration, Instant}; +use std::{mem, thread}; + +#[test] +fn send_before_try_recv() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(19i128).is_ok()); + + match receiver.try_recv() { + Ok(19) => {} + _ => panic!("expected Ok(19)"), + } +} + +#[test] +fn send_before_recv() { + let (sender, receiver) = oneshot::channel::<()>(); + + assert!(sender.send(()).is_ok()); + assert_eq!(receiver.recv(), Ok(())); + + let (sender, receiver) = oneshot::channel::(); + + assert!(sender.send(42).is_ok()); + assert_eq!(receiver.recv(), Ok(42)); + + let (sender, receiver) = oneshot::channel::<[u8; 4096]>(); + + assert!(sender.send([0b10101010; 4096]).is_ok()); + assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]); +} + +#[test] +fn sender_drop() { + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + } + } + + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.try_recv() { + Err(TryRecvError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } + { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } + } +} + +#[test] +fn send_never_deadline() { + let (sender, receiver) = oneshot::channel::(); + + mem::drop(sender); + + match receiver.recv_deadline(Instant::now()) { + Err(RecvTimeoutError::Disconnected) => {} + _ => panic!("expected disconnected error"), + } +} + +#[test] +fn send_before_recv_timeout() { + let (sender, receiver) = oneshot::channel(); + + assert!(sender.send(22i128).is_ok()); + + let start = Instant::now(); + + let timeout = Duration::from_secs(1); + match receiver.recv_timeout(timeout) { + Ok(22) => {} + _ => panic!("expected Ok(22)"), + } + + assert!(start.elapsed() < timeout); +} + +#[test] +fn send_error() { + let (sender, receiver) = oneshot::channel(); + + mem::drop(receiver); + + let send_error = sender.send(32u128).unwrap_err(); + assert_eq!(send_error.0, 32); +} + +#[test] +fn recv_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + sender.send(9u128).unwrap(); + }); + let t2 = thread::spawn(move || { + assert_eq!(receiver.recv(), Ok(9)); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn recv_timeout_before_send() { + let (sender, receiver) = oneshot::channel(); + + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + sender.send(99u128).unwrap(); + }); + + match receiver.recv_timeout(Duration::from_secs(1)) { + Ok(99) => {} + _ => panic!("expected Ok(99)"), + } + + t.join().unwrap(); +} + +#[test] +fn recv_then_drop_sender() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected recv error"), + }); + + let t2 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn drop_sender_then_recv() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(10)); + mem::drop(sender); + }); + + let t2 = thread::spawn(move || match receiver.recv() { + Err(RecvError) => {} + _ => panic!("expected disconnected error"), + }); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn try_recv_empty() { + let (sender, receiver) = oneshot::channel::(); + match receiver.try_recv() { + Err(TryRecvError::Empty(_)) => {} + _ => panic!("expected empty error"), + } + mem::drop(sender); +} + +#[test] +fn try_recv_then_drop_receiver() { + let (sender, receiver) = oneshot::channel::(); + + let t1 = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + let _ = sender.send(42); + }); + + let t2 = thread::spawn(move || match receiver.try_recv() { + Ok(_) => {} + Err(TryRecvError::Empty(r)) => { + mem::drop(r); + } + Err(TryRecvError::Disconnected) => {} + }); + + t2.join().unwrap(); + t1.join().unwrap(); +} + +#[test] +fn recv_no_time() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + match receiver.recv_deadline(start) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + let (_sender, receiver) = oneshot::channel::(); + match receiver.recv_timeout(Duration::from_millis(0)) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } +} + +#[test] +fn recv_deadline_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + + match receiver.recv_deadline(start + timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn recv_time_passed() { + let (_sender, receiver) = oneshot::channel::(); + + let start = Instant::now(); + let timeout = Duration::from_millis(100); + match receiver.recv_timeout(timeout) { + Err(RecvTimeoutError::Timeout(_)) => {} + _ => panic!("expected timeout error"), + } + assert!(start.elapsed() >= timeout); + assert!(start.elapsed() < timeout * 3); +} + +#[test] +fn non_send_type_can_be_used_on_same_thread() { + use std::ptr; + + #[derive(Debug, Eq, PartialEq)] + struct NotSend(*mut ()); + + let (sender, receiver) = oneshot::channel(); + sender.send(NotSend(ptr::null_mut())).unwrap(); + let reply = receiver.try_recv().unwrap(); + assert_eq!(reply, NotSend(ptr::null_mut())); +} + +/// Helper for testing drop behavior (taken directly from the `oneshot` crate). +struct DropCounter { + count: std::rc::Rc>, +} + +impl DropCounter { + fn new() -> (DropTracker, DropCounter) { + let count = std::rc::Rc::new(std::cell::RefCell::new(0)); + (DropTracker { count: count.clone() }, DropCounter { count }) + } + + fn count(&self) -> usize { + *self.count.borrow() + } +} + +struct DropTracker { + count: std::rc::Rc>, +} + +impl Drop for DropTracker { + fn drop(&mut self) { + *self.count.borrow_mut() += 1; + } +} + +#[test] +fn message_in_channel_dropped_on_receiver_drop() { + let (sender, receiver) = oneshot::channel(); + + let (message, counter) = DropCounter::new(); + assert_eq!(counter.count(), 0); + + sender.send(message).unwrap(); + assert_eq!(counter.count(), 0); + + mem::drop(receiver); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + mem::drop(send_error); + assert_eq!(counter.count(), 1); +} + +#[test] +fn send_error_drops_message_correctly_on_extract() { + let (sender, receiver) = oneshot::channel(); + mem::drop(receiver); + + let (message, counter) = DropCounter::new(); + + let send_error = sender.send(message).unwrap_err(); + assert_eq!(counter.count(), 0); + + let message = send_error.0; // Access the inner value directly + assert_eq!(counter.count(), 0); + + mem::drop(message); + assert_eq!(counter.count(), 1); +} From 3f1dd92cc7e5c97b54b58e70ad9d904ce08e372c Mon Sep 17 00:00:00 2001 From: "U. Lasiotus" Date: Sun, 4 Jan 2026 16:55:57 -0800 Subject: [PATCH 137/340] Motor OS: fix compile error PR https://github.com/rust-lang/rust/pull/146341 introduced a compilation error. This fixes it. --- library/std/src/sys/fs/motor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs index 8f3336e2fa96..2ae01db24be5 100644 --- a/library/std/src/sys/fs/motor.rs +++ b/library/std/src/sys/fs/motor.rs @@ -4,7 +4,7 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sys::fd::FileDesc; -pub use crate::sys::fs::common::exists; +pub use crate::sys::fs::common::{Dir, exists}; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, map_motor_error, unsupported}; From 5c5c1ff6dbe84e1d9eddd158116f6e40b941ed03 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Thu, 25 Dec 2025 23:29:35 +0900 Subject: [PATCH 138/340] moved some test delete tests/ui/issues/issue-22426.rs duplicated of tests/ui/match/guards.rs --- .../associated-type-const-nomalization.rs} | 0 .../ui/{issues/issue-2428.rs => cast/cast-enum-const.rs} | 0 .../ui/{issues/issue-22403.rs => cast/cast-to-box-arr.rs} | 0 .../issue-41998.rs => cast/cast-to-char-compare.rs} | 0 .../const-static-ref-to-closure.rs} | 0 .../derive-debug-generic-with-lifetime.rs} | 0 .../derive-debug-newtype-unsized-slice.rs} | 0 .../call-unit-struct-impl-fn-once.rs} | 0 .../fn-trait-explicit-call.rs} | 0 tests/ui/issues/issue-22426.rs | 8 -------- tests/ui/{issues => resolve}/auxiliary/i8.rs | 0 .../const-iter-no-conflict-for-loop.rs} | 0 .../issue-20427.rs => resolve/shadow-primitives.rs} | 0 .../self-in-method-body-resolves.rs} | 0 .../bound/recursive-trait-bound-on-type-param.rs} | 0 .../tuple-ref-order-distinct-impls.rs} | 0 .../issue-20676.rs => ufcs/ufcs-trait-object-format.rs} | 0 17 files changed, 8 deletions(-) rename tests/ui/{issues/issue-26614.rs => associated-types/associated-type-const-nomalization.rs} (100%) rename tests/ui/{issues/issue-2428.rs => cast/cast-enum-const.rs} (100%) rename tests/ui/{issues/issue-22403.rs => cast/cast-to-box-arr.rs} (100%) rename tests/ui/{issues/issue-41998.rs => cast/cast-to-char-compare.rs} (100%) rename tests/ui/{issues/issue-25180.rs => consts/const-static-ref-to-closure.rs} (100%) rename tests/ui/{issues/issue-29030.rs => derives/derive-debug-generic-with-lifetime.rs} (100%) rename tests/ui/{issues/issue-25394.rs => derives/derive-debug-newtype-unsized-slice.rs} (100%) rename tests/ui/{issues/issue-33687.rs => fn_traits/call-unit-struct-impl-fn-once.rs} (100%) rename tests/ui/{issues/issue-20847.rs => fn_traits/fn-trait-explicit-call.rs} (100%) delete mode 100644 tests/ui/issues/issue-22426.rs rename tests/ui/{issues => resolve}/auxiliary/i8.rs (100%) rename tests/ui/{issues/issue-27639.rs => resolve/const-iter-no-conflict-for-loop.rs} (100%) rename tests/ui/{issues/issue-20427.rs => resolve/shadow-primitives.rs} (100%) rename tests/ui/{issues/issue-24389.rs => self/self-in-method-body-resolves.rs} (100%) rename tests/ui/{issues/issue-19601.rs => traits/bound/recursive-trait-bound-on-type-param.rs} (100%) rename tests/ui/{issues/issue-11384.rs => typeck/tuple-ref-order-distinct-impls.rs} (100%) rename tests/ui/{issues/issue-20676.rs => ufcs/ufcs-trait-object-format.rs} (100%) diff --git a/tests/ui/issues/issue-26614.rs b/tests/ui/associated-types/associated-type-const-nomalization.rs similarity index 100% rename from tests/ui/issues/issue-26614.rs rename to tests/ui/associated-types/associated-type-const-nomalization.rs diff --git a/tests/ui/issues/issue-2428.rs b/tests/ui/cast/cast-enum-const.rs similarity index 100% rename from tests/ui/issues/issue-2428.rs rename to tests/ui/cast/cast-enum-const.rs diff --git a/tests/ui/issues/issue-22403.rs b/tests/ui/cast/cast-to-box-arr.rs similarity index 100% rename from tests/ui/issues/issue-22403.rs rename to tests/ui/cast/cast-to-box-arr.rs diff --git a/tests/ui/issues/issue-41998.rs b/tests/ui/cast/cast-to-char-compare.rs similarity index 100% rename from tests/ui/issues/issue-41998.rs rename to tests/ui/cast/cast-to-char-compare.rs diff --git a/tests/ui/issues/issue-25180.rs b/tests/ui/consts/const-static-ref-to-closure.rs similarity index 100% rename from tests/ui/issues/issue-25180.rs rename to tests/ui/consts/const-static-ref-to-closure.rs diff --git a/tests/ui/issues/issue-29030.rs b/tests/ui/derives/derive-debug-generic-with-lifetime.rs similarity index 100% rename from tests/ui/issues/issue-29030.rs rename to tests/ui/derives/derive-debug-generic-with-lifetime.rs diff --git a/tests/ui/issues/issue-25394.rs b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs similarity index 100% rename from tests/ui/issues/issue-25394.rs rename to tests/ui/derives/derive-debug-newtype-unsized-slice.rs diff --git a/tests/ui/issues/issue-33687.rs b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs similarity index 100% rename from tests/ui/issues/issue-33687.rs rename to tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs diff --git a/tests/ui/issues/issue-20847.rs b/tests/ui/fn_traits/fn-trait-explicit-call.rs similarity index 100% rename from tests/ui/issues/issue-20847.rs rename to tests/ui/fn_traits/fn-trait-explicit-call.rs diff --git a/tests/ui/issues/issue-22426.rs b/tests/ui/issues/issue-22426.rs deleted file mode 100644 index 0857ac9dfb4d..000000000000 --- a/tests/ui/issues/issue-22426.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass - -fn main() { - match 42 { - x if x < 7 => (), - _ => () - } -} diff --git a/tests/ui/issues/auxiliary/i8.rs b/tests/ui/resolve/auxiliary/i8.rs similarity index 100% rename from tests/ui/issues/auxiliary/i8.rs rename to tests/ui/resolve/auxiliary/i8.rs diff --git a/tests/ui/issues/issue-27639.rs b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs similarity index 100% rename from tests/ui/issues/issue-27639.rs rename to tests/ui/resolve/const-iter-no-conflict-for-loop.rs diff --git a/tests/ui/issues/issue-20427.rs b/tests/ui/resolve/shadow-primitives.rs similarity index 100% rename from tests/ui/issues/issue-20427.rs rename to tests/ui/resolve/shadow-primitives.rs diff --git a/tests/ui/issues/issue-24389.rs b/tests/ui/self/self-in-method-body-resolves.rs similarity index 100% rename from tests/ui/issues/issue-24389.rs rename to tests/ui/self/self-in-method-body-resolves.rs diff --git a/tests/ui/issues/issue-19601.rs b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs similarity index 100% rename from tests/ui/issues/issue-19601.rs rename to tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs diff --git a/tests/ui/issues/issue-11384.rs b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs similarity index 100% rename from tests/ui/issues/issue-11384.rs rename to tests/ui/typeck/tuple-ref-order-distinct-impls.rs diff --git a/tests/ui/issues/issue-20676.rs b/tests/ui/ufcs/ufcs-trait-object-format.rs similarity index 100% rename from tests/ui/issues/issue-20676.rs rename to tests/ui/ufcs/ufcs-trait-object-format.rs From af5bebeae3d66b2b92bee4187108f64d931537f8 Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Sat, 3 Jan 2026 16:24:56 +0800 Subject: [PATCH 139/340] Merge `associated_const_equality` feature gate into MGCA This removes `associated_const_equality` as a separate feature gate and makes it part of `min_generic_const_args` (mgca). Key changes: - Remove `associated_const_equality` from unstable features, add to removed - Update all test files to use `min_generic_const_args` instead - Preserve the original "associated const equality is incomplete" error message by specially handling `sym::associated_const_equality` spans in `feature_gate.rs` - Rename FIXME(associated_const_equality) to FIXME(mgca) --- tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed | 2 +- tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed index f2bd306a99e4..f8be3331317c 100644 --- a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed +++ b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs index 8e7d843a44c0..a0d7a653993f 100644 --- a/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs +++ b/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] From 442127051669be574107571773c669006413dedf Mon Sep 17 00:00:00 2001 From: AprilNEA Date: Sat, 3 Jan 2026 16:24:56 +0800 Subject: [PATCH 140/340] Merge `associated_const_equality` feature gate into MGCA This removes `associated_const_equality` as a separate feature gate and makes it part of `min_generic_const_args` (mgca). Key changes: - Remove `associated_const_equality` from unstable features, add to removed - Update all test files to use `min_generic_const_args` instead - Preserve the original "associated const equality is incomplete" error message by specially handling `sym::associated_const_equality` spans in `feature_gate.rs` - Rename FIXME(associated_const_equality) to FIXME(mgca) --- compiler/rustc_ast_passes/src/feature_gate.rs | 18 +++++- .../src/debuginfo/type_names.rs | 2 +- compiler/rustc_feature/src/removed.rs | 3 + compiler/rustc_feature/src/unstable.rs | 2 - .../src/hir_ty_lowering/bounds.rs | 4 +- .../src/hir_ty_lowering/dyn_trait.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 4 -- .../src/solve/assembly/structural_traits.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 2 - ...duplication_in_bounds_assoc_const_eq.fixed | 2 +- ...it_duplication_in_bounds_assoc_const_eq.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- tests/crashes/mgca/ace-with-const-ctor.rs | 2 +- .../associated-constant-not-allowed-102467.rs | 2 +- .../auxiliary/assoc-const-equality.rs | 2 +- .../assoc-const-eq-ambiguity.rs | 2 +- .../assoc-const-eq-bound-var-in-ty-not-wf.rs | 1 - ...soc-const-eq-bound-var-in-ty-not-wf.stderr | 4 +- .../assoc-const-eq-bound-var-in-ty.rs | 1 - ...oc-const-eq-const_evaluatable_unchecked.rs | 2 +- .../assoc-const-eq-esc-bound-var-in-ty.rs | 1 - .../assoc-const-eq-esc-bound-var-in-ty.stderr | 2 +- .../assoc-const-eq-missing.rs | 4 +- .../assoc-const-eq-param-in-ty.rs | 1 - .../assoc-const-eq-param-in-ty.stderr | 22 +++---- .../assoc-const-eq-supertraits.rs | 1 - .../assoc-const-eq-ty-alias-noninteracting.rs | 2 +- .../assoc-const-ty-mismatch.rs | 4 +- tests/ui/associated-consts/assoc-const.rs | 2 +- .../equality-unused-issue-126729.rs | 2 +- .../associated-consts/issue-102335-const.rs | 2 +- .../ui/associated-consts/issue-105330.stderr | 8 +-- tests/ui/associated-consts/issue-110933.rs | 2 +- tests/ui/associated-consts/issue-93835.rs | 4 +- tests/ui/associated-consts/issue-93835.stderr | 8 +-- .../projection-unspecified-but-bounded.rs | 2 +- .../const-projection-err.rs | 2 +- .../duplicate-bound-err.rs | 1 - .../duplicate-bound-err.stderr | 64 +++++++++---------- .../associated-type-bounds/duplicate-bound.rs | 2 +- .../associated-type-bounds/issue-99828.stderr | 4 +- .../associated-types-eq-2.stderr | 16 ++--- .../assoc_const_eq_diagnostic.rs | 3 +- .../assoc_const_eq_diagnostic.stderr | 16 ++--- .../associated_const_equality/coherence.rs | 2 +- .../equality_bound_with_infer.rs | 2 +- ...with-generic-in-ace-no-feature-gate.stderr | 20 +++--- .../mismatched-types-with-generic-in-ace.rs | 2 +- .../unconstrained_impl_param.stderr | 4 +- .../mgca/explicit_anon_consts.rs | 2 +- .../explicit_anon_consts_literals_hack.rs | 2 +- .../mgca/type_const-only-in-impl.rs | 2 +- .../mgca/type_const-only-in-trait.rs | 2 +- .../mgca/using-fnptr-as-type_const.rs | 2 +- .../issue-89013-no-kw.stderr | 4 +- .../parser-error-recovery/issue-89013.stderr | 4 +- .../feature-gate-associated_const_equality.rs | 2 +- ...ture-gate-associated_const_equality.stderr | 4 +- .../assoc-const-no-infer-ice-115806.rs | 2 +- .../associated-const-equality.rs | 2 +- .../no-name-for-DefPath-issue-133426.stderr | 4 +- .../recover-assoc-const-constraint.stderr | 8 +-- .../overlap-due-to-unsatisfied-const-bound.rs | 2 +- ...rlap-due-to-unsatisfied-const-bound.stderr | 12 ++-- .../dont-ice-on-assoc-projection.stderr | 4 +- 66 files changed, 166 insertions(+), 162 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index dbbd3906b525..f2fdd1b0eb8b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -505,7 +505,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { half_open_range_patterns_in_slices, "half-open range patterns in slices are unstable" ); - gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); @@ -518,6 +517,23 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { 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"); + // associated_const_equality is stabilized as part of min_generic_const_args + if let Some(spans) = spans.get(&sym::associated_const_equality) { + for span in spans { + if !visitor.features.min_generic_const_args() + && !span.allows_unstable(sym::min_generic_const_args) + { + #[allow(rustc::untranslatable_diagnostic)] + feature_err( + &visitor.sess, + sym::min_generic_const_args, + *span, + "associated const equality is incomplete", + ) + .emit(); + } + } + } 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_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 18279a4d05fe..02476a332252 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -260,7 +260,7 @@ fn push_debuginfo_type_name<'tcx>( .map(|bound| { let ExistentialProjection { def_id: item_def_id, term, .. } = tcx.instantiate_bound_regions_with_erased(bound); - // FIXME(associated_const_equality): allow for consts here + // FIXME(mgca): allow for consts here (item_def_id, term.expect_type()) }) .collect(); diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 9d8a84c52e98..6aaf4542260c 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -60,6 +60,9 @@ declare_features! ( (removed, allocator, "1.0.0", None, None), /// Allows a test to fail without failing the whole suite. (removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416), + /// Allows users to enforce equality of associated constants `TraitImpl`. + (removed, associated_const_equality, "CURRENT_RUSTC_VERSION", Some(92827), + Some("merged into `min_generic_const_args`")), (removed, await_macro, "1.38.0", Some(50547), Some("subsumed by `.await` syntax"), 62293), /// Allows using the `box $expr` syntax. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index f64702fc44b0..387a01967ae5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -363,8 +363,6 @@ declare_features! ( (unstable, asm_goto_with_outputs, "1.85.0", Some(119364)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), - /// Allows users to enforce equality of associated constants `TraitImpl`. - (unstable, associated_const_equality, "1.58.0", Some(92827)), /// Allows associated type defaults. (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows implementing `AsyncDrop`. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 555ef5c45e12..9ae6a9fac504 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -610,9 +610,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { AttributeKind::TypeConst(_) ) { - if tcx.features().min_generic_const_args() - || tcx.features().associated_const_equality() - { + if tcx.features().min_generic_const_args() { let mut err = self.dcx().struct_span_err( constraint.span, "use of trait associated const without `#[type_const]`", diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 15d7da3a0070..edb79592e6c5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -239,7 +239,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.kind() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - // FIXME(associated_const_equality): We should walk the const instead of not doing anything + // FIXME(mgca): We should walk the const instead of not doing anything ty::TermKind::Const(_) => false, }; 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 5fc201db68e5..51c664921804 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -359,12 +359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { None }; - // FIXME(associated_const_equality): This has quite a few false positives and negatives. + // FIXME(mgca): This has quite a few false positives and negatives. let wrap_in_braces_sugg = if let Some(constraint) = constraint && let Some(hir_ty) = constraint.ty() && let ty = self.lower_ty(hir_ty) && (ty.is_enum() || ty.references_error()) - && tcx.features().associated_const_equality() + && tcx.features().min_generic_const_args() { Some(errors::AssocKindMismatchWrapInBracesSugg { lo: hir_ty.span.shrink_to_lo(), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 25cc739f5ff9..a2f4714d1b2c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -907,10 +907,6 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu self.coroutine_clone() } - fn associated_const_equality(self) -> bool { - self.associated_const_equality() - } - fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool { // We don't consider feature bounds to hold in the crate when `staged_api` feature is // enabled, even if it is enabled through `#[feature]`. diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 2f6ff12e1e8d..05ea217c1de0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -868,7 +868,7 @@ where .map(|(pred, _)| pred), )); - // FIXME(associated_const_equality): Also add associated consts to + // FIXME(mgca): Also add associated consts to // the requirements here. for associated_type_def_id in cx.associated_type_def_ids(trait_ref.def_id) { // associated types that require `Self: Sized` do not show up in the built-in diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 16f837141e97..4323b1ca6469 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -646,8 +646,6 @@ pub trait Features: Copy { fn coroutine_clone(self) -> bool; - fn associated_const_equality(self) -> bool; - fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed index f2bd306a99e4..f8be3331317c 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.fixed @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs index 8e7d843a44c0..a0d7a653993f 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_assoc_const_eq.rs @@ -1,6 +1,6 @@ #![deny(clippy::trait_duplication_in_bounds)] #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait AssocConstTrait { #[type_const] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 9307868f3982..6c224f875d3a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -862,7 +862,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { TermKind::Ty(ty) => { ty.walk().any(|arg| arg == dummy_self_ty.into()) } - // FIXME(associated_const_equality): We should walk the const instead of not doing anything + // FIXME(mgca): We should walk the const instead of not doing anything TermKind::Const(_) => false, }; diff --git a/tests/crashes/mgca/ace-with-const-ctor.rs b/tests/crashes/mgca/ace-with-const-ctor.rs index 9e49bca06d52..28e85f37de1f 100644 --- a/tests/crashes/mgca/ace-with-const-ctor.rs +++ b/tests/crashes/mgca/ace-with-const-ctor.rs @@ -3,7 +3,7 @@ // readded once fixed. // Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952 #![crate_name = "foo"] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] pub enum ParseMode { Raw, } diff --git a/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs b/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs index c4bbcfc2b077..5b8a90d64121 100644 --- a/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs +++ b/tests/rustdoc-ui/associated-constant-not-allowed-102467.rs @@ -2,7 +2,7 @@ // It ensures that the expected error is displayed. #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait T { type A: S = 34>; diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs index f6c03d189b5e..598d2b5bf29d 100644 --- a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs +++ b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] pub fn accept(_: impl Trait) {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index 27261a4806eb..6bc2a6d5d153 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -1,7 +1,7 @@ // We used to say "ambiguous associated type" on ambiguous associated consts. // Ensure that we now use the correct label. -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait0: Parent0 + Parent0 {} 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 50914fb192ff..803cc59cc93d 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 @@ -1,7 +1,6 @@ // Check that we eventually catch types of assoc const bounds // (containing late-bound vars) that are ill-formed. #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, 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 fd49e151b8e6..76868715b861 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,11 +1,11 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:22:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 | LL | K = const { () } | ^^^^^^^^^^^^ 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 54e199d702c9..e6fd5bdad002 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 @@ -4,7 +4,6 @@ //@ check-pass #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs index 22a03e47b2f7..161eef63d36f 100644 --- a/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs +++ b/tests/ui/associated-consts/assoc-const-eq-const_evaluatable_unchecked.rs @@ -4,7 +4,7 @@ // // issue: //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] pub trait TraitA { 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 7f9a04bbf0fc..d32737fcb62f 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 @@ -1,7 +1,6 @@ // Detect and reject escaping late-bound generic params in // the type of assoc consts used in an equality bound. #![feature( - associated_const_equality, min_generic_const_args, unsized_const_params, generic_const_parameter_types, 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 e22d9bfed7ef..ef861cb7f49a 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,5 +1,5 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters - --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:16:35 + --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:15:35 | LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-missing.rs b/tests/ui/associated-consts/assoc-const-eq-missing.rs index f384927e4a34..22b565cb27d2 100644 --- a/tests/ui/associated-consts/assoc-const-eq-missing.rs +++ b/tests/ui/associated-consts/assoc-const-eq-missing.rs @@ -1,5 +1,5 @@ -#![feature(associated_const_equality)] -#![allow(unused)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features, unused)] pub trait Foo { const N: usize; 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 ea2f60cd6187..44e7e3f19ef2 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 @@ -1,7 +1,6 @@ // Regression test for issue #108271. // Detect and reject generic params in the type of assoc consts used in an equality bound. #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, 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 ae6a35b4b9f2..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,5 +1,5 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | -- the lifetime parameter `'r` is defined here @@ -10,7 +10,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the type parameter `A` is defined here @@ -21,7 +21,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:23:29 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( | - the const parameter `Q` is defined here @@ -32,7 +32,7 @@ LL | _: impl Trait<'r, A, Q, K = const { loop {} }> = 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:40:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 | LL | fn take1(_: impl Project) {} | -------------^^^^------------ @@ -41,7 +41,7 @@ LL | fn take1(_: impl Project) {} | 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:45:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 | LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` @@ -51,7 +51,7 @@ 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -62,7 +62,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -70,7 +70,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` @@ -80,7 +80,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here @@ -92,7 +92,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` @@ -101,7 +101,7 @@ LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> = 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:54:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` diff --git a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs index c092285dfcd4..a5f8859c92bd 100644 --- a/tests/ui/associated-consts/assoc-const-eq-supertraits.rs +++ b/tests/ui/associated-consts/assoc-const-eq-supertraits.rs @@ -4,7 +4,6 @@ //@ check-pass #![feature( - associated_const_equality, min_generic_const_args, adt_const_params, unsized_const_params, diff --git a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs index 41857eca87de..004215986711 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ty-alias-noninteracting.rs @@ -5,7 +5,7 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] trait Trait: SuperTrait { diff --git a/tests/ui/associated-consts/assoc-const-ty-mismatch.rs b/tests/ui/associated-consts/assoc-const-ty-mismatch.rs index 7211637659bd..1092733a8e2e 100644 --- a/tests/ui/associated-consts/assoc-const-ty-mismatch.rs +++ b/tests/ui/associated-consts/assoc-const-ty-mismatch.rs @@ -1,5 +1,5 @@ -#![feature(associated_const_equality)] -#![allow(unused)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features, unused)] pub trait Foo { const N: usize; diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 6295fd50b8ff..ac9f7e53b3cb 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(unused, incomplete_features)] pub trait Foo { diff --git a/tests/ui/associated-consts/equality-unused-issue-126729.rs b/tests/ui/associated-consts/equality-unused-issue-126729.rs index 35b49314b5f5..614ed8c803d4 100644 --- a/tests/ui/associated-consts/equality-unused-issue-126729.rs +++ b/tests/ui/associated-consts/equality-unused-issue-126729.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] #![deny(dead_code)] diff --git a/tests/ui/associated-consts/issue-102335-const.rs b/tests/ui/associated-consts/issue-102335-const.rs index f9b816fd3bc9..a88a3abf0a12 100644 --- a/tests/ui/associated-consts/issue-102335-const.rs +++ b/tests/ui/associated-consts/issue-102335-const.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] trait T { diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index 5d6dc48e36c0..06900404ec34 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -21,8 +21,8 @@ error[E0658]: associated const equality is incomplete LL | fn foo>() { | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -31,8 +31,8 @@ error[E0658]: associated const equality is incomplete LL | fn main>() { | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0562]: `impl Trait` is not allowed in impl headers diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index 731ff1564ce2..9a013ee71274 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] pub trait Trait { diff --git a/tests/ui/associated-consts/issue-93835.rs b/tests/ui/associated-consts/issue-93835.rs index d6c2acaa9edc..26d0bbe3a40f 100644 --- a/tests/ui/associated-consts/issue-93835.rs +++ b/tests/ui/associated-consts/issue-93835.rs @@ -4,9 +4,9 @@ fn e() { type_ascribe!(p, a>); //~^ ERROR cannot find type `a` in this scope //~| ERROR cannot find value - //~| ERROR associated const equality + //~| ERROR associated const equality is incomplete //~| ERROR cannot find trait `p` in this scope - //~| ERROR associated const equality + //~| ERROR associated const equality is incomplete } fn main() {} diff --git a/tests/ui/associated-consts/issue-93835.stderr b/tests/ui/associated-consts/issue-93835.stderr index 3f1679890130..990d22bba4de 100644 --- a/tests/ui/associated-consts/issue-93835.stderr +++ b/tests/ui/associated-consts/issue-93835.stderr @@ -22,8 +22,8 @@ error[E0658]: associated const equality is incomplete LL | type_ascribe!(p, a>); | ^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -32,8 +32,8 @@ error[E0658]: associated const equality is incomplete LL | type_ascribe!(p, a>); | ^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs index 7f3304f07656..8a78b26dbc5d 100644 --- a/tests/ui/associated-consts/projection-unspecified-but-bounded.rs +++ b/tests/ui/associated-consts/projection-unspecified-but-bounded.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] // Issue 110549 diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index b230ea77f5fe..d485316ce371 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![allow(incomplete_features)] trait TraitWAssocConst { diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 7e86148eb811..1587be7200e7 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -1,7 +1,6 @@ //@ edition: 2024 #![feature( - associated_const_equality, min_generic_const_args, type_alias_impl_trait, return_type_notation diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index 6484880392d6..ec864c1dd96e 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:15:5 + --> $DIR/duplicate-bound-err.rs:14:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -10,7 +10,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:19:5 + --> $DIR/duplicate-bound-err.rs:18:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -21,7 +21,7 @@ LL | iter::empty::() | +++++ error[E0282]: type annotations needed - --> $DIR/duplicate-bound-err.rs:23:5 + --> $DIR/duplicate-bound-err.rs:22:5 | LL | iter::empty() | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty` @@ -32,7 +32,7 @@ LL | iter::empty::() | +++++ error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:27:51 + --> $DIR/duplicate-bound-err.rs:26:51 | LL | type Tait1> = impl Copy; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | type Tait1> = impl Copy; = note: `Tait1` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:29:51 + --> $DIR/duplicate-bound-err.rs:28:51 | LL | type Tait2> = impl Copy; | ^^^^^^^^^ @@ -48,7 +48,7 @@ LL | type Tait2> = impl Copy; = note: `Tait2` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:31:57 + --> $DIR/duplicate-bound-err.rs:30:57 | LL | type Tait3> = impl Copy; | ^^^^^^^^^ @@ -56,7 +56,7 @@ LL | type Tait3> = impl Copy; = note: `Tait3` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:34:14 + --> $DIR/duplicate-bound-err.rs:33:14 | LL | type Tait4 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | type Tait4 = impl Iterator; = note: `Tait4` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:36:14 + --> $DIR/duplicate-bound-err.rs:35:14 | LL | type Tait5 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | type Tait5 = impl Iterator; = note: `Tait5` must be used in combination with a concrete type within the same crate error: unconstrained opaque type - --> $DIR/duplicate-bound-err.rs:38:14 + --> $DIR/duplicate-bound-err.rs:37:14 | LL | type Tait6 = impl Iterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | type Tait6 = impl Iterator; = note: `Tait6` must be used in combination with a concrete type within the same crate error[E0277]: `*const ()` cannot be sent between threads safely - --> $DIR/duplicate-bound-err.rs:41:18 + --> $DIR/duplicate-bound-err.rs:40:18 | LL | fn mismatch() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely @@ -91,7 +91,7 @@ LL | iter::empty::<*const ()>() = help: the trait `Send` is not implemented for `*const ()` error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/duplicate-bound-err.rs:46:20 + --> $DIR/duplicate-bound-err.rs:45:20 | LL | fn mismatch_2() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` @@ -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:112:17 + --> $DIR/duplicate-bound-err.rs:111: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:88:42 + --> $DIR/duplicate-bound-err.rs:87: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:88:17 + --> $DIR/duplicate-bound-err.rs:87: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:97:43 + --> $DIR/duplicate-bound-err.rs:96: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:97:18 + --> $DIR/duplicate-bound-err.rs:96: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:101:43 + --> $DIR/duplicate-bound-err.rs:100: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:104:43 + --> $DIR/duplicate-bound-err.rs:103: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:112:17 + --> $DIR/duplicate-bound-err.rs:111: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:108:31 + --> $DIR/duplicate-bound-err.rs:107: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:120:16 + --> $DIR/duplicate-bound-err.rs:119:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -179,13 +179,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:80:32 + --> $DIR/duplicate-bound-err.rs:79:32 | 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:121:16 + --> $DIR/duplicate-bound-err.rs:120:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -193,13 +193,13 @@ LL | uncallable(iter::empty::()); | required by a bound introduced by this call | note: required by a bound in `uncallable` - --> $DIR/duplicate-bound-err.rs:80:44 + --> $DIR/duplicate-bound-err.rs:79:44 | 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:122:22 + --> $DIR/duplicate-bound-err.rs:121:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -209,13 +209,13 @@ LL | uncallable_const(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:82:46 + --> $DIR/duplicate-bound-err.rs:81:46 | 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:123:22 + --> $DIR/duplicate-bound-err.rs:122:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -225,13 +225,13 @@ LL | uncallable_const(4u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_const` - --> $DIR/duplicate-bound-err.rs:82:35 + --> $DIR/duplicate-bound-err.rs:81:35 | 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:124:20 + --> $DIR/duplicate-bound-err.rs:123:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,7 +241,7 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:85:61 + --> $DIR/duplicate-bound-err.rs:84:61 | LL | fn uncallable_rtn( | -------------- required by a bound in this function @@ -249,7 +249,7 @@ LL | _: impl Trait, foo(..): Trait> | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:125:20 + --> $DIR/duplicate-bound-err.rs:124:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -259,7 +259,7 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:85:34 + --> $DIR/duplicate-bound-err.rs:84:34 | LL | fn uncallable_rtn( | -------------- required by a bound in this function diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 6ea0daeca2c4..1aeb0022a04f 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -1,7 +1,7 @@ //@ edition: 2024 //@ run-pass -#![feature(associated_const_equality, min_generic_const_args, return_type_notation)] +#![feature(min_generic_const_args, return_type_notation)] #![expect(incomplete_features)] #![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)] diff --git a/tests/ui/associated-type-bounds/issue-99828.stderr b/tests/ui/associated-type-bounds/issue-99828.stderr index 132d5251987b..e1dc1f07d9cb 100644 --- a/tests/ui/associated-type-bounds/issue-99828.stderr +++ b/tests/ui/associated-type-bounds/issue-99828.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn get_iter(vec: &[i32]) -> impl Iterator + '_ { | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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: expected type, found constant diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 19c34241e5f2..9be346516c89 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -7,8 +7,8 @@ LL | impl Tr3 for Bar { | |____^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -17,8 +17,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3 for Qux { | ^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -27,8 +27,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -37,8 +37,8 @@ error[E0658]: associated const equality is incomplete LL | impl Tr3 for Bar { | ^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs index 6ab82f45e684..f2b581412a72 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.rs +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.rs @@ -1,5 +1,6 @@ //@ edition:2015 -#![feature(associated_const_equality)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] pub enum Mode { Cool, diff --git a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr index bcfad9d1538c..05e0ec93d494 100644 --- a/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr +++ b/tests/ui/const-generics/assoc_const_eq_diagnostic.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub trait CoolStuff: Parse {} | help: try using the variant's enum: `Mode` error[E0573]: expected type, found variant `Mode::Cool` - --> $DIR/assoc_const_eq_diagnostic.rs:18:17 + --> $DIR/assoc_const_eq_diagnostic.rs:19:17 | LL | fn no_help() -> Mode::Cool {} | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn no_help() -> Mode::Cool {} | help: try using the variant's enum: `Mode` error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -25,7 +25,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -43,7 +43,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub trait CoolStuff: Parse {} | + + error: expected constant, found type - --> $DIR/assoc_const_eq_diagnostic.rs:12:35 + --> $DIR/assoc_const_eq_diagnostic.rs:13:35 | LL | pub trait CoolStuff: Parse {} | ---- ^^^^^^^^^^ unexpected type @@ -62,7 +62,7 @@ LL | pub trait CoolStuff: Parse {} | expected a constant because of this associated constant | note: the associated constant is defined here - --> $DIR/assoc_const_eq_diagnostic.rs:9:5 + --> $DIR/assoc_const_eq_diagnostic.rs:10:5 | LL | const MODE: Mode; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-generics/associated_const_equality/coherence.rs b/tests/ui/const-generics/associated_const_equality/coherence.rs index fb5f255c1dc4..f4081fae6144 100644 --- a/tests/ui/const-generics/associated_const_equality/coherence.rs +++ b/tests/ui/const-generics/associated_const_equality/coherence.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] #![expect(incomplete_features)] pub trait IsVoid { diff --git a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs index 3973c7af15b4..b7ed8ee39f87 100644 --- a/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs +++ b/tests/ui/const-generics/associated_const_equality/equality_bound_with_infer.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(associated_const_equality, min_generic_const_args, generic_const_items)] +#![feature(min_generic_const_args, generic_const_items)] #![expect(incomplete_features)] // Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr index 0b487b6a7aa0..d2f28a62e04e 100644 --- a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr +++ b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace-no-feature-gate.stderr @@ -1,13 +1,3 @@ -error[E0658]: associated const equality is incomplete - --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:7:38 - | -LL | fn take0(_: impl Owner = { N }>) {} - | ^^^^^^^^^^^^ - | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` 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]: generic const items are experimental --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:2:12 | @@ -18,6 +8,16 @@ LL | const C: u32 = N; = help: add `#![feature(generic_const_items)]` 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]: associated const equality is incomplete + --> $DIR/mismatched-types-with-generic-in-ace-no-feature-gate.rs:7:38 + | +LL | fn take0(_: impl Owner = { N }>) {} + | ^^^^^^^^^^^^ + | + = 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 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs index 33afa7e3228e..77f0f06f8040 100644 --- a/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs +++ b/tests/ui/const-generics/associated_const_equality/mismatched-types-with-generic-in-ace.rs @@ -1,4 +1,4 @@ -#![feature(generic_const_items, associated_const_equality, min_generic_const_args)] +#![feature(generic_const_items, min_generic_const_args)] #![expect(incomplete_features)] trait Foo { 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 092faff93511..c34674604b51 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 @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete 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 + = 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[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index f3edc0b3fbf3..bf825a44b1c0 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -1,4 +1,4 @@ -#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![feature(generic_const_items, min_generic_const_args)] #![expect(incomplete_features)] // library crates exercise weirder code paths around // DefIds which were created for const args. 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 index 8c8c5c8e8f88..eb8f04b8b24b 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -4,7 +4,7 @@ // However, we don't allow so for const arguments in field init positions. // This is just harder to implement so we did not do so. -#![feature(min_generic_const_args, adt_const_params, associated_const_equality)] +#![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] trait Trait { diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl.rs index ae4a0004232b..1887f511bd62 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-impl.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait BadTr { const NUM: usize; diff --git a/tests/ui/const-generics/mgca/type_const-only-in-trait.rs b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs index 8c8ff6259cae..2ff38648206a 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-trait.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs @@ -1,5 +1,5 @@ #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait GoodTr { #[type_const] 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 d97b3a9f0929..5c494031d4fa 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 @@ -1,7 +1,7 @@ // Regression test for #119783 #![expect(incomplete_features)] -#![feature(associated_const_equality, min_generic_const_args)] +#![feature(min_generic_const_args)] trait Trait { #[type_const] diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr index d435af07db2a..9c956d79a7bb 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for Bar { | ^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr index f852c14b1784..4a4ff098dc4b 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -16,8 +16,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for Bar { | ^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0229]: associated item constraints are not allowed here diff --git a/tests/ui/feature-gates/feature-gate-associated_const_equality.rs b/tests/ui/feature-gates/feature-gate-associated_const_equality.rs index 2534c527be46..6b643b629a29 100644 --- a/tests/ui/feature-gates/feature-gate-associated_const_equality.rs +++ b/tests/ui/feature-gates/feature-gate-associated_const_equality.rs @@ -8,7 +8,7 @@ impl TraitWAssocConst for Demo { } fn foo>() {} -//~^ ERROR associated const equality +//~^ ERROR associated const equality is incomplete fn main() { foo::(); diff --git a/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr b/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr index 5a0fb69b6ba7..096755701931 100644 --- a/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr +++ b/tests/ui/feature-gates/feature-gate-associated_const_equality.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn foo>() {} | ^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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 1 previous error 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 a72aaedb980e..fb2506daf078 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 @@ -1,6 +1,6 @@ // ICE: assertion failed: !value.has_infer() // issue: rust-lang/rust#115806 -#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)] +#![feature(min_generic_const_args, unsized_const_params)] #![allow(incomplete_features)] pub struct NoPin; diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 37cf381e6824..d0301b920e27 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -1,7 +1,7 @@ //@ check-pass #![feature(generic_const_items, min_generic_const_args)] -#![feature(associated_const_equality, adt_const_params)] +#![feature(adt_const_params)] #![allow(incomplete_features)] trait Owner { diff --git a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr index 555d8eec6bab..3d1233cdd019 100644 --- a/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr +++ b/tests/ui/lowering/no-name-for-DefPath-issue-133426.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | fn b(_: impl Iterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0614]: type `!` cannot be dereferenced diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.stderr b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr index 02b1c3fe68a9..766acd0398d2 100644 --- a/tests/ui/parser/recover/recover-assoc-const-constraint.stderr +++ b/tests/ui/parser/recover/recover-assoc-const-constraint.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | bar::(); | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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]: associated const equality is incomplete @@ -14,8 +14,8 @@ error[E0658]: associated const equality is incomplete LL | bar::(); | ^^^^^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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 2 previous errors diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs index edea6f75444f..538b0c2b1d46 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.rs @@ -1,6 +1,6 @@ // Regression test for #140571. The compiler used to ICE -#![feature(associated_const_equality, min_generic_const_args, specialization)] +#![feature(min_generic_const_args, specialization)] //~^ WARN the feature `specialization` is incomplete //~| WARN the feature `min_generic_const_args` is incomplete diff --git a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr index bf15d0fae4e5..6159c2ed331a 100644 --- a/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr +++ b/tests/ui/specialization/overlap-due-to-unsatisfied-const-bound.stderr @@ -1,17 +1,17 @@ warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:39 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:12 | -LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #132980 for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:63 + --> $DIR/overlap-due-to-unsatisfied-const-bound.rs:3:36 | -LL | #![feature(associated_const_equality, min_generic_const_args, specialization)] - | ^^^^^^^^^^^^^^ +LL | #![feature(min_generic_const_args, specialization)] + | ^^^^^^^^^^^^^^ | = note: see issue #31844 for more information = help: consider using `min_specialization` instead, which is more stable and complete diff --git a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr index db7d2dd3e3a3..8334fdae9485 100644 --- a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr +++ b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr @@ -4,8 +4,8 @@ error[E0658]: associated const equality is incomplete LL | impl Foo for T where T: Bar {} | ^^^^^^^^^ | - = note: see issue #92827 for more information - = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + = 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[E0119]: conflicting implementations of trait `Foo` for type `()` From 3f773fac3b5a1ed57ffd9918789dab7ce0e7c0ac Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 31 Dec 2025 12:29:01 +0530 Subject: [PATCH 141/340] std: sys: fs: uefi: Implement remove_dir_all - Using the implementation from sys::fs::common since UEFI does not have a built-in for this functionality. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 14ee49e071c1..5a07e6332109 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -6,7 +6,7 @@ use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; -pub use crate::sys::fs::common::Dir; +pub use crate::sys::fs::common::{Dir, remove_dir_all}; use crate::sys::pal::{helpers, unsupported}; use crate::sys::time::SystemTime; @@ -446,10 +446,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } } -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - pub fn exists(path: &Path) -> io::Result { let f = uefi_fs::File::from_path(path, r_efi::protocols::file::MODE_READ, 0); match f { From 93f8ad99507ecb851ace4b1d4e3e7c5cd67ed80c Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Fri, 26 Dec 2025 00:13:11 +0900 Subject: [PATCH 142/340] cleaned up some tests cleaned up cast-enum-const.rs cleaned up ufcs-trait-object-format.rs add comment to cast-to-box-arr.rs add comment to shadow-primitives.rs add comment to associated-type-const-nomalization.rs add comment to fn-trait-explicit-call.rs add comment to call-unit-struct-impl-fn-once.rs add comment to cast-to-char-compare.rs add comment to self-in-method-body-resolves.rs add comment to derive-debug-newtype-unsized-slice.rs add comment to tuple-ref-order-distinct-impls.rs add comment to derive-debug-generic-with-lifetime.rs add comment to recursive-trait-bound-on-type-param.rs cleaned up const-static-ref-to-closure.rs add comment to const-iter-no-conflict-for-loop.rs --- .../associated-type-const-nomalization.rs | 1 + tests/ui/cast/cast-enum-const.rs | 12 +++---- tests/ui/cast/cast-to-box-arr.rs | 1 + tests/ui/cast/cast-to-char-compare.rs | 2 +- .../ui/consts/const-static-ref-to-closure.rs | 4 +-- .../derive-debug-generic-with-lifetime.rs | 1 + .../derive-debug-newtype-unsized-slice.rs | 1 + .../call-unit-struct-impl-fn-once.rs | 1 + tests/ui/fn_traits/fn-trait-explicit-call.rs | 1 + .../const-iter-no-conflict-for-loop.rs | 4 +++ tests/ui/resolve/shadow-primitives.rs | 33 ++++++++++--------- tests/ui/self/self-in-method-body-resolves.rs | 9 +++-- .../recursive-trait-bound-on-type-param.rs | 8 ++++- .../typeck/tuple-ref-order-distinct-impls.rs | 5 ++- tests/ui/ufcs/ufcs-trait-object-format.rs | 9 ++--- 15 files changed, 59 insertions(+), 33 deletions(-) diff --git a/tests/ui/associated-types/associated-type-const-nomalization.rs b/tests/ui/associated-types/associated-type-const-nomalization.rs index 576c7545924b..b7951ba9a435 100644 --- a/tests/ui/associated-types/associated-type-const-nomalization.rs +++ b/tests/ui/associated-types/associated-type-const-nomalization.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass trait Mirror { diff --git a/tests/ui/cast/cast-enum-const.rs b/tests/ui/cast/cast-enum-const.rs index 9cb02460f35b..cfad40c07b0e 100644 --- a/tests/ui/cast/cast-enum-const.rs +++ b/tests/ui/cast/cast-enum-const.rs @@ -1,14 +1,12 @@ +//! regression test for //@ run-pass -#![allow(non_upper_case_globals)] - -pub fn main() { - let _foo = 100; - const quux: isize = 5; +fn main() { + const QUUX: isize = 5; enum Stuff { - Bar = quux + Bar = QUUX, } - assert_eq!(Stuff::Bar as isize, quux); + assert_eq!(Stuff::Bar as isize, QUUX); } diff --git a/tests/ui/cast/cast-to-box-arr.rs b/tests/ui/cast/cast-to-box-arr.rs index 89c956913f93..1a9004cd074e 100644 --- a/tests/ui/cast/cast-to-box-arr.rs +++ b/tests/ui/cast/cast-to-box-arr.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass fn main() { let x = Box::new([1, 2, 3]); diff --git a/tests/ui/cast/cast-to-char-compare.rs b/tests/ui/cast/cast-to-char-compare.rs index 303bf7a57513..159b8ee04e02 100644 --- a/tests/ui/cast/cast-to-char-compare.rs +++ b/tests/ui/cast/cast-to-char-compare.rs @@ -1,6 +1,6 @@ +//! regression test for //@ check-pass - fn main() { if ('x' as char) < ('y' as char) { print!("x"); diff --git a/tests/ui/consts/const-static-ref-to-closure.rs b/tests/ui/consts/const-static-ref-to-closure.rs index 339aca037546..06b5ca5a935c 100644 --- a/tests/ui/consts/const-static-ref-to-closure.rs +++ b/tests/ui/consts/const-static-ref-to-closure.rs @@ -1,7 +1,7 @@ +//! regression test for //@ check-pass #![allow(dead_code)] -#![allow(non_upper_case_globals)] -const x: &'static dyn Fn() = &|| println!("ICE here"); +const X: &'static dyn Fn() = &|| println!("ICE here"); fn main() {} diff --git a/tests/ui/derives/derive-debug-generic-with-lifetime.rs b/tests/ui/derives/derive-debug-generic-with-lifetime.rs index c92853fb5dc2..430ade071795 100644 --- a/tests/ui/derives/derive-debug-generic-with-lifetime.rs +++ b/tests/ui/derives/derive-debug-generic-with-lifetime.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass #![allow(dead_code)] #[derive(Debug)] diff --git a/tests/ui/derives/derive-debug-newtype-unsized-slice.rs b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs index 689c9f33af02..c735d9f039d2 100644 --- a/tests/ui/derives/derive-debug-newtype-unsized-slice.rs +++ b/tests/ui/derives/derive-debug-newtype-unsized-slice.rs @@ -1,3 +1,4 @@ +//! regression test for //@ check-pass #![allow(dead_code)] #[derive(Debug)] diff --git a/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs index a5693b3aca8e..15554482931b 100644 --- a/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs +++ b/tests/ui/fn_traits/call-unit-struct-impl-fn-once.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/tests/ui/fn_traits/fn-trait-explicit-call.rs b/tests/ui/fn_traits/fn-trait-explicit-call.rs index 364b07bf6922..f37e0a558baa 100644 --- a/tests/ui/fn_traits/fn-trait-explicit-call.rs +++ b/tests/ui/fn_traits/fn-trait-explicit-call.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![feature(fn_traits)] diff --git a/tests/ui/resolve/const-iter-no-conflict-for-loop.rs b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs index 95edcb8695e2..ddbba64e5a31 100644 --- a/tests/ui/resolve/const-iter-no-conflict-for-loop.rs +++ b/tests/ui/resolve/const-iter-no-conflict-for-loop.rs @@ -1,3 +1,7 @@ +//! regression test for +//! Ensure that a constant named `iter` does not +//! interfere with the name resolution of the `iter` methods used internally +//! by `for` loops //@ run-pass #![allow(dead_code)] #![allow(non_upper_case_globals)] diff --git a/tests/ui/resolve/shadow-primitives.rs b/tests/ui/resolve/shadow-primitives.rs index 4018043c371e..17da0cd0530c 100644 --- a/tests/ui/resolve/shadow-primitives.rs +++ b/tests/ui/resolve/shadow-primitives.rs @@ -1,3 +1,4 @@ +//! regression test for //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] @@ -31,17 +32,10 @@ mod char { mod char_ {} mod str { - use super::i8 as i8; - use super::i32_ as i32; - use super::i64_ as i64; - use super::u8_ as u8; - use super::f_ as f64; - use super::u16_ as u16; - use super::u32_ as u32; - use super::u64_ as u64; - use super::bool_ as bool; - use super::{bool_ as str}; - use super::char_ as char; + use super::{ + bool_ as bool, bool_ as str, char_ as char, f_ as f64, i8, i32_ as i32, i64_ as i64, + u8_ as u8, u16_ as u16, u32_ as u32, u64_ as u64, + }; } } @@ -49,7 +43,9 @@ trait isize_ { type isize; } -fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize } +fn usize<'usize>(usize: &'usize usize) -> &'usize usize { + usize +} mod reuse { use std::mem::size_of; @@ -68,9 +64,10 @@ mod reuse { mod guard { pub fn check() { use std::u8; // bring module u8 in scope - fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8 + fn f() -> u8 { + // OK, resolves to primitive u8, not to std::u8 u8::max_value() // OK, resolves to associated function ::max_value, - // not to non-existent std::u8::max_value + // not to non-existent std::u8::max_value } assert_eq!(f(), u8::MAX); // OK, resolves to std::u8::MAX } @@ -79,7 +76,13 @@ mod guard { fn main() { let bool = true; let _ = match bool { - str @ true => if str { i32 as i64 } else { i64 }, + str @ true => { + if str { + i32 as i64 + } else { + i64 + } + } false => i64, }; diff --git a/tests/ui/self/self-in-method-body-resolves.rs b/tests/ui/self/self-in-method-body-resolves.rs index 95bb2af9b25c..636922cd87ce 100644 --- a/tests/ui/self/self-in-method-body-resolves.rs +++ b/tests/ui/self/self-in-method-body-resolves.rs @@ -1,11 +1,16 @@ +//! regression test for //@ check-pass #![allow(dead_code)] struct Foo; impl Foo { - fn new() -> Self { Foo } - fn bar() { Self::new(); } + fn new() -> Self { + Foo + } + fn bar() { + Self::new(); + } } fn main() {} diff --git a/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs index e97819e4122d..41ae91afad49 100644 --- a/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs +++ b/tests/ui/traits/bound/recursive-trait-bound-on-type-param.rs @@ -1,6 +1,12 @@ +//! regression test for //@ check-pass trait A {} -struct B where B: A> { t: T } +struct B +where + B: A>, +{ + t: T, +} fn main() {} diff --git a/tests/ui/typeck/tuple-ref-order-distinct-impls.rs b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs index ad0affa4b0d2..fdede8a1d9c4 100644 --- a/tests/ui/typeck/tuple-ref-order-distinct-impls.rs +++ b/tests/ui/typeck/tuple-ref-order-distinct-impls.rs @@ -1,6 +1,9 @@ +//! regression test for //@ check-pass -trait Common { fn dummy(&self) { } } +trait Common { + fn dummy(&self) {} +} impl<'t, T> Common for (T, &'t T) {} diff --git a/tests/ui/ufcs/ufcs-trait-object-format.rs b/tests/ui/ufcs/ufcs-trait-object-format.rs index 2059365c7d62..7d50a2444806 100644 --- a/tests/ui/ufcs/ufcs-trait-object-format.rs +++ b/tests/ui/ufcs/ufcs-trait-object-format.rs @@ -1,8 +1,9 @@ //@ run-pass -// Regression test for #20676. Error was that we didn't support -// UFCS-style calls to a method in `Trait` where `Self` was bound to a -// trait object of type `Trait`. See also `ufcs-trait-object.rs`. - +//! Regression test for . +//! Error was that we didn't support +//! UFCS-style calls to a method in `Trait` where `Self` was bound to a +//! trait object of type `Trait`. +//! See also . use std::fmt; From 38ab51943c5726ce71f5656e8345e0487f94e2ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Jan 2026 09:28:05 +0100 Subject: [PATCH 143/340] ./x check miri: enable check_only feature --- src/bootstrap/src/core/build_steps/check.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index df82b7baa9f9..7da2551c76fe 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -793,8 +793,7 @@ tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate, - enable_features: ["stack-cache"], - default_features: false, + enable_features: ["check_only"], }); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate }); From 0330cc24468ac4a009df902a4313c472448658bf Mon Sep 17 00:00:00 2001 From: Khashayar Fereidani Date: Mon, 5 Jan 2026 13:14:11 +0330 Subject: [PATCH 144/340] Add feature flag `likely/unlikely` for alloc --- library/alloc/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b659e904c8a0..595329c38fc2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -126,6 +126,7 @@ #![feature(iter_next_chunk)] #![feature(layout_for_ptr)] #![feature(legacy_receiver_trait)] +#![feature(likely_unlikely)] #![feature(local_waker)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] From bd79ea1b743cccde61ffda92ba4f41abdfab515c Mon Sep 17 00:00:00 2001 From: Khashayar Fereidani Date: Mon, 5 Jan 2026 13:18:41 +0330 Subject: [PATCH 145/340] Improve and optimize retain_mut implementation --- library/alloc/src/vec/mod.rs | 117 +++++++++++++++++------------------ 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f8a96e358d6d..4e76a34a72c7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -86,7 +86,7 @@ use core::mem::{self, Assume, ManuallyDrop, MaybeUninit, SizedTypeProperties, Tr use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics, ub_checks}; +use core::{fmt, hint, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -2292,13 +2292,8 @@ impl Vec { return; } - // Avoid double drop if the drop guard is not executed, - // since we may make some holes during the process. - unsafe { self.set_len(0) }; - // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked] - // |<- processed len ->| ^- next to check - // |<- deleted cnt ->| + // | ^- write ^- read | // |<- original_len ->| // Kept: Elements which predicate returns true on. // Hole: Moved or dropped element slot. @@ -2307,77 +2302,77 @@ impl Vec { // This drop guard will be invoked when predicate or `drop` of element panicked. // It shifts unchecked elements to cover holes and `set_len` to the correct length. // In cases when predicate and `drop` never panick, it will be optimized out. - struct BackshiftOnDrop<'a, T, A: Allocator> { + struct PanicGuard<'a, T, A: Allocator> { v: &'a mut Vec, - processed_len: usize, - deleted_cnt: usize, + read: usize, + write: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, T, A> { + impl Drop for PanicGuard<'_, T, A> { + #[cold] fn drop(&mut self) { - if self.deleted_cnt > 0 { - // SAFETY: Trailing unchecked items must be valid since we never touch them. - unsafe { - ptr::copy( - self.v.as_ptr().add(self.processed_len), - self.v.as_mut_ptr().add(self.processed_len - self.deleted_cnt), - self.original_len - self.processed_len, - ); - } + let remaining = self.original_len - self.read; + // SAFETY: Trailing unchecked items must be valid since we never touch them. + unsafe { + ptr::copy( + self.v.as_ptr().add(self.read), + self.v.as_mut_ptr().add(self.write), + remaining, + ); } // SAFETY: After filling holes, all items are in contiguous memory. unsafe { - self.v.set_len(self.original_len - self.deleted_cnt); + self.v.set_len(self.write + remaining); } } } - let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - - fn process_loop( - original_len: usize, - f: &mut F, - g: &mut BackshiftOnDrop<'_, T, A>, - ) where - F: FnMut(&mut T) -> bool, - { - while g.processed_len != original_len { - // SAFETY: Unchecked element must be valid. - let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; - if !f(cur) { - // Advance early to avoid double drop if `drop_in_place` panicked. - g.processed_len += 1; - g.deleted_cnt += 1; - // SAFETY: We never touch this element again after dropped. - unsafe { ptr::drop_in_place(cur) }; - // We already advanced the counter. - if DELETED { - continue; - } else { - break; - } - } - if DELETED { - // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. - // We use copy for move, and never touch this element again. - unsafe { - let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); - ptr::copy_nonoverlapping(cur, hole_slot, 1); - } - } - g.processed_len += 1; + let mut read = 0; + loop { + // SAFETY: read < original_len + let cur = unsafe { self.get_unchecked_mut(read) }; + if hint::unlikely(!f(cur)) { + break; + } + read += 1; + if read == original_len { + // All elements are kept, return early. + return; } } - // Stage 1: Nothing was deleted. - process_loop::(original_len, &mut f, &mut g); + // Critical section starts here and at least one element is going to be removed. + // Advance `g.read` early to avoid double drop if `drop_in_place` panicked. + let mut g = PanicGuard { v: self, read: read + 1, write: read, original_len }; + // SAFETY: previous `read` is always less than original_len. + unsafe { ptr::drop_in_place(&mut *g.v.as_mut_ptr().add(read)) }; - // Stage 2: Some elements were deleted. - process_loop::(original_len, &mut f, &mut g); + while g.read < g.original_len { + // SAFETY: `read` is always less than original_len. + let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.read) }; + if !f(cur) { + // Advance `read` early to avoid double drop if `drop_in_place` panicked. + g.read += 1; + // SAFETY: We never touch this element again after dropped. + unsafe { ptr::drop_in_place(cur) }; + } else { + // SAFETY: `read` > `write`, so the slots don't overlap. + // We use copy for move, and never touch the source element again. + unsafe { + let hole = g.v.as_mut_ptr().add(g.write); + ptr::copy_nonoverlapping(cur, hole, 1); + } + g.write += 1; + g.read += 1; + } + } - // All item are processed. This can be optimized to `set_len` by LLVM. - drop(g); + // We are leaving the critical section and no panic happened, + // Commit the length change and forget the guard. + // SAFETY: `write` is always less than or equal to original_len. + unsafe { g.v.set_len(g.write) }; + mem::forget(g); } /// Removes all but the first of consecutive elements in the vector that resolve to the same From 75eaa452681e8008a24a7bd2ce8d44bad38d5a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:23:13 +0100 Subject: [PATCH 146/340] Allow building cg_gcc without building libgccjit --- src/bootstrap/src/core/build_steps/compile.rs | 106 ++++++++---------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 762aeea9f451..adfb3c21d38e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -19,7 +19,7 @@ use serde_derive::Deserialize; #[cfg(feature = "tracing")] use tracing::span; -use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags}; +use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair}; use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; @@ -1569,21 +1569,29 @@ impl Step for RustcLink { } /// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets. +/// `libgccjit` requires a separate build for each `(host, target)` pair. +/// So if you are on linux-x64 and build for linux-aarch64, you will need at least: +/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros) +/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code) #[derive(Clone)] pub struct GccDylibSet { dylibs: BTreeMap, - host_pair: GccTargetPair, } impl GccDylibSet { - /// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be - /// executed, and which will target the host. So e.g. if `cg_gcc` will be executed on - /// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair - /// `(x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu)`. - fn host_dylib(&self) -> &GccOutput { - self.dylibs.get(&self.host_pair).unwrap_or_else(|| { - panic!("libgccjit.so was not built for host target {}", self.host_pair) - }) + /// Build a set of libgccjit dylibs that will be executed on `host` and will generate code for + /// each specified target. + pub fn build( + builder: &Builder<'_>, + host: TargetSelection, + targets: Vec, + ) -> Self { + let dylibs = targets + .iter() + .map(|t| GccTargetPair::for_target_pair(host, *t)) + .map(|target_pair| (target_pair, builder.ensure(Gcc { target_pair }))) + .collect(); + Self { dylibs } } /// Install the libgccjit dylibs to the corresponding target directories of the given compiler. @@ -1626,39 +1634,28 @@ impl GccDylibSet { /// Output of the `compile::GccCodegenBackend` step. /// -/// It contains paths to all built libgccjit libraries on which this backend depends here. +/// It contains a build stamp with the path to the built cg_gcc dylib. #[derive(Clone)] pub struct GccCodegenBackendOutput { stamp: BuildStamp, - dylib_set: GccDylibSet, } /// Builds the GCC codegen backend (`cg_gcc`). -/// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each -/// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64, -/// you will need at least: -/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros) -/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code) -/// -/// We model this by having a single cg_gcc for a given host target, which contains one -/// libgccjit per (host, target) pair. -/// Note that the host target is taken from `self.compilers.target_compiler.host`. +/// Note that this **does not** build libgccjit, which is a dependency of cg_gcc. +/// That has to be built separately, because a separate copy of libgccjit is required +/// for each (host, target) compilation pair. +/// cg_gcc goes to great lengths to ensure that it does not *directly* link to libgccjit, +/// so we respect that here and allow building cg_gcc without building libgccjit itself. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GccCodegenBackend { compilers: RustcPrivateCompilers, - targets: Vec, + target: TargetSelection, } impl GccCodegenBackend { - /// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be - /// able to produce code target pairs (`H`, `T`) for all `T` from `targets`. - pub fn for_targets( - compilers: RustcPrivateCompilers, - mut targets: Vec, - ) -> Self { - // Sort targets to improve step cache hits - targets.sort(); - Self { compilers, targets } + /// Build `cg_gcc` that will run on the given host target. + pub fn for_target(compilers: RustcPrivateCompilers, target: TargetSelection) -> Self { + Self { compilers, target } } } @@ -1672,10 +1669,8 @@ impl Step for GccCodegenBackend { } fn make_run(run: RunConfig<'_>) { - // By default, build cg_gcc that will only be able to compile native code for the given - // host target. let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target); - run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] }); + run.builder.ensure(GccCodegenBackend::for_target(compilers, run.target)); } fn run(self, builder: &Builder<'_>) -> Self::Output { @@ -1689,18 +1684,6 @@ impl Step for GccCodegenBackend { &CodegenBackendKind::Gcc, ); - let dylib_set = GccDylibSet { - dylibs: self - .targets - .iter() - .map(|&target| { - let target_pair = GccTargetPair::for_target_pair(host, target); - (target_pair, builder.ensure(Gcc { target_pair })) - }) - .collect(), - host_pair: GccTargetPair::for_native_build(host), - }; - if builder.config.keep_stage.contains(&build_compiler.stage) { trace!("`keep-stage` requested"); builder.info( @@ -1709,7 +1692,7 @@ impl Step for GccCodegenBackend { ); // Codegen backends are linked separately from this step today, so we don't do // anything here. - return GccCodegenBackendOutput { stamp, dylib_set }; + return GccCodegenBackendOutput { stamp }; } let mut cargo = builder::Cargo::new( @@ -1723,15 +1706,12 @@ impl Step for GccCodegenBackend { cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml")); rustc_cargo_env(builder, &mut cargo, host); - add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib()); - let _guard = builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); GccCodegenBackendOutput { stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), - dylib_set, } } @@ -2457,12 +2437,18 @@ impl Step for Assemble { // GCC dylibs built below by taking a look at the current stage and whether // cg_gcc is used as the default codegen backend. + // First, the easy part: build cg_gcc let compilers = prepare_compilers(); + let cg_gcc = builder + .ensure(GccCodegenBackend::for_target(compilers, target_compiler.host)); + copy_codegen_backends_to_sysroot(builder, cg_gcc.stamp, target_compiler); + + // Then, the hard part: prepare all required libgccjit dylibs. // The left side of the target pairs below is implied. It has to match the - // host target on which cg_gcc will run, which is the host target of + // host target on which libgccjit will be used, which is the host target of // `target_compiler`. We only pass the right side of the target pairs to - // the `GccCodegenBackend` constructor. + // the `GccDylibSet` constructor. let mut targets = HashSet::new(); // Add all host targets, so that we are able to build host code in this // bootstrap invocation using cg_gcc. @@ -2477,14 +2463,16 @@ impl Step for Assemble { // host code (e.g. proc macros) using cg_gcc. targets.insert(compilers.target_compiler().host); - let output = builder.ensure(GccCodegenBackend::for_targets( - compilers, + // Now build all the required libgccjit dylibs + let dylib_set = GccDylibSet::build( + builder, + compilers.target_compiler().host, targets.into_iter().collect(), - )); - copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler); - // Also copy all requires libgccjit dylibs to the corresponding - // library sysroots, so that they are available for the codegen backend. - output.dylib_set.install_to(builder, target_compiler); + ); + + // And then copy all the dylibs to the corresponding + // library sysroots, so that they are available for cg_gcc. + dylib_set.install_to(builder, target_compiler); } CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue, } From 2b53ecaff4ab1a7c8279ca182c6433f488312b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:39:15 +0100 Subject: [PATCH 147/340] Add a dist step for the GCC codegen backend --- src/bootstrap/src/core/build_steps/compile.rs | 6 + src/bootstrap/src/core/build_steps/dist.rs | 125 +++++++++++++++--- src/bootstrap/src/core/builder/mod.rs | 1 + src/bootstrap/src/utils/tarball.rs | 7 + src/tools/opt-dist/src/main.rs | 1 + 5 files changed, 123 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index adfb3c21d38e..a42d46a8c018 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1640,6 +1640,12 @@ pub struct GccCodegenBackendOutput { stamp: BuildStamp, } +impl GccCodegenBackendOutput { + pub fn stamp(&self) -> &BuildStamp { + &self.stamp + } +} + /// Builds the GCC codegen backend (`cg_gcc`). /// Note that this **does not** build libgccjit, which is a dependency of cg_gcc. /// That has to be built separately, because a separate copy of libgccjit is required diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0e7051cc22df..f47b0c0b0072 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1652,23 +1652,7 @@ impl Step for CraneliftCodegenBackend { return None; } - // Get the relative path of where the codegen backend should be stored. - let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler()); - let backends_rel = backends_dst - .strip_prefix(builder.sysroot(compilers.target_compiler())) - .unwrap() - .strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler())) - .unwrap(); - // Don't use custom libdir here because ^lib/ will be resolved again with installer - let backends_dst = PathBuf::from("lib").join(backends_rel); - - let codegen_backend_dylib = get_codegen_backend_file(&stamp); - tarball.add_renamed_file( - &codegen_backend_dylib, - &backends_dst, - &normalize_codegen_backend_name(builder, &codegen_backend_dylib), - FileType::NativeLibrary, - ); + add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp); Some(tarball.generate()) } @@ -1681,6 +1665,113 @@ impl Step for CraneliftCodegenBackend { } } +/// Builds a dist component containing the GCC codegen backend. +/// Note that for this backend to work, it must have a set of libgccjit dylibs available +/// at runtime. +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct GccCodegenBackend { + pub compilers: RustcPrivateCompilers, + pub target: TargetSelection, +} + +impl Step for GccCodegenBackend { + type Output = Option; + const IS_HOST: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("rustc_codegen_gcc") + } + + fn is_default_step(builder: &Builder<'_>) -> bool { + // We only want to build the gcc backend in `x dist` if the backend was enabled + // in rust.codegen-backends. + // Sadly, we don't have access to the actual target for which we're disting clif here.. + // So we just use the host target. + builder + .config + .enabled_codegen_backends(builder.host_target) + .contains(&CodegenBackendKind::Gcc) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(GccCodegenBackend { + compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + // This prevents rustc_codegen_gcc from being built for "dist" + // or "install" on the stable/beta channels. It is not yet stable and + // should not be included. + if !builder.build.unstable_features() { + return None; + } + + let target = self.target; + if target != "x86_64-unknown-linux-gnu" { + builder + .info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping")); + return None; + } + + let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple); + tarball.set_overlay(OverlayKind::RustcCodegenGcc); + tarball.is_preview(true); + tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc"); + + let compilers = self.compilers; + let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target)); + + if builder.config.dry_run() { + return None; + } + + add_codegen_backend_to_tarball( + builder, + &tarball, + compilers.target_compiler(), + backend.stamp(), + ); + + Some(tarball.generate()) + } + + fn metadata(&self) -> Option { + Some( + StepMetadata::dist("rustc_codegen_gcc", self.target) + .built_by(self.compilers.build_compiler()), + ) + } +} + +/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given +/// `tarball` at the correct place. +fn add_codegen_backend_to_tarball( + builder: &Builder<'_>, + tarball: &Tarball<'_>, + compiler: Compiler, + stamp: &BuildStamp, +) { + // Get the relative path of where the codegen backend should be stored. + let backends_dst = builder.sysroot_codegen_backends(compiler); + let backends_rel = backends_dst + .strip_prefix(builder.sysroot(compiler)) + .unwrap() + .strip_prefix(builder.sysroot_libdir_relative(compiler)) + .unwrap(); + // Don't use custom libdir here because ^lib/ will be resolved again with installer + let backends_dst = PathBuf::from("lib").join(backends_rel); + + let codegen_backend_dylib = get_codegen_backend_file(stamp); + tarball.add_renamed_file( + &codegen_backend_dylib, + &backends_dst, + &normalize_codegen_backend_name(builder, &codegen_backend_dylib), + FileType::NativeLibrary, + ); +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { pub compilers: RustcPrivateCompilers, diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 92a6eb8ce837..0164cc5310c2 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -967,6 +967,7 @@ impl<'a> Builder<'a> { dist::Mingw, dist::Rustc, dist::CraneliftCodegenBackend, + dist::GccCodegenBackend, dist::Std, dist::RustcDev, dist::Analysis, diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 079afb7a0054..7db06dcc3e9a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -25,6 +25,7 @@ pub(crate) enum OverlayKind { Rustfmt, RustAnalyzer, RustcCodegenCranelift, + RustcCodegenGcc, LlvmBitcodeLinker, } @@ -66,6 +67,11 @@ impl OverlayKind { "compiler/rustc_codegen_cranelift/LICENSE-APACHE", "compiler/rustc_codegen_cranelift/LICENSE-MIT", ], + OverlayKind::RustcCodegenGcc => &[ + "compiler/rustc_codegen_gcc/Readme.md", + "compiler/rustc_codegen_gcc/LICENSE-APACHE", + "compiler/rustc_codegen_gcc/LICENSE-MIT", + ], OverlayKind::LlvmBitcodeLinker => &[ "COPYRIGHT", "LICENSE-APACHE", @@ -93,6 +99,7 @@ impl OverlayKind { .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), OverlayKind::RustcCodegenCranelift => builder.rust_version(), + OverlayKind::RustcCodegenGcc => builder.rust_version(), OverlayKind::LlvmBitcodeLinker => builder.rust_version(), } } diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 5515dbf1940e..b17cfb567e5b 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -456,6 +456,7 @@ fn main() -> anyhow::Result<()> { "rustfmt", "generate-copyright", "bootstrap", + "rustc_codegen_gcc", ] { build_args.extend(["--skip".to_string(), target.to_string()]); } From 9b789f0bd05477690eaf01dc8698f34678652f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 31 Dec 2025 13:39:23 +0100 Subject: [PATCH 148/340] Dist cg_gcc on CI --- src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index 9579e0d79cb0..f77a0d562f03 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -7,7 +7,9 @@ python3 ../x.py build --set rust.debug=true opt-dist ./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ - build-manifest bootstrap + build-manifest \ + bootstrap \ + rustc_codegen_gcc # Use GCC for building GCC components, as it seems to behave badly when built with Clang # Only build GCC on full builds, not try builds From 04707f4f86ea0b484da9c368dcb81fdfb7939bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Jan 2026 10:05:30 +0100 Subject: [PATCH 149/340] Only keep old cg_gcc if the stamp file actually exists --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index a42d46a8c018..02be3f2cc735 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1690,7 +1690,7 @@ impl Step for GccCodegenBackend { &CodegenBackendKind::Gcc, ); - if builder.config.keep_stage.contains(&build_compiler.stage) { + if builder.config.keep_stage.contains(&build_compiler.stage) && stamp.path().exists() { trace!("`keep-stage` requested"); builder.info( "WARNING: Using a potentially old codegen backend. \ From 304101f21241f8ba3692b5c917e23252a37709b0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 4 Jan 2026 18:39:59 +1100 Subject: [PATCH 150/340] Move all `thir::Pat` creation into `rustc_mir_build::thir::pattern` --- compiler/rustc_mir_build/src/thir/cx/block.rs | 24 +------------- compiler/rustc_mir_build/src/thir/cx/mod.rs | 22 +++++++++---- .../rustc_mir_build/src/thir/pattern/mod.rs | 32 +++++++++++++++++-- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 57ddb8eddb8e..7cdd70a7fc27 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -2,8 +2,6 @@ use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::middle::region; use rustc_middle::thir::*; -use rustc_middle::ty; -use rustc_middle::ty::CanonicalUserTypeAnnotation; use tracing::debug; use crate::thir::cx::ThirBuildCx; @@ -73,29 +71,9 @@ impl<'tcx> ThirBuildCx<'tcx> { let else_block = local.els.map(|els| self.mirror_block(els)); - let mut pattern = self.pattern_from_hir(local.pat); + let pattern = self.pattern_from_hir_with_annotation(local.pat, local.ty); debug!(?pattern); - if let Some(ty) = &local.ty - && let Some(&user_ty) = - self.typeck_results.user_provided_types().get(ty.hir_id) - { - debug!("mirror_stmts: user_ty={:?}", user_ty); - let annotation = CanonicalUserTypeAnnotation { - user_ty: Box::new(user_ty), - span: ty.span, - inferred_ty: self.typeck_results.node_type(ty.hir_id), - }; - pattern = Box::new(Pat { - ty: pattern.ty, - span: pattern.span, - kind: PatKind::AscribeUserType { - ascription: Ascription { annotation, variance: ty::Covariant }, - subpattern: pattern, - }, - }); - } - let span = match local.init { Some(init) => local.span.with_hi(init.span.hi()), None => local.span, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index d26dfac0c2ab..79e85a243f40 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -12,9 +12,6 @@ use rustc_hir::{self as hir, HirId, find_attr}; use rustc_middle::bug; use rustc_middle::thir::*; use rustc_middle::ty::{self, TyCtxt}; -use tracing::instrument; - -use crate::thir::pattern::pat_from_hir; /// Query implementation for [`TyCtxt::thir_body`]. pub(crate) fn thir_body( @@ -111,9 +108,22 @@ impl<'tcx> ThirBuildCx<'tcx> { } } - #[instrument(level = "debug", skip(self))] - fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box> { - pat_from_hir(self.tcx, self.typing_env, self.typeck_results, p) + fn pattern_from_hir(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { + self.pattern_from_hir_with_annotation(pat, None) + } + + fn pattern_from_hir_with_annotation( + &mut self, + pat: &'tcx hir::Pat<'tcx>, + let_stmt_type: Option<&hir::Ty<'tcx>>, + ) -> Box> { + crate::thir::pattern::pat_from_hir( + self.tcx, + self.typing_env, + self.typeck_results, + pat, + let_stmt_type, + ) } fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0310003e7d58..76890316ba44 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -38,11 +38,14 @@ struct PatCtxt<'tcx> { rust_2024_migration: Option>, } +#[instrument(level = "debug", skip(tcx, typing_env, typeck_results), ret)] pub(super) fn pat_from_hir<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, typeck_results: &'tcx ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, + // Present if `pat` came from a let statement with an explicit type annotation + let_stmt_type: Option<&hir::Ty<'tcx>>, ) -> Box> { let mut pcx = PatCtxt { tcx, @@ -53,12 +56,35 @@ pub(super) fn pat_from_hir<'tcx>( .get(pat.hir_id) .map(PatMigration::new), }; - let result = pcx.lower_pattern(pat); - debug!("pat_from_hir({:?}) = {:?}", pat, result); + + let mut thir_pat = pcx.lower_pattern(pat); + + // If this pattern came from a let statement with an explicit type annotation + // (e.g. `let x: Foo = ...`), retain that user type information in the THIR pattern. + if let Some(let_stmt_type) = let_stmt_type + && let Some(&user_ty) = typeck_results.user_provided_types().get(let_stmt_type.hir_id) + { + debug!(?user_ty); + let annotation = CanonicalUserTypeAnnotation { + user_ty: Box::new(user_ty), + span: let_stmt_type.span, + inferred_ty: typeck_results.node_type(let_stmt_type.hir_id), + }; + thir_pat = Box::new(Pat { + ty: thir_pat.ty, + span: thir_pat.span, + kind: PatKind::AscribeUserType { + ascription: Ascription { annotation, variance: ty::Covariant }, + subpattern: thir_pat, + }, + }); + } + if let Some(m) = pcx.rust_2024_migration { m.emit(tcx, pat.hir_id); } - result + + thir_pat } impl<'tcx> PatCtxt<'tcx> { From 3d6a2c5ae1685cda3a1ec8357a21fc7f76c7c6be Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 5 Jan 2026 12:05:23 +0000 Subject: [PATCH 151/340] relate.rs: tiny cleanup: eliminate temp vars 2 --- compiler/rustc_type_ir/src/relate.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 9e14bf6b60ad..3610605462ba 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -216,11 +216,7 @@ impl Relate for ty::AliasTy { b: ty::AliasTy, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let cx = relation.cx(); let args = if let Some(variances) = cx.opt_alias_variances(a.kind(cx), a.def_id) { @@ -240,11 +236,7 @@ impl Relate for ty::AliasTerm { b: ty::AliasTerm, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let args = match a.kind(relation.cx()) { ty::AliasTermKind::OpaqueTy => relate_args_with_variances( @@ -275,11 +267,7 @@ impl Relate for ty::ExistentialProjection { b: ty::ExistentialProjection, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched({ - let a = a.def_id; - let b = b.def_id; - ExpectedFound::new(a, b) - })) + Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) } else { let term = relation.relate_with_variance( ty::Invariant, From a956b56d6db0f9ad54b555b8ef52539c0c6b3bc2 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 5 Jan 2026 14:10:50 +0100 Subject: [PATCH 152/340] Improve comment clarity in candidate_may_shadow --- compiler/rustc_hir_typeck/src/method/probe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1a25f6a582f2..beb0337d8c59 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -190,8 +190,8 @@ impl PickConstraintsForShadowed { // An item never shadows itself candidate.item.def_id != self.def_id // and we're only concerned about inherent impls doing the shadowing. - // Shadowing can only occur if the shadowed is further along - // the Receiver dereferencing chain than the shadowed. + // Shadowing can only occur if the impl being shadowed is further along + // the Receiver dereferencing chain than the impl doing the shadowing. && match candidate.kind { CandidateKind::InherentImplCandidate { receiver_steps, .. } => match self.receiver_steps { Some(shadowed_receiver_steps) => receiver_steps > shadowed_receiver_steps, From ba13bb44edd8a96c6de25e98ac70d9b6eefc163e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Jan 2026 08:05:20 -0800 Subject: [PATCH 153/340] Update wasm-component-ld Same as 147495, just keeping it up-to-date. --- Cargo.lock | 53 +++++++++++++------------- src/tools/wasm-component-ld/Cargo.toml | 2 +- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 816bb1a37859..470b38d5a91c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6221,9 +6221,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "38.0.4" +version = "40.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682" +checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1" [[package]] name = "wasm-bindgen" @@ -6272,17 +6272,18 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.19" +version = "0.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115" +checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789" dependencies = [ "anyhow", "clap", + "clap_lex", "lexopt", "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.241.2", + "wasmparser 0.243.0", "wat", "windows-sys 0.61.2", "winsplit", @@ -6309,24 +6310,24 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8" +checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35" dependencies = [ "leb128fmt", - "wasmparser 0.241.2", + "wasmparser 0.243.0", ] [[package]] name = "wasm-metadata" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167" +checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.241.2", - "wasmparser 0.241.2", + "wasm-encoder 0.243.0", + "wasmparser 0.243.0", ] [[package]] @@ -6351,9 +6352,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8" +checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ "bitflags", "hashbrown 0.15.5", @@ -6364,22 +6365,22 @@ dependencies = [ [[package]] name = "wast" -version = "241.0.2" +version = "243.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816" +checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.2", - "wasm-encoder 0.241.2", + "wasm-encoder 0.243.0", ] [[package]] name = "wat" -version = "1.241.2" +version = "1.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d" +checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b" dependencies = [ "wast", ] @@ -6775,9 +6776,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241" +checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4" dependencies = [ "anyhow", "bitflags", @@ -6786,17 +6787,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.241.2", + "wasm-encoder 0.243.0", "wasm-metadata", - "wasmparser 0.241.2", + "wasmparser 0.243.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.241.2" +version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91" +checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc" dependencies = [ "anyhow", "id-arena", @@ -6807,7 +6808,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.241.2", + "wasmparser 0.243.0", ] [[package]] diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 744b67c17f65..2d44358c7433 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.19" +wasm-component-ld = "0.5.20" From 1925afb7b08e3de09af0bb06fd60fbc3ce82b178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 5 Jan 2026 17:18:52 +0100 Subject: [PATCH 154/340] Enable merge queue in new bors --- rust-bors.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-bors.toml b/rust-bors.toml index 384343e431dc..0d59918e3f77 100644 --- a/rust-bors.toml +++ b/rust-bors.toml @@ -29,8 +29,7 @@ labels_blocking_approval = [ # If CI runs quicker than this duration, consider it to be a failure min_ci_time = 600 -# Flip this once new bors is used for actual merges on this repository -merge_queue_enabled = false +merge_queue_enabled = true report_merge_conflicts = true [labels] @@ -55,7 +54,9 @@ try_failed = [ "-S-waiting-on-review", "-S-waiting-on-crater" ] -auto_build_succeeded = ["+merged-by-bors"] +auto_build_succeeded = [ + "+merged-by-bors" +] auto_build_failed = [ "+S-waiting-on-review", "-S-blocked", From accfc34e43b0fb6ef9ac162ca256ae270b6d468e Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 11 Dec 2025 10:31:33 -0500 Subject: [PATCH 155/340] rustc_codegen_llvm: update alignment for double on AIX This was recently fixed upstream in LLVM, so we update our default layout to match. @rustbot label: +llvm-main --- compiler/rustc_codegen_llvm/src/context.rs | 4 ++++ compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 07b04863af6b..4b2544b7efdf 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -211,6 +211,10 @@ pub(crate) unsafe fn create_module<'ll>( // LLVM 22 updated the NVPTX layout to indicate 256-bit vector load/store: https://github.com/llvm/llvm-project/pull/155198 target_data_layout = target_data_layout.replace("-i256:256", ""); } + if sess.target.arch == Arch::PowerPC64 { + // LLVM 22 updated the ABI alignment for double on AIX: https://github.com/llvm/llvm-project/pull/144673 + target_data_layout = target_data_layout.replace("-f64:32:64", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index b4f394643a9d..b83f5544a351 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -17,7 +17,8 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-f64:32:64-S128-v256:256:256-v512:512:512" + .into(), arch: Arch::PowerPC64, options: base, } From 85c8e41f62f1c347f2b5c2f5f008a238ecff22e9 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 5 Jan 2026 09:01:23 +0000 Subject: [PATCH 156/340] add pretty printing --- compiler/rustc_hir_pretty/src/lib.rs | 36 ++++++++++++++--- ...struct-exprs-tuple-call-pretty-printing.rs | 33 ++++++++++++++++ ...ct-exprs-tuple-call-pretty-printing.stdout | 39 +++++++++++++++++++ 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs create mode 100644 tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 533afc372063..feaada638f07 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -17,9 +17,9 @@ use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir::attrs::{AttributeKind, PrintAttribute}; use rustc_hir::{ - BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, - HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TyPatKind, + BindingMode, ByRef, ConstArg, ConstArgExprField, ConstArgKind, GenericArg, GenericBound, + GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, + PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, Ident, Span, Symbol, kw, sym}; @@ -1137,9 +1137,8 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { - // FIXME(mgca): proper printing for struct exprs - ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), - ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"), + ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), + ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), @@ -1147,6 +1146,31 @@ impl<'a> State<'a> { } } + fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) { + self.print_qpath(qpath, true); + self.word(" "); + self.word("{"); + if !fields.is_empty() { + self.nbsp(); + } + self.commasep(Inconsistent, *fields, |s, field| { + s.word(field.field.as_str().to_string()); + s.word(":"); + s.nbsp(); + s.print_const_arg(field.expr); + }); + self.word("}"); + } + + fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) { + self.print_qpath(qpath, true); + self.word("("); + self.commasep(Inconsistent, *args, |s, arg| { + s.print_const_arg(arg); + }); + self.word(")"); + } + fn print_call_post(&mut self, args: &[hir::Expr<'_>]) { self.popen(); self.commasep_exprs(Inconsistent, args); diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs new file mode 100644 index 000000000000..5f2d6680efac --- /dev/null +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.rs @@ -0,0 +1,33 @@ +//@ compile-flags: -Zunpretty=hir +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] + +use std::marker::ConstParamTy; + +struct Point(u32, u32); + +struct Point3(); + +struct Point1 { + a: u32, + b: u32, +} + +struct Point2 {} + +fn with_point() {} +fn with_point1() {} +fn with_point2() {} +fn with_point3() {} + +fn test() { + with_point::<{ Point(N, N) }>(); + with_point1::<{ Point1 { a: N, b: N } }>(); + with_point2::<{ Point2 {} }>(); + with_point3::<{ Point3() }>(); +} + +fn main() {} diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout new file mode 100644 index 000000000000..fc0fbe8ef237 --- /dev/null +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -0,0 +1,39 @@ +//@ compile-flags: -Zunpretty=hir +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![allow(dead_code)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +use std::marker::ConstParamTy; + +struct Point(u32, u32); + +struct Point3(); + +struct Point1 { + a: u32, + b: u32, +} + +struct Point2 { +} + +fn with_point() { } +fn with_point1() { } +fn with_point2() { } +fn with_point3() { } + +fn test() { + with_point::(); + with_point1::(); + with_point2::(); + with_point3::(); +} + +fn main() { } From 85d7fb0755432cdd65f88c3d9cb372fbc49c29fb Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Mon, 5 Jan 2026 23:28:24 +0000 Subject: [PATCH 157/340] Remove copyright year --- COPYRIGHT | 2 +- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- README.md | 2 +- clippy_utils/README.md | 2 +- rustc_tools_util/README.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/COPYRIGHT b/COPYRIGHT index 5d3075903a01..d3b4c9e5fb2c 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,6 +1,6 @@ // REUSE-IgnoreStart -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 6f6e5844208d..773ae298cc19 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index a51639bc0f9b..9549420685cc 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index 287dee82daaa..8bccd040c1f9 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license diff --git a/clippy_utils/README.md b/clippy_utils/README.md index e3ce95d30074..69bb6a2d6669 100644 --- a/clippy_utils/README.md +++ b/clippy_utils/README.md @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md index 083814e1e05d..45d2844ad00b 100644 --- a/rustc_tools_util/README.md +++ b/rustc_tools_util/README.md @@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under: -Copyright 2014-2026 The Rust Project Developers +Copyright (c) The Rust Project Contributors Licensed under the Apache License, Version 2.0 or the MIT license From fa4a62b06656b46afbd3398dc75b10997b3ab7db Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 27 Dec 2025 00:26:21 +0100 Subject: [PATCH 158/340] use PIDFD_GET_INFO ioctl when available This way using pidfd_spawnp won't have to rely on procfs, avoiding an unpleasant edge-case where the child is spawned but we can't get the pid. And `pidfd.{try_}wait` will be able to return the exit status even after a process has been reaped. At least on newer kernels. --- library/std/src/os/linux/process.rs | 10 +- library/std/src/sys/pal/unix/linux/pidfd.rs | 101 ++++++++++++++---- .../std/src/sys/pal/unix/linux/pidfd/tests.rs | 38 ++++--- library/std/src/sys/process/unix/unix.rs | 40 +++---- 4 files changed, 132 insertions(+), 57 deletions(-) diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs index fef321436f6a..60851db831bf 100644 --- a/library/std/src/os/linux/process.rs +++ b/library/std/src/os/linux/process.rs @@ -67,8 +67,10 @@ impl PidFd { /// Waits for the child to exit completely, returning the status that it exited with. /// /// Unlike [`Child::wait`] it does not ensure that the stdin handle is closed. - /// Additionally it will not return an `ExitStatus` if the child - /// has already been reaped. Instead an error will be returned. + /// + /// Additionally on kernels prior to 6.15 only the first attempt to + /// reap a child will return an ExitStatus, further attempts + /// will return an Error. /// /// [`Child::wait`]: process::Child::wait pub fn wait(&self) -> Result { @@ -77,8 +79,8 @@ impl PidFd { /// Attempts to collect the exit status of the child if it has already exited. /// - /// Unlike [`Child::try_wait`] this method will return an Error - /// if the child has already been reaped. + /// On kernels prior to 6.15, and unlike [`Child::try_wait`], only the first attempt + /// to reap a child will return an ExitStatus, further attempts will return an Error. /// /// [`Child::try_wait`]: process::Child::try_wait pub fn try_wait(&self) -> Result> { diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index 7859854e96b4..e9e4831fcc02 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -1,5 +1,5 @@ use crate::io; -use crate::os::fd::{AsRawFd, FromRawFd, RawFd}; +use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys::process::ExitStatus; use crate::sys::{AsInner, FromInner, IntoInner, cvt}; @@ -15,6 +15,73 @@ impl PidFd { self.send_signal(libc::SIGKILL) } + #[cfg(any(test, target_env = "gnu", target_env = "musl"))] + pub(crate) fn current_process() -> io::Result { + let pid = crate::process::id(); + let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, pid, 0) })?; + Ok(unsafe { PidFd::from_raw_fd(pidfd as RawFd) }) + } + + #[cfg(any(test, target_env = "gnu", target_env = "musl"))] + pub(crate) fn pid(&self) -> io::Result { + use crate::sys::weak::weak; + + // since kernel 6.13 + // https://lore.kernel.org/all/20241010155401.2268522-1-luca.boccassi@gmail.com/ + let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() }; + pidfd_info.mask = libc::PIDFD_INFO_PID as u64; + match cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) }) + { + Ok(_) => {} + Err(e) if e.raw_os_error() == Some(libc::EINVAL) => { + // kernel doesn't support that ioctl, try the glibc helper that looks at procfs + weak!( + fn pidfd_getpid(pidfd: RawFd) -> libc::pid_t; + ); + if let Some(pidfd_getpid) = pidfd_getpid.get() { + let pid: libc::c_int = cvt(unsafe { pidfd_getpid(self.0.as_raw_fd()) })?; + return Ok(pid as u32); + } + return Err(e); + } + Err(e) => return Err(e), + } + + Ok(pidfd_info.pid) + } + + fn exit_for_reaped_child(&self) -> io::Result { + // since kernel 6.15 + // https://lore.kernel.org/linux-fsdevel/20250305-work-pidfs-kill_on_last_close-v3-0-c8c3d8361705@kernel.org/T/ + let mut pidfd_info: libc::pidfd_info = unsafe { crate::mem::zeroed() }; + pidfd_info.mask = libc::PIDFD_INFO_EXIT as u64; + cvt(unsafe { libc::ioctl(self.0.as_raw_fd(), libc::PIDFD_GET_INFO, &mut pidfd_info) })?; + Ok(ExitStatus::new(pidfd_info.exit_code)) + } + + fn waitid(&self, options: libc::c_int) -> io::Result> { + let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; + let r = cvt(unsafe { + libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, options) + }); + match r { + Err(waitid_err) if waitid_err.raw_os_error() == Some(libc::ECHILD) => { + // already reaped + match self.exit_for_reaped_child() { + Ok(exit_status) => return Ok(Some(exit_status)), + Err(_) => return Err(waitid_err), + } + } + Err(e) => return Err(e), + Ok(_) => {} + } + if unsafe { siginfo.si_pid() } == 0 { + Ok(None) + } else { + Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) + } + } + pub(crate) fn send_signal(&self, signal: i32) -> io::Result<()> { cvt(unsafe { libc::syscall( @@ -29,29 +96,15 @@ impl PidFd { } pub fn wait(&self) -> io::Result { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - cvt(unsafe { - libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) - })?; - Ok(ExitStatus::from_waitid_siginfo(siginfo)) + let r = self.waitid(libc::WEXITED)?; + match r { + Some(exit_status) => Ok(exit_status), + None => unreachable!("waitid with WEXITED should not return None"), + } } pub fn try_wait(&self) -> io::Result> { - let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() }; - - cvt(unsafe { - libc::waitid( - libc::P_PIDFD, - self.0.as_raw_fd() as u32, - &mut siginfo, - libc::WEXITED | libc::WNOHANG, - ) - })?; - if unsafe { siginfo.si_pid() } == 0 { - Ok(None) - } else { - Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) - } + self.waitid(libc::WEXITED | libc::WNOHANG) } } @@ -78,3 +131,9 @@ impl FromRawFd for PidFd { Self(FileDesc::from_raw_fd(fd)) } } + +impl IntoRawFd for PidFd { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} diff --git a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs index 17b06bea9127..a3bb5d5d64ba 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd/tests.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd/tests.rs @@ -1,8 +1,11 @@ +use super::PidFd as InternalPidFd; use crate::assert_matches::assert_matches; -use crate::os::fd::{AsRawFd, RawFd}; +use crate::io::ErrorKind; +use crate::os::fd::AsRawFd; use crate::os::linux::process::{ChildExt, CommandExt as _}; use crate::os::unix::process::{CommandExt as _, ExitStatusExt}; use crate::process::Command; +use crate::sys::AsInner; #[test] fn test_command_pidfd() { @@ -48,11 +51,22 @@ fn test_command_pidfd() { let mut cmd = Command::new("false"); let mut child = unsafe { cmd.pre_exec(|| Ok(())) }.create_pidfd(true).spawn().unwrap(); - assert!(child.id() > 0 && child.id() < -1i32 as u32); + let id = child.id(); + + assert!(id > 0 && id < -1i32 as u32, "spawning with pidfd still returns a sane pid"); if pidfd_open_available { assert!(child.pidfd().is_ok()) } + + if let Ok(pidfd) = child.pidfd() { + match pidfd.as_inner().pid() { + Ok(pid) => assert_eq!(pid, id), + Err(e) if e.kind() == ErrorKind::InvalidInput => { /* older kernel */ } + Err(e) => panic!("unexpected error getting pid from pidfd: {}", e), + } + } + child.wait().expect("error waiting on child"); } @@ -77,9 +91,15 @@ fn test_pidfd() { assert_eq!(status.signal(), Some(libc::SIGKILL)); // Trying to wait again for a reaped child is safe since there's no pid-recycling race. - // But doing so will return an error. + // But doing so may return an error. let res = fd.wait(); - assert_matches!(res, Err(e) if e.raw_os_error() == Some(libc::ECHILD)); + match res { + // older kernels + Err(e) if e.raw_os_error() == Some(libc::ECHILD) => {} + // 6.15+ + Ok(exit) if exit.signal() == Some(libc::SIGKILL) => {} + other => panic!("expected ECHILD error, got {:?}", other), + } // Ditto for additional attempts to kill an already-dead child. let res = fd.kill(); @@ -87,13 +107,5 @@ fn test_pidfd() { } fn probe_pidfd_support() -> bool { - // pidfds require the pidfd_open syscall - let our_pid = crate::process::id(); - let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) }; - if pidfd >= 0 { - unsafe { libc::close(pidfd as RawFd) }; - true - } else { - false - } + InternalPidFd::current_process().is_ok() } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 5ba57e11679c..df64a1716d52 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -482,10 +482,6 @@ impl Command { ) -> libc::c_int; ); - weak!( - fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int; - ); - static PIDFD_SUPPORTED: Atomic = AtomicU8::new(0); const UNKNOWN: u8 = 0; const SPAWN: u8 = 1; @@ -502,24 +498,26 @@ impl Command { } if support == UNKNOWN { support = NO; - let our_pid = crate::process::id(); - let pidfd = cvt(unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) } as c_int); - match pidfd { + + match PidFd::current_process() { Ok(pidfd) => { + // if pidfd_open works then we at least know the fork path is available. support = FORK_EXEC; - if let Some(Ok(pid)) = pidfd_getpid.get().map(|f| cvt(unsafe { f(pidfd) } as i32)) { - if pidfd_spawnp.get().is_some() && pid as u32 == our_pid { - support = SPAWN - } + // but for the fast path we need both spawnp and the + // pidfd -> pid conversion to work. + if pidfd_spawnp.get().is_some() && let Ok(pid) = pidfd.pid() { + assert_eq!(pid, crate::process::id(), "sanity check"); + support = SPAWN; } - unsafe { libc::close(pidfd) }; } Err(e) if e.raw_os_error() == Some(libc::EMFILE) => { - // We're temporarily(?) out of file descriptors. In this case obtaining a pidfd would also fail + // We're temporarily(?) out of file descriptors. In this case pidfd_spawnp would also fail // Don't update the support flag so we can probe again later. return Err(e) } - _ => {} + _ => { + // pidfd_open not available? likely an old kernel without pidfd support. + } } PIDFD_SUPPORTED.store(support, Ordering::Relaxed); if support == FORK_EXEC { @@ -791,13 +789,17 @@ impl Command { } spawn_res?; - let pid = match cvt(pidfd_getpid.get().unwrap()(pidfd)) { + use crate::os::fd::{FromRawFd, IntoRawFd}; + + let pidfd = PidFd::from_raw_fd(pidfd); + let pid = match pidfd.pid() { Ok(pid) => pid, Err(e) => { // The child has been spawned and we are holding its pidfd. - // But we cannot obtain its pid even though pidfd_getpid support was verified earlier. - // This might happen if libc can't open procfs because the file descriptor limit has been reached. - libc::close(pidfd); + // But we cannot obtain its pid even though pidfd_spawnp and getpid support + // was verified earlier. + // This is quite unlikely, but might happen if the ioctl is not supported, + // glibc tries to use procfs and we're out of file descriptors. return Err(Error::new( e.kind(), "pidfd_spawnp succeeded but the child's PID could not be obtained", @@ -805,7 +807,7 @@ impl Command { } }; - return Ok(Some(Process::new(pid, pidfd))); + return Ok(Some(Process::new(pid as i32, pidfd.into_raw_fd()))); } // Safety: -1 indicates we don't have a pidfd. From b0a581d51d7656379bd26c2e6c3c28db73ff97ce Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 6 Jan 2026 09:19:03 +0900 Subject: [PATCH 159/340] rename the `lower_ty` and `lower_ty_direct` to `lower_ty_and_alloc` and `lower_ty` --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 17 ++++---- compiler/rustc_ast_lowering/src/item.rs | 51 ++++++++++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 38 +++++++++--------- compiler/rustc_ast_lowering/src/path.rs | 15 +++---- 5 files changed, 70 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 5bfe63008516..cf3f331a701b 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Let statements are allowed to have impl trait in bindings. let super_ = l.super_.map(|span| self.lower_span(span)); let ty = l.ty.as_ref().map(|t| { - self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) + self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) }); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0502fd2873e9..9fbfeb7a11e6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -158,14 +158,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ohs) => { @@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt), ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf( - self.lower_ty( + self.lower_ty_alloc( container, ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), ), @@ -371,7 +371,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *kind, self.lower_expr(expr), ty.as_ref().map(|ty| { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + self.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Cast), + ) }), ), @@ -617,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); if let Some(ty) = opt_ty { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); + let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)); let block_expr = self.arena.alloc(self.expr_block(whole_block)); hir::ExprKind::Type(block_expr, ty) } else { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bfce7c25b75d..f8b98a5ece40 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -264,8 +264,8 @@ impl<'hir> LoweringContext<'_, 'hir> { define_opaque, }) => { let ident = self.lower_ident(*ident); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let body_id = self.lower_const_body(span, e.as_deref()); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(*m, ident, ty, body_id) @@ -279,8 +279,10 @@ impl<'hir> LoweringContext<'_, 'hir> { id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span); (ty, rhs) }, @@ -379,7 +381,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty( + Some(ty) => this.lower_ty_alloc( ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { @@ -453,7 +455,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .as_deref() .map(|of_trait| this.lower_trait_impl_header(of_trait)); - let lowered_ty = this.lower_ty( + let lowered_ty = this.lower_ty_alloc( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), ); @@ -758,8 +760,8 @@ impl<'hir> LoweringContext<'_, 'hir> { safety, define_opaque, }) => { - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); if define_opaque.is_some() { self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); @@ -870,7 +872,8 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, (index, f): (usize, &FieldDef), ) -> hir::FieldDef<'hir> { - let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); + let ty = + self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); hir::FieldDef { @@ -908,8 +911,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = rhs .as_ref() .map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span)); @@ -1008,7 +1013,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { - this.lower_ty( + this.lower_ty_alloc( x, ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), ) @@ -1120,8 +1125,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); this.lower_define_opaque(hir_id, &define_opaque); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span); hir::ImplItemKind::Const(ty, rhs) @@ -1180,7 +1187,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty( + let ty = this.lower_ty_alloc( ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { @@ -1916,7 +1923,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bound_generic_params, hir::GenericParamSource::Binder, ), - bounded_ty: self.lower_ty( + bounded_ty: self.lower_ty_alloc( bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), @@ -1945,10 +1952,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate { - lhs_ty: self - .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - rhs_ty: self - .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + lhs_ty: self.lower_ty_alloc( + lhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), + rhs_ty: self.lower_ty_alloc( + rhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), }) } }); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9a459156aba1..0d1388a2441d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1125,7 +1125,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match &constraint.kind { AssocItemConstraintKind::Equality { term } => { let term = match term { - Term::Ty(ty) => self.lower_ty(ty, itctx).into(), + Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(), Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), }; hir::AssocItemConstraintKind::Equality { term } @@ -1250,7 +1250,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } _ => {} } - GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap()) + GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } ast::GenericArg::Const(ct) => { GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) @@ -1259,8 +1259,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { - self.arena.alloc(self.lower_ty_direct(t, itctx)) + fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { + self.arena.alloc(self.lower_ty(t, itctx)) } fn lower_path_ty( @@ -1324,11 +1324,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer(()), TyKind::Err(guar) => hir::TyKind::Err(*guar), - TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), + TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { let lifetime = self.lower_ty_direct_lifetime(t, *region); @@ -1362,15 +1362,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { generic_params, - inner_ty: self.lower_ty(&f.inner_ty, itctx), + inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx), })) } TyKind::Never => hir::TyKind::Never, TyKind::Tup(tys) => hir::TyKind::Tup( - self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), + self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))), ), TyKind::Paren(ty) => { - return self.lower_ty_direct(ty, itctx); + return self.lower_ty(ty, itctx); } TyKind::Path(qself, path) => { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); @@ -1393,7 +1393,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ty, length) => hir::TyKind::Array( - self.lower_ty(ty, itctx), + self.lower_ty_alloc(ty, itctx), self.lower_array_length_to_const_arg(length), ), TyKind::TraitObject(bounds, kind) => { @@ -1493,7 +1493,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } TyKind::Pat(ty, pat) => { - hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span)) + hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span)) } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") @@ -1693,7 +1693,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) } }; - self.lower_ty_direct(¶m.ty, itctx) + self.lower_ty(¶m.ty, itctx) })); let output = match coro { @@ -1732,7 +1732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } }; - hir::FnRetTy::Return(self.lower_ty(ty, itctx)) + hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, @@ -1843,7 +1843,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - self.lower_ty(ty, itctx) + self.lower_ty_alloc(ty, itctx) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -2036,7 +2036,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }) .map(|def| { - self.lower_ty( + self.lower_ty_alloc( def, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), ) @@ -2047,8 +2047,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, span: _, default } => { - let ty = self - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); + let ty = self.lower_ty_alloc( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + ); // Not only do we deny const param defaults in binders but we also map them to `None` // since later compiler stages cannot handle them (and shouldn't need to be able to). @@ -2198,7 +2200,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { - hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } + hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl } } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 3322e0fb66b4..bfb42efb684f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let qself = qself .as_ref() // Reject cases like `::Assoc` and `::Assoc`. - .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); + .map(|q| { + self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)) + }); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -510,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) })); let output_ty = match output { // Only allow `impl Trait` in return position. i.e.: @@ -520,9 +522,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { if self.tcx.features().impl_trait_in_fn_trait_return() { - self.lower_ty(ty, itctx) + self.lower_ty_alloc(ty, itctx) } else { - self.lower_ty( + self.lower_ty_alloc( ty, ImplTraitContext::FeatureGated( ImplTraitPosition::FnTraitReturn, @@ -531,9 +533,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } } - FnRetTy::Ty(ty) => { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) - } + FnRetTy::Ty(ty) => self + .lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type( From 56cb5d598bc4b0e3b106752720feb3934316bfb5 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 6 Jan 2026 09:24:41 +0900 Subject: [PATCH 160/340] rename the `lower_anon_const_to_const_arg` and `lower_anon_const_to_const_arg_direct` to `lower_anon_const_to_const_arg_and_alloc` and `lower_anon_const_to_const_arg` --- compiler/rustc_ast_lowering/src/lib.rs | 27 ++++++++++++++------------ compiler/rustc_ast_lowering/src/pat.rs | 18 +++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0d1388a2441d..e11e24c0263f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1126,7 +1126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AssocItemConstraintKind::Equality { term } => { let term = match term { Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(), - Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), + Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(), }; hir::AssocItemConstraintKind::Equality { term } } @@ -1252,9 +1252,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap()) } - ast::GenericArg::Const(ct) => { - GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) - } + ast::GenericArg::Const(ct) => GenericArg::Const( + self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(), + ), } } @@ -2066,7 +2066,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { false } }) - .map(|def| self.lower_anon_const_to_const_arg(def)); + .map(|def| self.lower_anon_const_to_const_arg_and_alloc(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2288,7 +2288,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ()); self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind }) } - _ => self.lower_anon_const_to_const_arg(c), + _ => self.lower_anon_const_to_const_arg_and_alloc(c), } } @@ -2367,7 +2367,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::ConstItemRhs<'hir> { match rhs { Some(ConstItemRhs::TypeConst(anon)) => { - hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon)) + hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon)) } None if attr::contains_name(attrs, sym::type_const) => { let const_arg = ConstArg { @@ -2414,7 +2414,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_id = self.local_def_id(anon_const.id); let def_kind = self.tcx.def_kind(def_id); assert_eq!(DefKind::AnonConst, def_kind); - self.lower_anon_const_to_const_arg_direct(anon_const) + self.lower_anon_const_to_const_arg(anon_const) } else { self.lower_expr_to_const_arg_direct(arg) }; @@ -2467,7 +2467,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_kind = self.tcx.def_kind(def_id); assert_eq!(DefKind::AnonConst, def_kind); - self.lower_anon_const_to_const_arg_direct(anon_const) + self.lower_anon_const_to_const_arg(anon_const) } else { self.lower_expr_to_const_arg_direct(&f.expr) }; @@ -2508,12 +2508,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// 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> { - self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon)) + fn lower_anon_const_to_const_arg_and_alloc( + &mut self, + anon: &AnonConst, + ) -> &'hir hir::ConstArg<'hir> { + self.arena.alloc(self.lower_anon_const_to_const_arg(anon)) } #[instrument(level = "debug", skip(self))] - fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { let tcx = self.tcx; // We cannot change parsing depending on feature gates available, diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 7a5d8d9847a1..f09bbb9c4972 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let pat_hir_id = self.lower_node_id(pattern.id); let node = match &pattern.kind { TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range( - e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| { - self.lower_ty_pat_range_end( - hir::LangItem::RangeMin, - span.shrink_to_lo(), - base_type, - ) - }), + e1.as_deref() + .map(|e| self.lower_anon_const_to_const_arg_and_alloc(e)) + .unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMin, + span.shrink_to_lo(), + base_type, + ) + }), e2.as_deref() .map(|e| match end { - RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e), + RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e), RangeEnd::Excluded => self.lower_excluded_range_end(e), }) .unwrap_or_else(|| { From e603055d89063ee3fea237f34deccbf333a6e91a Mon Sep 17 00:00:00 2001 From: delta17920 Date: Mon, 5 Jan 2026 16:20:36 +0000 Subject: [PATCH 161/340] Fix ICE when transmute Assume field is invalid --- compiler/rustc_transmute/src/lib.rs | 10 +++--- .../non_scalar_alignment_value.rs | 30 ++++++++++++++++ .../non_scalar_alignment_value.stderr | 35 +++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 tests/ui/transmutability/non_scalar_alignment_value.rs create mode 100644 tests/ui/transmutability/non_scalar_alignment_value.stderr diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 58cb2eb6556e..08ae561c972c 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -155,14 +155,14 @@ mod rustc { .enumerate() .find(|(_, field_def)| name == field_def.name) .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); - fields[field_idx].to_leaf() == ScalarInt::TRUE + fields[field_idx].try_to_leaf().map(|leaf| leaf == ScalarInt::TRUE) }; Some(Self { - alignment: get_field(sym::alignment), - lifetimes: get_field(sym::lifetimes), - safety: get_field(sym::safety), - validity: get_field(sym::validity), + alignment: get_field(sym::alignment)?, + lifetimes: get_field(sym::lifetimes)?, + safety: get_field(sym::safety)?, + validity: get_field(sym::validity)?, }) } } diff --git a/tests/ui/transmutability/non_scalar_alignment_value.rs b/tests/ui/transmutability/non_scalar_alignment_value.rs new file mode 100644 index 000000000000..45c9e61fcfe2 --- /dev/null +++ b/tests/ui/transmutability/non_scalar_alignment_value.rs @@ -0,0 +1,30 @@ +#![feature(min_generic_const_args)] +//~^ WARN the feature `min_generic_const_args` is incomplete + +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, TransmuteFrom}; + struct Dst {} + fn is_maybe_transmutable() + where + Dst: TransmuteFrom< + (), + { + Assume { + alignment: Assume {}, + //~^ ERROR struct expression with missing field initialiser for `alignment` + //~| ERROR struct expression with missing field initialiser for `lifetimes` + //~| ERROR struct expression with missing field initialiser for `safety` + //~| ERROR struct expression with missing field initialiser for `validity` + lifetimes: const { true }, + safety: const { true }, + validity: const { true }, + } + }, + >, + { + } +} + +fn main() {} diff --git a/tests/ui/transmutability/non_scalar_alignment_value.stderr b/tests/ui/transmutability/non_scalar_alignment_value.stderr new file mode 100644 index 000000000000..06487dea82e0 --- /dev/null +++ b/tests/ui/transmutability/non_scalar_alignment_value.stderr @@ -0,0 +1,35 @@ +warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/non_scalar_alignment_value.rs:1:12 + | +LL | #![feature(min_generic_const_args)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: struct expression with missing field initialiser for `alignment` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `lifetimes` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `safety` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: struct expression with missing field initialiser for `validity` + --> $DIR/non_scalar_alignment_value.rs:15:32 + | +LL | alignment: Assume {}, + | ^^^^^^ + +error: aborting due to 4 previous errors; 1 warning emitted + From dd948f96f30af19cf2cb7041de577ee1bf29bb9f Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 6 Jan 2026 09:42:42 +0800 Subject: [PATCH 162/340] Thread `--jobs` from `bootstrap` -> `compiletest` -> `run-make-support` --- src/bootstrap/src/core/build_steps/test.rs | 2 ++ src/tools/compiletest/src/common.rs | 5 +++++ src/tools/compiletest/src/directives/tests.rs | 1 + src/tools/compiletest/src/lib.rs | 10 +++++++++- src/tools/compiletest/src/runtest/run_make.rs | 3 +++ src/tools/compiletest/src/rustdoc_gui_test.rs | 1 + src/tools/run-make-support/src/env.rs | 14 ++++++++++++++ tests/run-make/compiletest-self-test/jobs/rmake.rs | 5 +++++ 8 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/compiletest-self-test/jobs/rmake.rs diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a3c13fc4b095..4008ede6c0d4 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2265,6 +2265,8 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--with-std-remap-debuginfo"); } + cmd.arg("--jobs").arg(builder.jobs().to_string()); + let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled(test_compiler.host) { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5563abe92a80..800ce4f3088e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -715,6 +715,11 @@ pub struct Config { pub override_codegen_backend: Option, /// Whether to ignore `//@ ignore-backends`. pub bypass_ignore_backends: bool, + + /// Number of parallel jobs configured for the build. + /// + /// This is forwarded from bootstrap's `jobs` configuration. + pub jobs: u32, } impl Config { diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 0d3777b8e60c..71343080cfa2 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -225,6 +225,7 @@ impl ConfigBuilder { "--nightly-branch=", "--git-merge-commit-email=", "--minicore-path=", + "--jobs=0", ]; let mut args: Vec = args.iter().map(ToString::to_string).collect(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a64c7850aad4..997f570393f2 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -218,7 +218,8 @@ fn parse_config(args: Vec) -> Config { "the codegen backend to use instead of the default one", "CODEGEN BACKEND [NAME | PATH]", ) - .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives"); + .optflag("", "bypass-ignore-backends", "ignore `//@ ignore-backends` directives") + .reqopt("", "jobs", "number of parallel jobs bootstrap was configured with", "JOBS"); let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -363,6 +364,11 @@ fn parse_config(args: Vec) -> Config { let build_test_suite_root = opt_path(matches, "build-test-suite-root"); assert!(build_test_suite_root.starts_with(&build_root)); + let jobs = match matches.opt_str("jobs") { + Some(jobs) => jobs.parse::().expect("expected `--jobs` to be an `u32`"), + None => panic!("`--jobs` is required"), + }; + Config { bless: matches.opt_present("bless"), fail_fast: matches.opt_present("fail-fast") @@ -481,6 +487,8 @@ fn parse_config(args: Vec) -> Config { default_codegen_backend, override_codegen_backend, bypass_ignore_backends: matches.opt_present("bypass-ignore-backends"), + + jobs, } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index ba3a12347367..4eb8f91fe894 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -249,6 +249,9 @@ impl TestCx<'_> { cmd.env("__STD_REMAP_DEBUGINFO_ENABLED", "1"); } + // Used for `run_make_support::env::jobs`. + cmd.env("__BOOTSTRAP_JOBS", self.config.jobs.to_string()); + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4454ffb1f59e..06b66ef9fd0a 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -139,5 +139,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, bypass_ignore_backends: Default::default(), + jobs: Default::default(), } } diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index 507d51471df0..65b6d3db85d5 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -49,3 +49,17 @@ pub fn set_current_dir>(dir: P) { std::env::set_current_dir(dir.as_ref()) .expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display())); } + +/// Number of parallel jobs bootstrap was configured with. +/// +/// This may fallback to [`std::thread::available_parallelism`] when no explicit jobs count has been +/// configured. Refer to bootstrap's jobs fallback logic. +#[track_caller] +pub fn jobs() -> u32 { + std::env::var_os("__BOOTSTRAP_JOBS") + .expect("`__BOOTSTRAP_JOBS` must be set by `compiletest`") + .to_str() + .expect("`__BOOTSTRAP_JOBS` must be a valid string") + .parse::() + .expect("`__BOOTSTRAP_JOBS` must be a valid `u32`") +} diff --git a/tests/run-make/compiletest-self-test/jobs/rmake.rs b/tests/run-make/compiletest-self-test/jobs/rmake.rs new file mode 100644 index 000000000000..d21b44ada1c3 --- /dev/null +++ b/tests/run-make/compiletest-self-test/jobs/rmake.rs @@ -0,0 +1,5 @@ +//! Very basic smoke test to make sure `run_make_support::env::jobs` at least does not panic. + +fn main() { + println!("{}", run_make_support::env::jobs()); +} From 03fb7eecedf37b28a1feab1383c917d9e91dfaef Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:54:15 +0100 Subject: [PATCH 163/340] Create a `rustc_ast` representation for parsed attributes --- compiler/rustc_ast/src/ast.rs | 45 ++++++++++++++++++- compiler/rustc_ast/src/attr/mod.rs | 33 +++++++++++--- compiler/rustc_ast/src/visit.rs | 2 + compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 10 ++--- compiler/rustc_attr_parsing/src/parser.rs | 4 +- .../rustc_attr_parsing/src/validate_attr.rs | 4 +- compiler/rustc_builtin_macros/src/autodiff.rs | 14 +++--- .../src/deriving/generic/mod.rs | 41 +++++++++-------- compiler/rustc_expand/src/expand.rs | 4 +- compiler/rustc_parse/src/parser/attr.rs | 4 +- 11 files changed, 115 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7c922417ee29..571e840795b5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan}; use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; +use crate::attr::data_structures::CfgEntry; pub use crate::format::*; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; @@ -3390,7 +3391,7 @@ impl NormalAttr { item: AttrItem { unsafety: Safety::Default, path: Path::from_ident(ident), - args: AttrArgs::Empty, + args: AttrItemKind::Unparsed(AttrArgs::Empty), tokens: None, }, tokens: None, @@ -3402,11 +3403,51 @@ impl NormalAttr { pub struct AttrItem { pub unsafety: Safety, pub path: Path, - pub args: AttrArgs, + pub args: AttrItemKind, // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. pub tokens: Option, } +/// Some attributes are stored in a parsed form, for performance reasons. +/// Their arguments don't have to be reparsed everytime they're used +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum AttrItemKind { + Parsed(EarlyParsedAttribute), + Unparsed(AttrArgs), +} + +impl AttrItemKind { + pub fn unparsed(self) -> Option { + match self { + AttrItemKind::Unparsed(args) => Some(args), + AttrItemKind::Parsed(_) => None, + } + } + + pub fn unparsed_ref(&self) -> Option<&AttrArgs> { + match self { + AttrItemKind::Unparsed(args) => Some(args), + AttrItemKind::Parsed(_) => None, + } + } + + pub fn span(&self) -> Option { + match self { + AttrItemKind::Unparsed(args) => args.span(), + AttrItemKind::Parsed(_) => None, + } + } +} + +/// Some attributes are stored in parsed form in the AST. +/// This is done for performance reasons, so the attributes don't need to be reparsed on every use. +/// +/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline. +/// When adding new early parsed attributes, consider whether they should be pretty printed. +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] +pub enum EarlyParsedAttribute { +} + impl AttrItem { pub fn is_valid_for_outer_style(&self) -> bool { self.path == sym::cfg_attr diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index c0ed6e24e222..6ecba865c815 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,5 +1,8 @@ //! Functions dealing with attributes and meta items. +pub mod data_structures; +pub mod version; + use std::fmt::Debug; use std::sync::atomic::{AtomicU32, Ordering}; @@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; +use crate::AttrItemKind; use crate::ast::{ AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path, @@ -62,6 +66,15 @@ impl Attribute { } } + /// Replaces the arguments of this attribute with new arguments `AttrItemKind`. + /// This is useful for making this attribute into a trace attribute, and should otherwise be avoided. + pub fn replace_args(&mut self, new_args: AttrItemKind) { + match &mut self.kind { + AttrKind::Normal(normal) => normal.item.args = new_args, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { AttrKind::Normal(normal) => normal.item, @@ -77,7 +90,7 @@ impl AttributeExt for Attribute { fn value_span(&self) -> Option { match &self.kind { - AttrKind::Normal(normal) => match &normal.item.args { + AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => Some(expr.span), _ => None, }, @@ -147,7 +160,7 @@ impl AttributeExt for Attribute { fn is_word(&self) -> bool { if let AttrKind::Normal(normal) = &self.kind { - matches!(normal.item.args, AttrArgs::Empty) + matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty)) } else { false } @@ -303,7 +316,7 @@ impl AttrItem { } pub fn meta_item_list(&self) -> Option> { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { MetaItemKind::list_from_tokens(args.tokens.clone()) } @@ -324,7 +337,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_str(&self) -> Option { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => match expr.kind { ExprKind::Lit(token_lit) => { LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str()) @@ -348,7 +361,7 @@ impl AttrItem { /// #[attr("value")] /// ``` fn value_span(&self) -> Option { - match &self.args { + match &self.args.unparsed_ref()? { AttrArgs::Eq { expr, .. } => Some(expr.span), AttrArgs::Delimited(_) | AttrArgs::Empty => None, } @@ -364,7 +377,7 @@ impl AttrItem { } pub fn meta_kind(&self) -> Option { - MetaItemKind::from_attr_args(&self.args) + MetaItemKind::from_attr_args(self.args.unparsed_ref()?) } } @@ -699,7 +712,13 @@ fn mk_attr( args: AttrArgs, span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) + mk_attr_from_item( + g, + AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None }, + None, + style, + span, + ) } pub fn mk_attr_from_item( diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d122adfdf966..83b751fbde90 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers { crate::token::LitKind, crate::tokenstream::LazyAttrTokenStream, crate::tokenstream::TokenStream, + EarlyParsedAttribute, Movability, Mutability, Pinnedness, @@ -457,6 +458,7 @@ macro_rules! common_visitor_and_walkers { ModSpans, MutTy, NormalAttr, + AttrItemKind, Parens, ParenthesizedArgs, PatFieldsRest, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1aa08dfd3d5e..0cf0eae821e9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } ast::Safety::Default | ast::Safety::Safe(_) => {} } - match &item.args { + match &item.args.unparsed_ref().expect("Parsed attributes are never printed") { AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common( Some(MacHeader::Path(&item.path)), false, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 66f0f8d391f6..ccf0a394afd0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -294,11 +294,9 @@ pub fn parse_cfg_attr( sess: &Session, features: Option<&Features>, ) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> { - match cfg_attr.get_normal_item().args { - ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) - if !tokens.is_empty() => - { - check_cfg_attr_bad_delim(&sess.psess, dspan, delim); + match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() { + ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => { + check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim); match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { parse_cfg_attr_internal(p, sess, features, cfg_attr) }) { @@ -322,7 +320,7 @@ pub fn parse_cfg_attr( } _ => { let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = - cfg_attr.get_normal_item().args + cfg_attr.get_normal_item().args.unparsed_ref()? { (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) } else { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 39419dfa4ed8..d79579fdf0b7 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -122,10 +122,10 @@ impl ArgParser { } if args.delim != Delimiter::Parenthesis { - psess.dcx().emit_err(MetaBadDelim { + should_emit.emit_err(psess.dcx().create_err(MetaBadDelim { span: args.dspan.entire(), sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close }, - }); + })); return None; } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 4879646a1107..f56e85b11061 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { } _ => { let attr_item = attr.get_normal_item(); - if let AttrArgs::Eq { .. } = attr_item.args { + if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { Ok(_) => {} @@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met unsafety: item.unsafety, span: attr.span, path: item.path.clone(), - kind: match &item.args { + kind: match &item.args.unparsed_ref().unwrap() { AttrArgs::Empty => MetaItemKind::Word, AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => { check_meta_bad_delim(psess, *dspan, *delim); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 39abb66df30c..95191b82ff3f 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -358,7 +358,7 @@ mod llvm_enzyme { let inline_item = ast::AttrItem { unsafety: ast::Safety::Default, path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)), - args: ast::AttrArgs::Delimited(never_arg), + args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)), tokens: None, }; let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None }); @@ -421,11 +421,13 @@ mod llvm_enzyme { } }; // Now update for d_fn - rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs { - dspan: DelimSpan::dummy(), - delim: rustc_ast::token::Delimiter::Parenthesis, - tokens: ts, - }); + rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed( + rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs { + dspan: DelimSpan::dummy(), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: ts, + }), + ); let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index bb6557802ece..7c84530abbee 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> { rustc_ast::AttrItem { unsafety: Safety::Default, path: rustc_const_unstable, - args: AttrArgs::Delimited(DelimArgs { - dspan: DelimSpan::from_single(self.span), - delim: rustc_ast::token::Delimiter::Parenthesis, - tokens: [ - TokenKind::Ident(sym::feature, IdentIsRaw::No), - TokenKind::Eq, - TokenKind::lit(LitKind::Str, sym::derive_const, None), - TokenKind::Comma, - TokenKind::Ident(sym::issue, IdentIsRaw::No), - TokenKind::Eq, - TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), - ] - .into_iter() - .map(|kind| { - TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone) - }) - .collect(), - }), + args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited( + DelimArgs { + dspan: DelimSpan::from_single(self.span), + delim: rustc_ast::token::Delimiter::Parenthesis, + tokens: [ + TokenKind::Ident(sym::feature, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const, None), + TokenKind::Comma, + TokenKind::Ident(sym::issue, IdentIsRaw::No), + TokenKind::Eq, + TokenKind::lit(LitKind::Str, sym::derive_const_issue, None), + ] + .into_iter() + .map(|kind| { + TokenTree::Token( + Token { kind, span: self.span }, + Spacing::Alone, + ) + }) + .collect(), + }, + )), tokens: None, }, self.span, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 52b7339e0140..8102f8e6dac7 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -813,10 +813,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let attr_item = attr.get_normal_item(); let safety = attr_item.unsafety; - if let AttrArgs::Eq { .. } = attr_item.args { + if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } - let inner_tokens = attr_item.args.inner_tokens(); + let inner_tokens = attr_item.args.unparsed_ref().unwrap().inner_tokens(); match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 63109c7ba5cb..1cb9a1b65d65 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::token::{self, MetaVarKind}; use rustc_ast::tokenstream::ParserRange; -use rustc_ast::{Attribute, attr}; +use rustc_ast::{AttrItemKind, Attribute, attr}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult}; use rustc_span::{BytePos, Span}; @@ -313,7 +313,7 @@ impl<'a> Parser<'a> { this.expect(exp!(CloseParen))?; } Ok(( - ast::AttrItem { unsafety, path, args, tokens: None }, + ast::AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None }, Trailing::No, UsePreAttrPos::No, )) From 5590fc034c2c965f20844841e9e2a7382b25a0fb Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:56:42 +0100 Subject: [PATCH 164/340] Make `cfg` and `cfg_attr` trace attributes into early parsed attributes --- compiler/rustc_ast/src/ast.rs | 2 + .../rustc_ast/src/attr/data_structures.rs | 101 ++++++++++++++++++ .../src => rustc_ast/src/attr}/version.rs | 16 +-- .../rustc_attr_parsing/src/early_parsed.rs | 53 +++++++++ compiler/rustc_attr_parsing/src/interface.rs | 44 +++++--- compiler/rustc_attr_parsing/src/lib.rs | 1 + compiler/rustc_attr_parsing/src/safety.rs | 7 +- compiler/rustc_expand/src/config.rs | 8 +- compiler/rustc_expand/src/expand.rs | 57 ++++++---- .../rustc_hir/src/attrs/data_structures.rs | 85 ++------------- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 + .../rustc_hir/src/attrs/pretty_printing.rs | 4 + compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/lib.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 6 +- 15 files changed, 247 insertions(+), 143 deletions(-) create mode 100644 compiler/rustc_ast/src/attr/data_structures.rs rename compiler/{rustc_hir/src => rustc_ast/src/attr}/version.rs (75%) create mode 100644 compiler/rustc_attr_parsing/src/early_parsed.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 571e840795b5..d4407dbf7be7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3446,6 +3446,8 @@ impl AttrItemKind { /// When adding new early parsed attributes, consider whether they should be pretty printed. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum EarlyParsedAttribute { + CfgTrace(CfgEntry), + CfgAttrTrace, } impl AttrItem { diff --git a/compiler/rustc_ast/src/attr/data_structures.rs b/compiler/rustc_ast/src/attr/data_structures.rs new file mode 100644 index 000000000000..2eab91801cd6 --- /dev/null +++ b/compiler/rustc_ast/src/attr/data_structures.rs @@ -0,0 +1,101 @@ +use std::fmt; + +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::{Span, Symbol}; +use thin_vec::ThinVec; + +use crate::attr::version::RustcVersion; + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)] +pub enum CfgEntry { + All(ThinVec, Span), + Any(ThinVec, Span), + Not(Box, Span), + Bool(bool, Span), + NameValue { name: Symbol, value: Option, span: Span }, + Version(Option, Span), +} + +impl CfgEntry { + pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) { + match self { + CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => { + *span = lower_span(*span); + subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span)); + } + CfgEntry::Not(sub, span) => { + *span = lower_span(*span); + sub.lower_spans(lower_span); + } + CfgEntry::Bool(_, span) + | CfgEntry::NameValue { span, .. } + | CfgEntry::Version(_, span) => { + *span = lower_span(*span); + } + } + } + + pub fn span(&self) -> Span { + 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 && value1 == value2, + (Self::Version(a, _), Self::Version(b, _)) => a == b, + _ => false, + } + } +} + +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(()), + }, + } + } +} diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_ast/src/attr/version.rs similarity index 75% rename from compiler/rustc_hir/src/version.rs rename to compiler/rustc_ast/src/attr/version.rs index 03182088d4c0..59deee40ae28 100644 --- a/compiler/rustc_hir/src/version.rs +++ b/compiler/rustc_ast/src/attr/version.rs @@ -1,16 +1,10 @@ -use std::borrow::Cow; use std::fmt::{self, Display}; use std::sync::OnceLock; -use rustc_error_messages::{DiagArgValue, IntoDiagArg}; -use rustc_macros::{ - BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, -}; - -use crate::attrs::PrintAttribute; +use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version}; #[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct RustcVersion { pub major: u16, pub minor: u16, @@ -47,9 +41,3 @@ impl Display for RustcVersion { write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) } } - -impl IntoDiagArg for RustcVersion { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string())) - } -} diff --git a/compiler/rustc_attr_parsing/src/early_parsed.rs b/compiler/rustc_attr_parsing/src/early_parsed.rs new file mode 100644 index 000000000000..6a33cb38edf9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/early_parsed.rs @@ -0,0 +1,53 @@ +use rustc_ast::EarlyParsedAttribute; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] = + &[&[sym::cfg_trace], &[sym::cfg_attr_trace]]; + +/// This struct contains the state necessary to convert early parsed attributes to hir attributes +/// The only conversion that really happens here is that multiple early parsed attributes are +/// merged into a single hir attribute, representing their combined state. +/// FIXME: We should make this a nice and extendable system if this is going to be used more often +#[derive(Default)] +pub(crate) struct EarlyParsedState { + /// Attribute state for `#[cfg]` trace attributes + cfg_trace: ThinVec<(CfgEntry, Span)>, + + /// Attribute state for `#[cfg_attr]` trace attributes + /// The arguments of these attributes is no longer relevant for any later passes, only their presence. + /// So we discard the arguments here. + cfg_attr_trace: bool, +} + +impl EarlyParsedState { + pub(crate) fn accept_early_parsed_attribute( + &mut self, + attr_span: Span, + lower_span: impl Copy + Fn(Span) -> Span, + parsed: &EarlyParsedAttribute, + ) { + match parsed { + EarlyParsedAttribute::CfgTrace(cfg) => { + let mut cfg = cfg.clone(); + cfg.lower_spans(lower_span); + self.cfg_trace.push((cfg, attr_span)); + } + EarlyParsedAttribute::CfgAttrTrace => { + self.cfg_attr_trace = true; + } + } + } + + pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec) { + if !self.cfg_trace.is_empty() { + attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace))); + } + if self.cfg_attr_trace { + attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace)); + } + } +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 91596ff0de60..e38fffa6587c 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,7 +2,7 @@ use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; -use rustc_ast::{AttrStyle, NodeId, Safety}; +use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -13,6 +13,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; +use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> { normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); 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)?; + let args = ArgParser::from_attr_args( + &normal_attr.item.args.unparsed_ref().unwrap(), + &parts, + &sess.psess, + emit_errors, + )?; Self::parse_single_args( sess, attr.span, @@ -263,12 +268,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id: S::Id, target: Target, omit_doc: OmitDoc, - lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); + let mut early_parsed_state = EarlyParsedState::default(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -288,6 +293,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { continue; } + let attr_span = lower_span(attr.span); match &attr.kind { ast::AttrKind::DocComment(comment_kind, symbol) => { if omit_doc == OmitDoc::Skip { @@ -297,7 +303,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Sugared(*comment_kind), - span: lower_span(attr.span), + span: attr_span, comment: *symbol, })) } @@ -305,6 +311,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); + let args = match &n.item.args { + AttrItemKind::Unparsed(args) => args, + AttrItemKind::Parsed(parsed) => { + early_parsed_state + .accept_early_parsed_attribute(attr_span, lower_span, parsed); + continue; + } + }; + self.check_attribute_safety( &attr_path, lower_span(n.item.span()), @@ -318,7 +333,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { let Some(args) = ArgParser::from_attr_args( - &n.item.args, + args, &parts, &self.sess.psess, self.stage.should_emit(), @@ -351,7 +366,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Raw(nv.value_span), - span: attr.span, + span: attr_span, comment, })); continue; @@ -365,7 +380,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id, emit_lint: &mut emit_lint, }, - attr_span: lower_span(attr.span), + attr_span, inner_span: lower_span(n.item.span()), attr_style: attr.style, parsed_description: ParsedDescription::Attribute, @@ -396,17 +411,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Unparsed(Box::new(AttrItem { path: attr_path.clone(), - args: self.lower_attr_args(&n.item.args, lower_span), + args: self + .lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, - span: lower_span(attr.span), + span: attr_span, }))); } } } } - let mut parsed_attributes = Vec::new(); + early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &S::parsers().finalizers { if let Some(attr) = f(&mut FinalizeContext { shared: SharedContext { @@ -417,18 +433,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }, all_attrs: &attr_paths, }) { - parsed_attributes.push(Attribute::Parsed(attr)); + attributes.push(Attribute::Parsed(attr)); } } - attributes.extend(parsed_attributes); - attributes } /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().accepters.contains_key(path) + Late::parsers().accepters.contains_key(path) || EARLY_PARSED_ATTRIBUTES.contains(&path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 411b4dd75e66..349e6c234520 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -99,6 +99,7 @@ mod interface; /// like lists or name-value pairs. pub mod parser; +mod early_parsed; mod safety; mod session_diagnostics; mod target_checking; diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 68aeca2bbda9..9fca57f88025 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -4,7 +4,7 @@ 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 rustc_span::Span; use crate::context::Stage; use crate::{AttributeParser, ShouldEmit}; @@ -23,11 +23,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]); - 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)); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 492c845df171..28f711f362bd 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, - NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, + HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ @@ -288,7 +288,9 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { // 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); + let mut trace_attr = cfg_attr.clone(); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace)); + let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 8102f8e6dac7..c130d9f59940 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,12 +7,16 @@ use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID, - ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, - MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, + DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, + ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, + TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr}; +use rustc_attr_parsing::{ + AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry, + parse_cfg, validate_attr, +}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; @@ -2188,21 +2192,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { && !AttributeParser::::is_parsed_attribute(&attr.path()) { let attr_name = attr.name().unwrap(); - // `#[cfg]` and `#[cfg_attr]` are special - they are - // eagerly evaluated. - if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { - self.cx.sess.psess.buffer_lint( - UNUSED_ATTRIBUTES, - attr.span, - self.cx.current_expansion.lint_node_id, - crate::errors::UnusedBuiltinAttribute { - attr_name, - macro_name: pprust::path_to_string(&call.path), - invoc_span: call.path.span, - attr_span: attr.span, - }, - ); - } + self.cx.sess.psess.buffer_lint( + UNUSED_ATTRIBUTES, + attr.span, + self.cx.current_expansion.lint_node_id, + crate::errors::UnusedBuiltinAttribute { + attr_name, + macro_name: pprust::path_to_string(&call.path), + invoc_span: call.path.span, + attr_span: attr.span, + }, + ); } } } @@ -2213,11 +2213,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints); + let Some(cfg) = AttributeParser::parse_single( + self.cfg().sess, + &attr, + attr.span, + self.cfg().lint_node_id, + self.cfg().features, + ShouldEmit::ErrorsAndLints, + parse_cfg, + &CFG_TEMPLATE, + ) else { + // Cfg attribute was not parsable, give up + return EvalConfigResult::True; + }; + + let res = eval_config_entry(self.cfg().sess, &cfg); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. - let trace_attr = attr_into_trace(attr, sym::cfg_trace); + let mut trace_attr = attr_into_trace(attr, sym::cfg_trace); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg))); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index f418c391ece7..fa8998f0546d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; -use std::fmt; use std::path::PathBuf; pub use ReprAttr::*; use rustc_abi::Align; +pub use rustc_ast::attr::data_structures::*; use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrStyle, ast}; use rustc_data_structures::fx::FxIndexMap; @@ -212,83 +212,6 @@ impl StrippedCfgItem { } } -#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] -pub enum CfgEntry { - All(ThinVec, Span), - Any(ThinVec, Span), - Not(Box, Span), - Bool(bool, Span), - NameValue { name: Symbol, value: Option, span: Span }, - Version(Option, Span), -} - -impl CfgEntry { - pub fn span(&self) -> Span { - 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 && value1 == value2, - (Self::Version(a, _), Self::Version(b, _)) => a == b, - _ => false, - } - } -} - -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`. /// @@ -713,6 +636,12 @@ pub enum AttributeKind { span: Span, }, + /// Represents the trace attribute of `#[cfg_attr]` + CfgAttrTrace, + + /// Represents the trace attribute of `#[cfg]` + CfgTrace(ThinVec<(CfgEntry, Span)>), + /// Represents `#[cfi_encoding]` CfiEncoding { encoding: Symbol }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 57d2d6c5875e..3efa876ed6a9 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -26,6 +26,8 @@ impl AttributeKind { AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, + CfgAttrTrace => Yes, + CfgTrace(..) => Yes, CfiEncoding { .. } => Yes, Coinductive(..) => No, Cold(..) => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index f8ac2a547ca8..806f5c4d3ed9 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -2,6 +2,8 @@ use std::num::NonZero; use std::ops::Deref; use rustc_abi::Align; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_ast::attr::version::RustcVersion; use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; @@ -182,4 +184,6 @@ print_debug!( Transparency, SanitizerSet, DefId, + RustcVersion, + CfgEntry, ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..1a9bc8a2781b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1371,6 +1371,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, + Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7c9c15c16df4..fa46c0f085a2 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -33,7 +33,6 @@ pub mod pat_util; mod stability; mod stable_hash_impls; mod target; -mod version; pub mod weak_lang_items; #[cfg(test)] @@ -42,9 +41,9 @@ mod tests; #[doc(no_inline)] pub use hir::*; pub use lang_items::{LangItem, LanguageItems}; +pub use rustc_ast::attr::version::*; pub use stability::*; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; -pub use version::*; arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7516460155e7..f1cbb72554d2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -229,6 +229,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::CfgTrace(..) | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::RustcBuiltinMacro { .. } @@ -302,6 +303,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) | AttributeKind::PinV2(..) | AttributeKind::WindowsSubsystem(..) + | AttributeKind::CfgAttrTrace | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } ) => { /* do nothing */ } @@ -338,8 +340,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::forbid | sym::cfg | sym::cfg_attr - | sym::cfg_trace - | sym::cfg_attr_trace // need to be fixed | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) @@ -1950,12 +1950,10 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) // in where clauses. After that, only `self.check_attributes` should be enough. - const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace]; let spans = self .tcx .hir_attrs(where_predicate.hir_id) .iter() - .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) // FIXME: We shouldn't need to special-case `doc`! .filter(|attr| { matches!( From 442981441294894978b8a1ce9cefcf52e2755bcd Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:26 +0100 Subject: [PATCH 165/340] Convert librustdoc to use the new parsed representation --- src/librustdoc/clean/cfg.rs | 129 +------------------- src/librustdoc/clean/cfg/tests.rs | 133 --------------------- src/librustdoc/clean/mod.rs | 16 +-- src/librustdoc/passes/propagate_doc_cfg.rs | 6 +- 4 files changed, 11 insertions(+), 273 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 61ebc73182c0..485af5ab1d01 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use std::{fmt, mem, ops}; use itertools::Either; -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; @@ -29,12 +28,6 @@ mod tests; #[cfg_attr(test, derive(PartialEq))] pub(crate) struct Cfg(CfgEntry); -#[derive(PartialEq, Debug)] -pub(crate) struct InvalidCfgError { - pub(crate) msg: &'static str, - pub(crate) span: Span, -} - /// Whether the configuration consists of just `Cfg` or `Not`. fn is_simple_cfg(cfg: &CfgEntry) -> bool { match cfg { @@ -105,106 +98,6 @@ fn should_capitalize_first_letter(cfg: &CfgEntry) -> bool { } impl Cfg { - /// Parses a `MetaItemInner` into a `Cfg`. - fn parse_nested( - nested_cfg: &MetaItemInner, - exclude: &FxHashSet, - ) -> Result, InvalidCfgError> { - match nested_cfg { - MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - Ok(Some(Cfg(CfgEntry::Bool(*b, DUMMY_SP)))) - } - MetaItemInner::Lit(lit) => { - Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) - } - } - } - - fn parse_without( - cfg: &MetaItem, - exclude: &FxHashSet, - ) -> Result, InvalidCfgError> { - let name = match cfg.ident() { - Some(ident) => ident.name, - None => { - return Err(InvalidCfgError { - msg: "expected a single identifier", - span: cfg.span, - }); - } - }; - match cfg.kind { - MetaItemKind::Word => { - if exclude.contains(&NameValueCfg::new(name)) { - Ok(None) - } else { - Ok(Some(Cfg(CfgEntry::NameValue { name, value: None, span: DUMMY_SP }))) - } - } - MetaItemKind::NameValue(ref lit) => match lit.kind { - LitKind::Str(value, _) => { - if exclude.contains(&NameValueCfg::new_value(name, value)) { - Ok(None) - } else { - Ok(Some(Cfg(CfgEntry::NameValue { - name, - value: Some(value), - span: DUMMY_SP, - }))) - } - } - _ => Err(InvalidCfgError { - // FIXME: if the main #[cfg] syntax decided to support non-string literals, - // this should be changed as well. - msg: "value of cfg option should be a string literal", - span: lit.span, - }), - }, - MetaItemKind::List(ref items) => { - let orig_len = items.len(); - let mut sub_cfgs = - items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose()); - let ret = match name { - sym::all => { - sub_cfgs.try_fold(Cfg(CfgEntry::Bool(true, DUMMY_SP)), |x, y| Ok(x & y?)) - } - sym::any => { - sub_cfgs.try_fold(Cfg(CfgEntry::Bool(false, DUMMY_SP)), |x, y| Ok(x | y?)) - } - sym::not => { - if orig_len == 1 { - let mut sub_cfgs = sub_cfgs.collect::>(); - if sub_cfgs.len() == 1 { - Ok(!sub_cfgs.pop().unwrap()?) - } else { - return Ok(None); - } - } else { - Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span }) - } - } - _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }), - }; - match ret { - Ok(c) => Ok(Some(c)), - Err(e) => Err(e), - } - } - } - } - - /// Parses a `MetaItem` into a `Cfg`. - /// - /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or - /// `target_os = "redox"`. - /// - /// If the content is not properly formatted, it will return an error indicating what and where - /// the error is. - pub(crate) fn parse(cfg: &MetaItemInner) -> Result { - Self::parse_nested(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) - } - /// 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(); @@ -644,10 +537,6 @@ impl NameValueCfg { fn new(name: Symbol) -> Self { Self { name, value: None } } - - fn new_value(name: Symbol, value: Symbol) -> Self { - Self { name, value: Some(value) } - } } impl<'a> From<&'a CfgEntry> for NameValueCfg { @@ -751,15 +640,6 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator tcx: TyCtxt<'_>, cfg_info: &mut CfgInfo, ) -> Option> { - fn single(it: T) -> Option { - let mut iter = it.into_iter(); - let item = iter.next()?; - if iter.next().is_some() { - return None; - } - Some(item) - } - fn check_changed_auto_active_status( changed_auto_active_status: &mut Option, attr_span: Span, @@ -859,12 +739,11 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } continue; } else if !cfg_info.parent_is_doc_cfg - && let Some(name) = attr.name() - && matches!(name, sym::cfg | sym::cfg_trace) - && let Some(attr) = single(attr.meta_item_list()?) - && let Ok(new_cfg) = Cfg::parse(&attr) + && let hir::Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) = attr { - cfg_info.current_cfg &= new_cfg; + for (new_cfg, _) in cfgs { + cfg_info.current_cfg &= Cfg(new_cfg.clone()); + } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 09316ead76ac..e0c21865d8df 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,8 +1,5 @@ -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::*; @@ -28,10 +25,6 @@ fn name_value_cfg_e(name: &str, value: &str) -> CfgEntry { } } -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)) } @@ -52,51 +45,6 @@ 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, - path: Path::from_ident(Ident::from_str(name)), - kind: MetaItemKind::Word, - span: DUMMY_SP, - }) -} - -fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItemInner { - let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(name)), - kind: MetaItemKind::NameValue(lit), - span: DUMMY_SP, - }) -} - -macro_rules! dummy_meta_item_list { - ($name:ident, [$($list:ident),* $(,)?]) => { - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(stringify!($name))), - kind: MetaItemKind::List(thin_vec![ - $( - dummy_meta_item_word(stringify!($list)), - )* - ]), - span: DUMMY_SP, - }) - }; - - ($name:ident, [$($list:expr),* $(,)?]) => { - MetaItemInner::MetaItem(MetaItem { - unsafety: Safety::Default, - path: Path::from_ident(Ident::from_str(stringify!($name))), - kind: MetaItemKind::List(thin_vec![ - $($list,)* - ]), - span: DUMMY_SP, - }) - }; -} - fn cfg_true() -> Cfg { Cfg(CfgEntry::Bool(true, DUMMY_SP)) } @@ -303,87 +251,6 @@ fn test_cfg_or() { }) } -#[test] -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())); - - let r#false = Symbol::intern("false"); - let mi = dummy_lit(r#false, LitKind::Bool(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"))); - - let done = Symbol::intern("done"); - let mi = dummy_meta_item_name_value("all", done, LitKind::Str(done, StrStyle::Cooked)); - assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); - - let mi = dummy_meta_item_list!(all, [a, b]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b"))); - - let mi = dummy_meta_item_list!(any, [a, b]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") | word_cfg("b"))); - - let mi = dummy_meta_item_list!(not, [a]); - assert_eq!(Cfg::parse(&mi), Ok(!word_cfg("a"))); - - let mi = dummy_meta_item_list!( - not, - [dummy_meta_item_list!( - any, - [dummy_meta_item_word("a"), dummy_meta_item_list!(all, [b, c]),] - ),] - ); - assert_eq!(Cfg::parse(&mi), Ok(!(word_cfg("a") | (word_cfg("b") & word_cfg("c"))))); - - let mi = dummy_meta_item_list!(all, [a, b, c]); - assert_eq!(Cfg::parse(&mi), Ok(word_cfg("a") & word_cfg("b") & word_cfg("c"))); - }) -} - -#[test] -fn test_parse_err() { - create_default_session_globals_then(|| { - let mi = dummy_meta_item_name_value("foo", kw::False, LitKind::Bool(false)); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, [a, b]); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, []); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(foo, []); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!( - all, - [dummy_meta_item_list!(foo, []), dummy_meta_item_word("b"),] - ); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!( - any, - [dummy_meta_item_word("a"), dummy_meta_item_list!(foo, []),] - ); - assert!(Cfg::parse(&mi).is_err()); - - let mi = dummy_meta_item_list!(not, [dummy_meta_item_list!(foo, []),]); - assert!(Cfg::parse(&mi).is_err()); - - let c = Symbol::intern("e"); - let mi = dummy_lit(c, LitKind::Char('e')); - assert!(Cfg::parse(&mi).is_err()); - - let five = Symbol::intern("5"); - let mi = dummy_lit(five, LitKind::Int(5.into(), LitIntType::Unsuffixed)); - assert!(Cfg::parse(&mi).is_err()); - }) -} - #[test] fn test_render_short_html() { create_default_session_globals_then(|| { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0768e6a56b3c..8de3722fa69d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -51,7 +51,7 @@ use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableE use rustc_middle::{bug, span_bug}; use rustc_span::ExpnKind; use rustc_span::hygiene::{AstPass, MacroKind}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_trait_selection::traits::wf::object_region_bounds; use tracing::{debug, instrument}; use utils::*; @@ -2682,17 +2682,13 @@ fn add_without_unwanted_attributes<'hir>( import_parent, )); } - hir::Attribute::Unparsed(normal) if let [name] = &*normal.path.segments => { - if is_inline || *name != sym::cfg_trace { - // If it's not a `cfg()` attribute, we keep it. - attrs.push((Cow::Borrowed(attr), import_parent)); - } - } - // FIXME: make sure to exclude `#[cfg_trace]` here when it is ported to the new parsers - hir::Attribute::Parsed(..) => { + + // We discard `#[cfg(...)]` attributes unless we're inlining + hir::Attribute::Parsed(AttributeKind::CfgTrace(..)) if !is_inline => {} + // We keep all other attributes + _ => { attrs.push((Cow::Borrowed(attr), import_parent)); } - _ => {} } } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index d4bf74c29514..54da158d4d39 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -2,7 +2,6 @@ use rustc_hir::Attribute; use rustc_hir::attrs::{AttributeKind, DocAttribute}; -use rustc_span::symbol::sym; use crate::clean::inline::{load_attrs, merge_attrs}; use crate::clean::{CfgInfo, Crate, Item, ItemKind}; @@ -39,10 +38,7 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) let mut new_attr = DocAttribute::default(); new_attr.cfg = d.cfg.clone(); attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); - } else if let Attribute::Unparsed(normal) = attr - && let [name] = &*normal.path.segments - && *name == sym::cfg_trace - { + } else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr { // If it's a `cfg()` attribute, we keep it. attrs.push(attr.clone()); } From e9fdf11c665f194bc269794e8523f61c7fb1591a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:35 +0100 Subject: [PATCH 166/340] Convert clippy to use the new parsed representation --- .../clippy/clippy_lints/src/attrs/mod.rs | 4 +- .../src/attrs/should_panic_without_expect.rs | 6 +-- .../clippy/clippy_lints/src/cfg_not_test.rs | 52 +++++++++++-------- .../src/doc/include_in_doc_without_cfg.rs | 4 +- .../clippy_lints/src/incompatible_msrv.rs | 9 ++-- .../clippy_lints/src/large_include_file.rs | 3 +- .../clippy_lints/src/methods/is_empty.rs | 5 +- .../clippy_lints/src/new_without_default.rs | 11 ++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 10 +++- src/tools/clippy/clippy_utils/src/lib.rs | 25 ++++----- 10 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 679ccfb8de3a..366f5873a1aa 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -16,7 +16,7 @@ mod utils; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -604,7 +604,7 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::ignore) && match &attr.kind { - AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }), + AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })), AttrKind::DocComment(..) => true, } { diff --git a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs index fd27e30a67f3..b854a3070bef 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrKind}; +use rustc_ast::{AttrArgs, AttrKind, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq { .. } = &normal_attr.item.args { + if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } - if let AttrArgs::Delimited(args) = &normal_attr.item.args + if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index 7590fe96fd21..ec543d02c9dd 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -1,7 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_ast::AttrItemKind; +use rustc_ast::EarlyParsedAttribute; +use rustc_span::sym; +use rustc_ast::attr::data_structures::CfgEntry; declare_clippy_lint! { /// ### What it does @@ -32,29 +35,34 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) { - span_lint_and_then( - cx, - CFG_NOT_TEST, - attr.span, - "code is excluded from test builds", - |diag| { - diag.help("consider not excluding any code from test builds"); - diag.note_once("this could increase code coverage despite not actually being tested"); - }, - ); + if attr.has_name(sym::cfg_trace) { + let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else { + unreachable!() + }; + + if contains_not_test(&cfg, false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } } } } -fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { - list.is_some_and(|list| { - list.iter().any(|item| { - item.ident().is_some_and(|ident| match ident.name { - rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), - rustc_span::sym::test => not, - _ => contains_not_test(item.meta_item_list(), not), - }) - }) - }) +fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool { + match cfg { + CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| { + contains_not_test(item, not) + }), + CfgEntry::Not(sub, _) => contains_not_test(sub, !not), + CfgEntry::NameValue { name: sym::test, .. } => not, + _ => false + } } diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs index bca1cd03bb7e..f8e9e870f629 100644 --- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 28ea2e4fa1f0..e0149a23fccf 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{ExpnKind, Span}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; declare_clippy_lint! { /// ### What it does @@ -268,11 +270,6 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { /// attribute. fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { - cx.tcx.hir_attrs(id).iter().any(|attr| { - matches!( - attr.name(), - Some(sym::cfg_trace | sym::cfg_attr_trace) - ) - }) + find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace) }) } diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 48ce1afc6e69..5c37747b8c9b 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -1,3 +1,4 @@ +use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; @@ -92,7 +93,7 @@ impl EarlyLintPass for LargeIncludeFile { && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index add01b6a0837..834456ff6668 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -5,7 +5,8 @@ use clippy_utils::res::MaybeResPath; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; -use rustc_span::sym; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use super::CONST_IS_EMPTY; @@ -40,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace))) + .any(|id| find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 6fc034b6fc5d..67493d54b552 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -9,6 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::sym; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -121,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let attrs_sugg = { let mut sugg = String::new(); for attr in cx.tcx.hir_attrs(assoc_item_hir_id) { - if !attr.has_name(sym::cfg_trace) { + let Attribute::Parsed(AttributeKind::CfgTrace(attrs)) = attr else { // This might be some other attribute that the `impl Default` ought to inherit. // But it could also be one of the many attributes that: // - can't be put on an impl block -- like `#[inline]` @@ -131,10 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // reduce the applicability app = Applicability::MaybeIncorrect; continue; + }; + + for (_, attr_span) in attrs { + sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app)); + sugg.push('\n'); } - sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app)); - sugg.push('\n'); } sugg }; 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 432d7a251a21..618719286e8f 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -976,11 +976,19 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args), + (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args), _ => false, } } +pub fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool { + match (l, r) { + (AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r), + (AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(), + _ => false, + } +} + pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { use AttrArgs::*; match (l, r) { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 954c32687af6..38e1542cd758 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -121,6 +121,7 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; +use rustc_hir::attrs::CfgEntry; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -2401,17 +2402,12 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.hir_attrs(id).iter().any(|attr| { - if attr.has_name(sym::cfg_trace) - && let Some(items) = attr.meta_item_list() - && let [item] = &*items - && item.has_name(sym::test) - { - true - } else { - false - } - }) + if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs) + && cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) { + true + } else { + false + } } /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied @@ -2426,11 +2422,10 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id, sym::cfg_trace) - || tcx + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..)) + || find_attr!(tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) - .any(|attr| attr.has_name(sym::cfg_trace)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..)) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is From f1ce0dd4dece601b131e794854ef219f40a7a444 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 26 Dec 2025 20:57:35 +0100 Subject: [PATCH 167/340] Convert clippy to use the new parsed representation --- clippy_lints/src/attrs/mod.rs | 4 +- .../src/attrs/should_panic_without_expect.rs | 6 +-- clippy_lints/src/cfg_not_test.rs | 52 +++++++++++-------- .../src/doc/include_in_doc_without_cfg.rs | 4 +- clippy_lints/src/incompatible_msrv.rs | 9 ++-- clippy_lints/src/large_include_file.rs | 3 +- clippy_lints/src/methods/is_empty.rs | 5 +- clippy_lints/src/new_without_default.rs | 11 ++-- clippy_utils/src/ast_utils/mod.rs | 10 +++- clippy_utils/src/lib.rs | 25 ++++----- 10 files changed, 72 insertions(+), 57 deletions(-) diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 679ccfb8de3a..366f5873a1aa 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -16,7 +16,7 @@ mod utils; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::msrvs::{self, Msrv, MsrvStack}; -use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind}; +use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind, AttrItemKind}; use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -604,7 +604,7 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { if attr.has_name(sym::ignore) && match &attr.kind { - AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }), + AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. })), AttrKind::DocComment(..) => true, } { diff --git a/clippy_lints/src/attrs/should_panic_without_expect.rs b/clippy_lints/src/attrs/should_panic_without_expect.rs index fd27e30a67f3..b854a3070bef 100644 --- a/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT}; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; -use rustc_ast::{AttrArgs, AttrKind}; +use rustc_ast::{AttrArgs, AttrKind, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq { .. } = &normal_attr.item.args { + if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } - if let AttrArgs::Delimited(args) = &normal_attr.item.args + if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args && let mut tt_iter = args.tokens.iter() && let Some(TokenTree::Token( Token { diff --git a/clippy_lints/src/cfg_not_test.rs b/clippy_lints/src/cfg_not_test.rs index 7590fe96fd21..ec543d02c9dd 100644 --- a/clippy_lints/src/cfg_not_test.rs +++ b/clippy_lints/src/cfg_not_test.rs @@ -1,7 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; +use rustc_ast::AttrItemKind; +use rustc_ast::EarlyParsedAttribute; +use rustc_span::sym; +use rustc_ast::attr::data_structures::CfgEntry; declare_clippy_lint! { /// ### What it does @@ -32,29 +35,34 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]); impl EarlyLintPass for CfgNotTest { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) { - span_lint_and_then( - cx, - CFG_NOT_TEST, - attr.span, - "code is excluded from test builds", - |diag| { - diag.help("consider not excluding any code from test builds"); - diag.note_once("this could increase code coverage despite not actually being tested"); - }, - ); + if attr.has_name(sym::cfg_trace) { + let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else { + unreachable!() + }; + + if contains_not_test(&cfg, false) { + span_lint_and_then( + cx, + CFG_NOT_TEST, + attr.span, + "code is excluded from test builds", + |diag| { + diag.help("consider not excluding any code from test builds"); + diag.note_once("this could increase code coverage despite not actually being tested"); + }, + ); + } } } } -fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool { - list.is_some_and(|list| { - list.iter().any(|item| { - item.ident().is_some_and(|ident| match ident.name { - rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not), - rustc_span::sym::test => not, - _ => contains_not_test(item.meta_item_list(), not), - }) - }) - }) +fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool { + match cfg { + CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| { + contains_not_test(item, not) + }), + CfgEntry::Not(sub, _) => contains_not_test(sub, !not), + CfgEntry::NameValue { name: sym::test, .. } => not, + _ => false + } } diff --git a/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/clippy_lints/src/doc/include_in_doc_without_cfg.rs index bca1cd03bb7e..f8e9e870f629 100644 --- a/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute, AttrItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index 28ea2e4fa1f0..e0149a23fccf 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{ExpnKind, Span}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; declare_clippy_lint! { /// ### What it does @@ -268,11 +270,6 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { /// attribute. fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool { cx.tcx.hir_parent_id_iter(hir_id).any(|id| { - cx.tcx.hir_attrs(id).iter().any(|attr| { - matches!( - attr.name(), - Some(sym::cfg_trace | sym::cfg_attr_trace) - ) - }) + find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace) }) } diff --git a/clippy_lints/src/large_include_file.rs b/clippy_lints/src/large_include_file.rs index 48ce1afc6e69..5c37747b8c9b 100644 --- a/clippy_lints/src/large_include_file.rs +++ b/clippy_lints/src/large_include_file.rs @@ -1,3 +1,4 @@ +use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; @@ -92,7 +93,7 @@ impl EarlyLintPass for LargeIncludeFile { && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs index add01b6a0837..834456ff6668 100644 --- a/clippy_lints/src/methods/is_empty.rs +++ b/clippy_lints/src/methods/is_empty.rs @@ -5,7 +5,8 @@ use clippy_utils::res::MaybeResPath; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; -use rustc_span::sym; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use super::CONST_IS_EMPTY; @@ -40,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace))) + .any(|id| find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 6fc034b6fc5d..67493d54b552 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -9,6 +9,8 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocKind; use rustc_session::impl_lint_pass; use rustc_span::sym; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -121,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let attrs_sugg = { let mut sugg = String::new(); for attr in cx.tcx.hir_attrs(assoc_item_hir_id) { - if !attr.has_name(sym::cfg_trace) { + let Attribute::Parsed(AttributeKind::CfgTrace(attrs)) = attr else { // This might be some other attribute that the `impl Default` ought to inherit. // But it could also be one of the many attributes that: // - can't be put on an impl block -- like `#[inline]` @@ -131,10 +133,13 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // reduce the applicability app = Applicability::MaybeIncorrect; continue; + }; + + for (_, attr_span) in attrs { + sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app)); + sugg.push('\n'); } - sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app)); - sugg.push('\n'); } sugg }; diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs index 432d7a251a21..618719286e8f 100644 --- a/clippy_utils/src/ast_utils/mod.rs +++ b/clippy_utils/src/ast_utils/mod.rs @@ -976,11 +976,19 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args), + (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args), _ => false, } } +pub fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool { + match (l, r) { + (AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r), + (AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(), + _ => false, + } +} + pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { use AttrArgs::*; match (l, r) { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 954c32687af6..38e1542cd758 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -121,6 +121,7 @@ use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; +use rustc_hir::attrs::CfgEntry; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; @@ -2401,17 +2402,12 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool { /// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent /// use [`is_in_cfg_test`] pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx.hir_attrs(id).iter().any(|attr| { - if attr.has_name(sym::cfg_trace) - && let Some(items) = attr.meta_item_list() - && let [item] = &*items - && item.has_name(sym::test) - { - true - } else { - false - } - }) + if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs) + && cfgs.iter().any(|(cfg, _)| { matches!(cfg, CfgEntry::NameValue { name: sym::test, ..})}) { + true + } else { + false + } } /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied @@ -2426,11 +2422,10 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.has_attr(def_id, sym::cfg_trace) - || tcx + find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..)) + || find_attr!(tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) - .any(|attr| attr.has_name(sym::cfg_trace)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)), AttributeKind::CfgTrace(..)) } /// Walks up the HIR tree from the given expression in an attempt to find where the value is From bd5526c2cf7a040d96ef7c41fce8b9f0ca6b9374 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Tue, 6 Jan 2026 20:14:52 +0900 Subject: [PATCH 168/340] accept test changes related to binary ops --- src/tools/clippy/tests/ui/manual_clamp.fixed | 3 +- src/tools/clippy/tests/ui/manual_clamp.rs | 3 +- src/tools/clippy/tests/ui/manual_clamp.stderr | 70 +++++++++---------- .../tests/ui/needless_bitwise_bool.fixed | 4 +- .../clippy/tests/ui/needless_bitwise_bool.rs | 2 + .../tests/ui/needless_bitwise_bool.stderr | 8 ++- 6 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/tools/clippy/tests/ui/manual_clamp.fixed b/src/tools/clippy/tests/ui/manual_clamp.fixed index 2450a4f4c611..b279a413bc17 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.fixed +++ b/src/tools/clippy/tests/ui/manual_clamp.fixed @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs index ee341d50768f..7fda41cd4c35 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.rs +++ b/src/tools/clippy/tests/ui/manual_clamp.rs @@ -4,7 +4,8 @@ dead_code, clippy::unnecessary_operation, clippy::no_effect, - clippy::if_same_then_else + clippy::if_same_then_else, + clippy::needless_match )] use std::cmp::{max as cmp_max, min as cmp_min}; diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr index 4a0e4fa51646..775a16418eba 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.stderr +++ b/src/tools/clippy/tests/ui/manual_clamp.stderr @@ -1,5 +1,5 @@ error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:212:5 + --> tests/ui/manual_clamp.rs:213:5 | LL | / if x9 < CONST_MIN { LL | | @@ -15,7 +15,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:230:5 + --> tests/ui/manual_clamp.rs:231:5 | LL | / if x11 > CONST_MAX { LL | | @@ -29,7 +29,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:240:5 + --> tests/ui/manual_clamp.rs:241:5 | LL | / if CONST_MIN > x12 { LL | | @@ -43,7 +43,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:250:5 + --> tests/ui/manual_clamp.rs:251:5 | LL | / if CONST_MAX < x13 { LL | | @@ -57,7 +57,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:363:5 + --> tests/ui/manual_clamp.rs:364:5 | LL | / if CONST_MAX < x35 { LL | | @@ -71,7 +71,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:144:14 + --> tests/ui/manual_clamp.rs:145:14 | LL | let x0 = if CONST_MAX < input { | ______________^ @@ -86,7 +86,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:154:14 + --> tests/ui/manual_clamp.rs:155:14 | LL | let x1 = if input > CONST_MAX { | ______________^ @@ -101,7 +101,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:164:14 + --> tests/ui/manual_clamp.rs:165:14 | LL | let x2 = if input < CONST_MIN { | ______________^ @@ -116,7 +116,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:174:14 + --> tests/ui/manual_clamp.rs:175:14 | LL | let x3 = if CONST_MIN > input { | ______________^ @@ -131,7 +131,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:184:14 + --> tests/ui/manual_clamp.rs:185:14 | LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -139,7 +139,7 @@ LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:187:14 + --> tests/ui/manual_clamp.rs:188:14 | LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -147,7 +147,7 @@ LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:190:14 + --> tests/ui/manual_clamp.rs:191:14 | LL | let x6 = match input { | ______________^ @@ -161,7 +161,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:197:14 + --> tests/ui/manual_clamp.rs:198:14 | LL | let x7 = match input { | ______________^ @@ -175,7 +175,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:204:14 + --> tests/ui/manual_clamp.rs:205:14 | LL | let x8 = match input { | ______________^ @@ -189,7 +189,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:221:15 + --> tests/ui/manual_clamp.rs:222:15 | LL | let x10 = match input { | _______________^ @@ -203,7 +203,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:259:15 + --> tests/ui/manual_clamp.rs:260:15 | LL | let x14 = if input > CONST_MAX { | _______________^ @@ -218,7 +218,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:270:19 + --> tests/ui/manual_clamp.rs:271:19 | LL | let x15 = if input > CONST_F64_MAX { | ___________________^ @@ -234,7 +234,7 @@ LL | | }; = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:283:19 + --> tests/ui/manual_clamp.rs:284:19 | LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -242,7 +242,7 @@ LL | let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:286:19 + --> tests/ui/manual_clamp.rs:287:19 | LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -250,7 +250,7 @@ LL | let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:289:19 + --> tests/ui/manual_clamp.rs:290:19 | LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -258,7 +258,7 @@ LL | let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:292:19 + --> tests/ui/manual_clamp.rs:293:19 | LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -266,7 +266,7 @@ LL | let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:295:19 + --> tests/ui/manual_clamp.rs:296:19 | LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -274,7 +274,7 @@ LL | let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:298:19 + --> tests/ui/manual_clamp.rs:299:19 | LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -282,7 +282,7 @@ LL | let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:301:19 + --> tests/ui/manual_clamp.rs:302:19 | LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -290,7 +290,7 @@ LL | let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:304:19 + --> tests/ui/manual_clamp.rs:305:19 | LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -298,7 +298,7 @@ LL | let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:308:19 + --> tests/ui/manual_clamp.rs:309:19 | LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -307,7 +307,7 @@ LL | let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:311:19 + --> tests/ui/manual_clamp.rs:312:19 | LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -316,7 +316,7 @@ LL | let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:314:19 + --> tests/ui/manual_clamp.rs:315:19 | LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -325,7 +325,7 @@ LL | let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:317:19 + --> tests/ui/manual_clamp.rs:318:19 | LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -334,7 +334,7 @@ LL | let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:320:19 + --> tests/ui/manual_clamp.rs:321:19 | LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -343,7 +343,7 @@ LL | let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:323:19 + --> tests/ui/manual_clamp.rs:324:19 | LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -352,7 +352,7 @@ LL | let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:326:19 + --> tests/ui/manual_clamp.rs:327:19 | LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -361,7 +361,7 @@ LL | let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:329:19 + --> tests/ui/manual_clamp.rs:330:19 | LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)` @@ -370,7 +370,7 @@ LL | let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:333:5 + --> tests/ui/manual_clamp.rs:334:5 | LL | / if x32 < CONST_MIN { LL | | @@ -384,7 +384,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:525:13 + --> tests/ui/manual_clamp.rs:526:13 | LL | let _ = if input > CONST_MAX { | _____________^ diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed index 89a3c1474f25..751d3d257000 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } - if y & (0 < 1) { + // Resolved + if y && (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs index f5aa7a9f3d9e..5d3ff3b2079c 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -34,7 +34,9 @@ fn main() { println!("true") // This is a const method call } + // Resolved if y & (0 < 1) { + //~^ needless_bitwise_bool println!("true") // This is a BinOp with no side effects } } diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr index 9f14646c3e5a..4f64c7136916 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr @@ -7,5 +7,11 @@ LL | if y & !x { = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_bitwise_bool)]` -error: aborting due to 1 previous error +error: use of bitwise operator instead of lazy operator between booleans + --> tests/ui/needless_bitwise_bool.rs:38:8 + | +LL | if y & (0 < 1) { + | ^^^^^^^^^^^ help: try: `y && (0 < 1)` + +error: aborting due to 2 previous errors From d32f1c695fb7a1082b710fd0ff7516a824bc2cff Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 5 Jan 2026 13:59:22 +0000 Subject: [PATCH 169/340] add const ctor support --- .../src/hir_ty_lowering/mod.rs | 58 ++++++++++++-- tests/crashes/132985.rs | 17 ---- tests/crashes/136138.rs | 7 -- tests/crashes/139596.rs | 10 --- tests/crashes/mgca/ace-with-const-ctor.rs | 16 ---- .../ice-associated-const-equality-105952.rs | 20 +++++ .../mgca/const-ctor-overflow-eval.rs | 19 +++++ .../mgca/const-ctor-overflow-eval.stderr | 80 +++++++++++++++++++ .../mgca/const-ctor-with-error.rs | 19 +++++ .../mgca/const-ctor-with-error.stderr | 14 ++++ tests/ui/const-generics/mgca/const-ctor.rs | 49 ++++++++++++ 11 files changed, 254 insertions(+), 55 deletions(-) delete mode 100644 tests/crashes/132985.rs delete mode 100644 tests/crashes/136138.rs delete mode 100644 tests/crashes/139596.rs delete mode 100644 tests/crashes/mgca/ace-with-const-ctor.rs create mode 100644 tests/rustdoc/constant/ice-associated-const-equality-105952.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr create mode 100644 tests/ui/const-generics/mgca/const-ctor-with-error.rs create mode 100644 tests/ui/const-generics/mgca/const-ctor-with-error.stderr create mode 100644 tests/ui/const-generics/mgca/const-ctor.rs diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d0f25e8fc321..a22729fd287e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1415,9 +1415,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ct = self.check_param_uses_if_mcg(ct, span, false); Ok(ct) } - TypeRelativePath::Ctor { ctor_def_id, args } => { - return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))); - } + TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) { + DefKind::Ctor(_, CtorKind::Fn) => { + Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args))) + } + DefKind::Ctor(ctor_of, CtorKind::Const) => { + Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args)) + } + _ => unreachable!(), + }, // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, // not just const ctors TypeRelativePath::Variant { .. } => { @@ -1452,7 +1458,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(mgca): do we want constructor resolutions to take priority over // other possible resolutions? if matches!(mode, LowerTypeRelativePathMode::Const) - && let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor + && let Some((_, ctor_def_id)) = variant_def.ctor { tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None); let _ = self.prohibit_generic_args( @@ -2597,7 +2603,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); self.lower_const_param(def_id, hir_id) } - Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => { + Res::Def(DefKind::Const, did) => { assert_eq!(opt_self_ty, None); let [leading_segments @ .., segment] = path.segments else { bug!() }; let _ = self @@ -2605,6 +2611,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let args = self.lower_generic_args_of_path_segment(span, did, segment); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } + Res::Def(DefKind::Ctor(ctor_of, CtorKind::Const), did) => { + assert_eq!(opt_self_ty, None); + let [leading_segments @ .., segment] = path.segments else { bug!() }; + let _ = self + .prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None); + + let parent_did = tcx.parent(did); + let generics_did = match ctor_of { + CtorOf::Variant => tcx.parent(parent_did), + CtorOf::Struct => parent_did, + }; + let args = self.lower_generic_args_of_path_segment(span, generics_did, segment); + + self.construct_const_ctor_value(did, ctor_of, args) + } Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => { assert_eq!(opt_self_ty, None); let [leading_segments @ .., segment] = path.segments else { bug!() }; @@ -3174,4 +3195,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(r) } + + fn construct_const_ctor_value( + &self, + ctor_def_id: DefId, + ctor_of: CtorOf, + args: GenericArgsRef<'tcx>, + ) -> Const<'tcx> { + let tcx = self.tcx(); + let parent_did = tcx.parent(ctor_def_id); + + let adt_def = tcx.adt_def(match ctor_of { + CtorOf::Variant => tcx.parent(parent_did), + CtorOf::Struct => parent_did, + }); + + let variant_idx = adt_def.variant_index_with_id(parent_did); + + let valtree = if adt_def.is_enum() { + let discr = ty::ValTree::from_scalar_int(tcx, variant_idx.as_u32().into()); + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, discr, tcx.types.u32)]) + } else { + ty::ValTree::zst(tcx) + }; + + let adt_ty = Ty::new_adt(tcx, adt_def, args); + ty::Const::new_value(tcx, valtree, adt_ty) + } } diff --git a/tests/crashes/132985.rs b/tests/crashes/132985.rs deleted file mode 100644 index 2735074f44d1..000000000000 --- a/tests/crashes/132985.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #132985 -//@ aux-build:aux132985.rs - -#![allow(incomplete_features)] -#![feature(min_generic_const_args)] -#![feature(adt_const_params)] - -extern crate aux132985; -use aux132985::Foo; - -fn bar() {} - -fn baz() { - bar::<{ Foo }>(); -} - -fn main() {} diff --git a/tests/crashes/136138.rs b/tests/crashes/136138.rs deleted file mode 100644 index c3893dc9c8e6..000000000000 --- a/tests/crashes/136138.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #136138 -#![feature(min_generic_const_args)] -struct U; -struct S() -where - S<{ U }>:; -fn main() {} diff --git a/tests/crashes/139596.rs b/tests/crashes/139596.rs deleted file mode 100644 index 590cfddf83e2..000000000000 --- a/tests/crashes/139596.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #139596 - -#![feature(min_generic_const_args)] -struct Colour; - -struct Led; - -fn main() { - Led::<{ Colour}>; -} diff --git a/tests/crashes/mgca/ace-with-const-ctor.rs b/tests/crashes/mgca/ace-with-const-ctor.rs deleted file mode 100644 index 28e85f37de1f..000000000000 --- a/tests/crashes/mgca/ace-with-const-ctor.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #132980 -// Originally a rustdoc test. Should be moved back there with @has checks -// readded once fixed. -// Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952 -#![crate_name = "foo"] -#![feature(min_generic_const_args)] -pub enum ParseMode { - Raw, -} -pub trait Parse { - #[type_const] - const PARSE_MODE: ParseMode; -} -pub trait RenderRaw {} - -impl> RenderRaw for T {} diff --git a/tests/rustdoc/constant/ice-associated-const-equality-105952.rs b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs new file mode 100644 index 000000000000..310e56b917fc --- /dev/null +++ b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs @@ -0,0 +1,20 @@ +//! Regression test for + +#![crate_name = "foo"] +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq, ConstParamTy)] +pub enum ParseMode { + Raw, +} +pub trait Parse { + #[type_const] + const PARSE_MODE: ParseMode; +} +pub trait RenderRaw {} + +//@ hasraw foo/trait.RenderRaw.html 'impl' +//@ hasraw foo/trait.RenderRaw.html 'ParseMode::Raw' +impl> RenderRaw for T {} diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs new file mode 100644 index 000000000000..6a4ee3ed1772 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.rs @@ -0,0 +1,19 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +struct U; + +#[derive(ConstParamTy, PartialEq, Eq)] +//~^ ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` + +struct S() +where + S<{ U }>:; +//~^ ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` +//~| ERROR overflow evaluating the requirement `S well-formed` + +fn main() {} diff --git a/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr new file mode 100644 index 000000000000..4c5ad645bc45 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-overflow-eval.stderr @@ -0,0 +1,80 @@ +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | S<{ U }>:; + | ^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:8:24 + | +LL | #[derive(ConstParamTy, PartialEq, Eq)] + | ^^^^^^^^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error[E0275]: overflow evaluating the requirement `S well-formed` + --> $DIR/const-ctor-overflow-eval.rs:8:35 + | +LL | #[derive(ConstParamTy, PartialEq, Eq)] + | ^^ + | +note: required by a bound in `S` + --> $DIR/const-ctor-overflow-eval.rs:14:5 + | +LL | struct S() + | - required by a bound in this struct +LL | where +LL | S<{ U }>:; + | ^^^^^^^^ required by this bound in `S` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/const-generics/mgca/const-ctor-with-error.rs b/tests/ui/const-generics/mgca/const-ctor-with-error.rs new file mode 100644 index 000000000000..95a910e3dd2c --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-with-error.rs @@ -0,0 +1,19 @@ +// to ensure it does not ices like before + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum Option { + #[allow(dead_code)] + Some(T), + None, +} + +fn pass_enum>() {} + +fn main() { + pass_enum::<{ None }>(); + //~^ ERROR missing generics for enum `std::option::Option` +} diff --git a/tests/ui/const-generics/mgca/const-ctor-with-error.stderr b/tests/ui/const-generics/mgca/const-ctor-with-error.stderr new file mode 100644 index 000000000000..8684457a978b --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor-with-error.stderr @@ -0,0 +1,14 @@ +error[E0107]: missing generics for enum `std::option::Option` + --> $DIR/const-ctor-with-error.rs:17:19 + | +LL | pass_enum::<{ None }>(); + | ^^^^ expected 1 generic argument + | +help: add missing generic argument + | +LL | pass_enum::<{ None }>(); + | +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/const-generics/mgca/const-ctor.rs b/tests/ui/const-generics/mgca/const-ctor.rs new file mode 100644 index 000000000000..19900b56a816 --- /dev/null +++ b/tests/ui/const-generics/mgca/const-ctor.rs @@ -0,0 +1,49 @@ +//! Regression test for +//! +//! + +//@ check-pass + +#![feature( + min_generic_const_args, + adt_const_params, + generic_const_parameter_types, + unsized_const_params +)] +#![expect(incomplete_features)] +use std::marker::{ConstParamTy, ConstParamTy_}; +#[derive(ConstParamTy, PartialEq, Eq)] +struct Colour; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum A { + B, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +enum MyOption { + #[allow(dead_code)] + Some(T), + None, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +struct Led; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Foo; + +fn pass_enum>() {} + +fn accepts_foo>() {} + +fn accepts_bar>() {} + +fn test() { + accepts_foo:: }>(); + accepts_bar:: }>(); +} + +fn main() { + Led::<{ Colour }>; +} From 460f22c38823b3478ff5aa5f9083968974532177 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:02:51 +0300 Subject: [PATCH 170/340] resolve: Rename `NameBinding(Data,Kind)` to `Decl(Data,Kind)` Also, rename `DeclKind::Res` to `DeclKind::Def`. --- compiler/rustc_middle/src/metadata.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 16 +- compiler/rustc_resolve/src/check_unused.rs | 6 +- compiler/rustc_resolve/src/diagnostics.rs | 56 +++---- .../src/effective_visibilities.rs | 20 +-- compiler/rustc_resolve/src/ident.rs | 60 +++---- compiler/rustc_resolve/src/imports.rs | 76 ++++----- compiler/rustc_resolve/src/late.rs | 8 +- compiler/rustc_resolve/src/lib.rs | 153 +++++++++--------- compiler/rustc_resolve/src/macros.rs | 14 +- 10 files changed, 195 insertions(+), 216 deletions(-) diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index b7848bc261d8..9e5b3ef61905 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -26,7 +26,7 @@ impl Reexport { } } -/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates +/// This structure is supposed to keep enough data to re-create `Decl`s for other crates /// during name resolution. Right now the bindings are not recreated entirely precisely so we may /// need to add more data in the future to correctly support macros 2.0, for example. /// Module child can be either a proper item or a reexport (including private imports). diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 241c13663ae5..d31723844290 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -36,9 +36,9 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, Segment, Used, VisResolutionError, errors, + BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, MacroData, Module, + ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment, + Used, VisResolutionError, errors, }; type Res = def::Res; @@ -51,7 +51,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'ra>, ident: Ident, ns: Namespace, - binding: NameBinding<'ra>, + binding: Decl<'ra>, ) { if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); @@ -82,10 +82,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis: Visibility, span: Span, expansion: LocalExpnId, - ambiguity: Option>, + ambiguity: Option>, ) { - let binding = self.arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(res), + let binding = self.arenas.alloc_name_binding(DeclData { + kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: true, @@ -1092,7 +1092,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { fn add_macro_use_binding( &mut self, name: Symbol, - binding: NameBinding<'ra>, + binding: Decl<'ra>, span: Span, allow_shadowing: bool, ) { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 5349cf6d7dbe..b7705773041f 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{ use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{LexicalScopeBinding, NameBindingKind, Resolver, module_to_string}; +use crate::{DeclKind, LexicalScopeBinding, Resolver, module_to_string}; struct UnusedImport { use_tree: ast::UseTree, @@ -515,7 +515,7 @@ impl Resolver<'_, '_> { for module in &self.local_modules { for (_key, resolution) in self.resolutions(*module).borrow().iter() { if let Some(binding) = resolution.borrow().best_binding() - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { if let Some(unused_import) = unused_imports.get(&import.root_id) @@ -543,7 +543,7 @@ impl Resolver<'_, '_> { // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding - && let NameBindingKind::Import { import, .. } = name_binding.kind + && let DeclKind::Import { import, .. } = name_binding.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 716e1d5a2e7f..7e78f66574ed 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -44,11 +44,11 @@ use crate::errors::{ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ - AmbiguityError, AmbiguityKind, BindingError, BindingKey, Finalize, + AmbiguityError, AmbiguityKind, BindingError, BindingKey, Decl, DeclKind, Finalize, ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, - ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, - PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, - VisResolutionError, errors as errs, path_names_to_string, + ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, + Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, + path_names_to_string, }; type Res = def::Res; @@ -149,8 +149,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ambiguity_error.warning { let node_id = match ambiguity_error.b1.0.kind { - NameBindingKind::Import { import, .. } => import.root_id, - NameBindingKind::Res(_) => CRATE_NODE_ID, + DeclKind::Import { import, .. } => import.root_id, + DeclKind::Def(_) => CRATE_NODE_ID, }; self.lint_buffer.buffer_lint( AMBIGUOUS_GLOB_IMPORTS, @@ -212,8 +212,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'_>, ident: Ident, ns: Namespace, - new_binding: NameBinding<'ra>, - old_binding: NameBinding<'ra>, + new_binding: Decl<'ra>, + old_binding: Decl<'ra>, ) { // Error on the second of two conflicting names if old_binding.span.lo() > new_binding.span.lo() { @@ -288,8 +288,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .with_code(code); // See https://github.com/rust-lang/rust/issues/32354 - use NameBindingKind::Import; - let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| { + use DeclKind::Import; + let can_suggest = |binding: Decl<'_>, import: self::Import<'_>| { !binding.span.is_dummy() && !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport) }; @@ -473,7 +473,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, finalize: Finalize, path: &[Segment], - second_binding: Option>, + second_binding: Option>, ) { let Finalize { node_id, root_span, .. } = finalize; @@ -506,7 +506,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! if let Some(binding) = second_binding - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind // Careful: we still want to rewrite paths from renamed extern crates. && let ImportKind::ExternCrate { source: None, .. } = import.kind { @@ -1360,7 +1360,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let NameBindingKind::Import { binding, .. } = name_binding.kind + if let DeclKind::Import { binding, .. } = name_binding.kind && this.is_accessible_from(binding.vis, parent_scope.module) && !this.is_accessible_from(name_binding.vis, parent_scope.module) { @@ -1469,8 +1469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident.0)); - let alias_import = if let NameBindingKind::Import { import, .. } = - name_binding.kind + let alias_import = if let DeclKind::Import { import, .. } = name_binding.kind && let ImportKind::ExternCrate { source: Some(_), .. } = import.kind && import.parent_scope.expansion == parent_scope.expansion { @@ -1754,7 +1753,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_kind.descr_expected(), ), }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind + if let crate::DeclKind::Import { import, .. } = binding.kind && !import.span.is_dummy() { let note = errors::IdentImporterHereButItIsDesc { @@ -1971,7 +1970,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: NameBinding<'_>, ident: Ident, scope: Scope<'_>) -> String { + fn binding_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { let (built_in, from) = match scope { @@ -2016,7 +2015,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (b1, b2, scope1, scope2, false) }; - let could_refer_to = |b: NameBinding<'_>, scope: Scope<'ra>, also: &str| { + let could_refer_to = |b: Decl<'_>, scope: Scope<'ra>, also: &str| { let what = self.binding_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -2075,11 +2074,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. - fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option { - let NameBindingKind::Res(Res::Def( - DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), - ctor_def_id, - )) = binding.kind + fn ctor_fields_span(&self, binding: Decl<'_>) -> Option { + let DeclKind::Def(Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id)) = + binding.kind else { return None; }; @@ -2105,8 +2102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let nonimport_descr = if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; let import_descr = nonimport_descr.clone() + " import"; - let get_descr = - |b: NameBinding<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; + let get_descr = |b: Decl<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. let ident_descr = get_descr(binding); @@ -2217,7 +2213,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let name = next_ident; next_binding = match binding.kind { _ if res == Res::Err => None, - NameBindingKind::Import { binding, import, .. } => match import.kind { + DeclKind::Import { binding, import, .. } => match import.kind { _ if binding.span.is_dummy() => None, ImportKind::Single { source, .. } => { next_ident = source; @@ -2232,7 +2228,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match binding.kind { - NameBindingKind::Import { import, .. } => { + DeclKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { // Don't include `{{root}}` in suggestions - it's an internal symbol // that should never be shown to users. @@ -2245,14 +2241,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) => {} + DeclKind::Def(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); if !first && binding.vis.is_public() { let desc = match binding.kind { - NameBindingKind::Import { .. } => "re-export", + DeclKind::Import { .. } => "re-export", _ => "directly", }; note_span.push_span_label(def_span, format!("you could import this {desc}")); @@ -2418,7 +2414,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, module: Option>, failed_segment_idx: usize, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index fe6e5b8e6eb6..5d78f3752439 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -8,12 +8,12 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::ty::Visibility; use tracing::info; -use crate::{NameBinding, NameBindingKind, Resolver}; +use crate::{Decl, DeclKind, Resolver}; #[derive(Clone, Copy)] enum ParentId<'ra> { Def(LocalDefId), - Import(NameBinding<'ra>), + Import(Decl<'ra>), } impl ParentId<'_> { @@ -31,7 +31,7 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { /// While walking import chains we need to track effective visibilities per-binding, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple /// bindings can correspond to a single def id in imports. So we keep a separate table. - import_effective_visibilities: EffectiveVisibilities>, + import_effective_visibilities: EffectiveVisibilities>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, changed: bool, @@ -42,8 +42,8 @@ impl Resolver<'_, '_> { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility { - let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; + fn private_vis_import(&self, binding: Decl<'_>) -> Visibility { + let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; Visibility::Restricted( import .id() @@ -70,7 +70,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { pub(crate) fn compute_effective_visibilities<'c>( r: &'a mut Resolver<'ra, 'tcx>, krate: &'c Crate, - ) -> FxHashSet> { + ) -> FxHashSet> { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), @@ -95,7 +95,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { - let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; + let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; if !binding.is_ambiguity_recursive() { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) @@ -126,10 +126,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. let is_ambiguity = - |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + |binding: Decl<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = binding.warn_ambiguity; - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + while let DeclKind::Import { binding: nested_binding, .. } = binding.kind { self.update_import(binding, parent_id); if is_ambiguity(binding, warn_ambiguity) { @@ -188,7 +188,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } } - fn update_import(&mut self, binding: NameBinding<'ra>, parent_id: ParentId<'ra>) { + fn update_import(&mut self, binding: Decl<'ra>, parent_id: ParentId<'ra>) { let nominal_vis = binding.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b6ec26be5ca1..7ebc75abca89 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,10 +19,10 @@ use crate::late::{ }; use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportKind, - LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, - ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, - Segment, Stage, Used, errors, + AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, + ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, + PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, + Used, errors, }; #[derive(Copy, Clone)] @@ -305,7 +305,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, ribs: &[Rib<'ra>], - ignore_binding: Option>, + ignore_binding: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> Option> { let orig_ident = ident; @@ -392,9 +392,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. @@ -425,7 +425,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_results: Vec<(NameBinding<'_>, Scope<'_>)> = Vec::new(); + let mut innermost_results: Vec<(Decl<'_>, Scope<'_>)> = Vec::new(); let mut determinacy = Determinacy::Determined; // Go through all the scopes and try to resolve the name. @@ -518,9 +518,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { @@ -759,9 +759,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - binding: NameBinding<'ra>, + binding: Decl<'ra>, scope: Scope<'ra>, - innermost_results: &[(NameBinding<'ra>, Scope<'ra>)], + innermost_results: &[(Decl<'ra>, Scope<'ra>)], ) -> bool { let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); let (res, innermost_res) = (binding.res(), innermost_binding.res()); @@ -869,7 +869,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) } @@ -881,9 +881,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { let tmp_parent_scope; let mut adjusted_parent_scope = parent_scope; match module { @@ -921,9 +921,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, Determinacy> { + ) -> Result, Determinacy> { match module { ModuleOrUniformRoot::Module(module) => self.resolve_ident_in_scope_set( ident, @@ -994,9 +994,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: Option, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding // doesn't need to be mutable. It will fail when there is a cycle of imports, and without @@ -1055,9 +1055,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); // `try_borrow_mut` is required to ensure exclusive access, even if the resulting binding // doesn't need to be mutable. It will fail when there is a cycle of imports, and without @@ -1179,12 +1179,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn finalize_module_binding( &mut self, ident: Ident, - binding: Option>, + binding: Option>, parent_scope: &ParentScope<'ra>, module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, - ) -> Result, ControlFlow> { + ) -> Result, ControlFlow> { let Finalize { path_span, report_private, used, root_span, .. } = finalize; let Some(binding) = binding else { @@ -1209,7 +1209,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if shadowing == Shadowing::Unrestricted && binding.expansion != LocalExpnId::ROOT - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && matches!(import.kind, ImportKind::MacroExport) { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); @@ -1255,15 +1255,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn single_import_can_define_name<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, - binding: Option>, + binding: Option>, ns: Namespace, ignore_import: Option>, - ignore_binding: Option>, + ignore_binding: Option>, parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { if let Some(binding) = resolution.non_glob_binding - && let NameBindingKind::Import { import, .. } = binding.kind + && let DeclKind::Import { import, .. } = binding.kind && import == *single_import { // Single import has already defined the name and we are aware of it, @@ -1277,7 +1277,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } if let Some(ignored) = ignore_binding - && let NameBindingKind::Import { import, .. } = ignored.kind + && let DeclKind::Import { import, .. } = ignored.kind && import == *single_import { continue; @@ -1668,7 +1668,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, ) -> PathResult<'ra> { self.resolve_path_with_ribs( @@ -1692,7 +1692,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { source: Option>, finalize: Option, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_binding: Option>, ignore_import: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 558f769eda19..7648b980ec5c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -32,23 +32,23 @@ use crate::errors::{ }; use crate::ref_mut::CmCell; use crate::{ - AmbiguityError, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, Module, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, + AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, + ImportSuggestion, Module, ModuleOrUniformRoot, ParentScope, PathResult, PerNS, ResolutionError, + Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res; -/// A [`NameBinding`] in the process of being resolved. +/// A [`Decl`] in the process of being resolved. #[derive(Clone, Copy, Default, PartialEq)] pub(crate) enum PendingBinding<'ra> { - Ready(Option>), + Ready(Option>), #[default] Pending, } impl<'ra> PendingBinding<'ra> { - pub(crate) fn binding(self) -> Option> { + pub(crate) fn binding(self) -> Option> { match self { PendingBinding::Ready(binding) => binding, PendingBinding::Pending => None, @@ -244,14 +244,14 @@ pub(crate) struct NameResolution<'ra> { /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet>, /// The non-glob binding for this name, if it is known to exist. - pub non_glob_binding: Option>, + pub non_glob_binding: Option>, /// The glob binding for this name, if it is known to exist. - pub glob_binding: Option>, + pub glob_binding: Option>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. - pub(crate) fn binding(&self) -> Option> { + pub(crate) fn binding(&self) -> Option> { self.best_binding().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) @@ -261,7 +261,7 @@ impl<'ra> NameResolution<'ra> { }) } - pub(crate) fn best_binding(&self) -> Option> { + pub(crate) fn best_binding(&self) -> Option> { self.non_glob_binding.or(self.glob_binding) } } @@ -282,12 +282,9 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack( - import: Import<'_>, - binding: NameBinding<'_>, -) -> Option { +fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: Decl<'_>) -> Option { match (&import.kind, &binding.kind) { - (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) + (ImportKind::Single { .. }, DeclKind::Import { import: binding_import, .. }) if let ImportKind::ExternCrate { id, .. } = binding_import.kind && import.vis.is_public() => { @@ -300,11 +297,7 @@ fn pub_use_of_private_extern_crate_hack( impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Given a binding and an import that resolves to it, /// return the corresponding binding defined by the import. - pub(crate) fn import( - &self, - binding: NameBinding<'ra>, - import: Import<'ra>, - ) -> NameBinding<'ra> { + pub(crate) fn import(&self, binding: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, binding).is_some() @@ -321,8 +314,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { max_vis.set_unchecked(Some(vis.expect_local())) } - self.arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Import { binding, import }, + self.arenas.alloc_name_binding(DeclData { + kind: DeclKind::Import { binding, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -337,9 +330,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: Module<'ra>, ident: Ident, ns: Namespace, - binding: NameBinding<'ra>, + binding: Decl<'ra>, warn_ambiguity: bool, - ) -> Result<(), NameBinding<'ra>> { + ) -> Result<(), Decl<'ra>> { let res = binding.res(); self.check_reserved_macro_name(ident, res); self.set_binding_parent_module(binding, module); @@ -361,9 +354,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (glob_binding, old_glob_binding) = (binding, old_binding); // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. if !binding.is_ambiguity_recursive() - && let NameBindingKind::Import { import: old_import, .. } = + && let DeclKind::Import { import: old_import, .. } = old_glob_binding.kind - && let NameBindingKind::Import { import, .. } = glob_binding.kind + && let DeclKind::Import { import, .. } = glob_binding.kind && old_import == import { // When imported from the same glob-import statement, we should replace @@ -421,18 +414,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn new_ambiguity_binding( &self, - primary_binding: NameBinding<'ra>, - secondary_binding: NameBinding<'ra>, + primary_binding: Decl<'ra>, + secondary_binding: Decl<'ra>, warn_ambiguity: bool, - ) -> NameBinding<'ra> { + ) -> Decl<'ra> { let ambiguity = Some(secondary_binding); - let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; + let data = DeclData { ambiguity, warn_ambiguity, ..*primary_binding }; self.arenas.alloc_name_binding(data) } - fn new_warn_ambiguity_binding(&self, binding: NameBinding<'ra>) -> NameBinding<'ra> { + fn new_warn_ambiguity_binding(&self, binding: Decl<'ra>) -> Decl<'ra> { assert!(binding.is_ambiguity_recursive()); - self.arenas.alloc_name_binding(NameBindingData { warn_ambiguity: true, ..*binding }) + self.arenas.alloc_name_binding(DeclData { warn_ambiguity: true, ..*binding }) } // Use `f` to mutate the resolution of the name in the module. @@ -634,13 +627,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { + pub(crate) fn lint_reexports(&mut self, exported_ambiguities: FxHashSet>) { for module in &self.local_modules { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); let Some(binding) = resolution.best_binding() else { continue }; - if let NameBindingKind::Import { import, .. } = binding.kind + if let DeclKind::Import { import, .. } = binding.kind && let Some(amb_binding) = binding.ambiguity && binding.res() != Res::Err && exported_ambiguities.contains(&binding) @@ -663,8 +656,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { if binding.res() != Res::Err && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = - glob_binding.kind + && let DeclKind::Import { import: glob_import, .. } = glob_binding.kind && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) @@ -672,10 +664,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !binding.vis.is_public() { let binding_id = match binding.kind { - NameBindingKind::Res(res) => { + DeclKind::Def(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Import { import, .. } => import.id(), + DeclKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { self.lint_buffer.buffer_lint( @@ -693,7 +685,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - if let NameBindingKind::Import { import, .. } = binding.kind + if let DeclKind::Import { import, .. } = binding.kind && let Some(binding_id) = import.id() && let import_def_id = self.local_def_id(binding_id) && self.effective_visibilities.is_exported(import_def_id) @@ -1207,11 +1199,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = resolution.borrow(); if let Some(name_binding) = resolution.best_binding() { match name_binding.kind { - NameBindingKind::Import { binding, .. } => { + DeclKind::Import { binding, .. } => { match binding.kind { // Never suggest the name that has binding error // i.e., the name that cannot be previously resolved - NameBindingKind::Res(Res::Err) => None, + DeclKind::Def(Res::Err) => None, _ => Some(i.name), } } @@ -1342,7 +1334,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match binding.kind { - NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id)) + DeclKind::Def(Res::Def(DefKind::Macro(_), def_id)) // exclude decl_macro if self.get_macro_by_def_id(def_id).macro_rules => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0bf6fcba539e..0ec17a2d6d57 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -43,9 +43,9 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, - UseError, Used, errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Decl, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, + ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, + errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1489,7 +1489,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, finalize: Option, - ignore_binding: Option>, + ignore_binding: Option>, ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fbd16072c2c0..a0fda5511048 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -431,7 +431,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { /// forward. #[derive(Debug, Copy, Clone)] enum LexicalScopeBinding<'ra> { - Item(NameBinding<'ra>), + Item(Decl<'ra>), Res(Res), } @@ -624,8 +624,7 @@ struct ModuleData<'ra> { globs: CmRefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: - CmRefCell, Option>)]>>>, + traits: CmRefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -634,7 +633,7 @@ struct ModuleData<'ra> { /// Binding for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - self_binding: Option>, + self_binding: Option>, } /// All modules are unique and allocated on a same arena, @@ -663,7 +662,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, - self_binding: Option>, + self_binding: Option>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -691,7 +690,7 @@ impl<'ra> Module<'ra> { fn for_each_child<'tcx, R: AsRef>>( self, resolver: &R, - mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -703,7 +702,7 @@ impl<'ra> Module<'ra> { fn for_each_child_mut<'tcx, R: AsMut>>( self, resolver: &mut R, - mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, NameBinding<'ra>), + mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { if let Some(binding) = name_resolution.borrow().best_binding() { @@ -803,11 +802,11 @@ impl<'ra> fmt::Debug for Module<'ra> { } } -/// Records a possibly-private value, type, or module definition. +/// Data associated with any name declaration. #[derive(Clone, Copy, Debug)] -struct NameBindingData<'ra> { - kind: NameBindingKind<'ra>, - ambiguity: Option>, +struct DeclData<'ra> { + kind: DeclKind<'ra>, + ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, @@ -816,15 +815,15 @@ struct NameBindingData<'ra> { vis: Visibility, } -/// All name bindings are unique and allocated on a same arena, +/// All name declarations are unique and allocated on a same arena, /// so we can use referential equality to compare them. -type NameBinding<'ra> = Interned<'ra, NameBindingData<'ra>>; +type Decl<'ra> = Interned<'ra, DeclData<'ra>>; // Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the // contained data. // FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees // are upheld. -impl std::hash::Hash for NameBindingData<'_> { +impl std::hash::Hash for DeclData<'_> { fn hash(&self, _: &mut H) where H: std::hash::Hasher, @@ -833,23 +832,27 @@ impl std::hash::Hash for NameBindingData<'_> { } } +/// Name declaration kind. #[derive(Clone, Copy, Debug)] -enum NameBindingKind<'ra> { - Res(Res), - Import { binding: NameBinding<'ra>, import: Import<'ra> }, +enum DeclKind<'ra> { + /// The name declaration is a definition (possibly without a `DefId`), + /// can be provided by source code or built into the language. + Def(Res), + /// The name declaration is a link to another name declaration. + Import { binding: Decl<'ra>, import: Import<'ra> }, } -impl<'ra> NameBindingKind<'ra> { +impl<'ra> DeclKind<'ra> { /// Is this a name binding of an import? fn is_import(&self) -> bool { - matches!(*self, NameBindingKind::Import { .. }) + matches!(*self, DeclKind::Import { .. }) } } #[derive(Debug)] struct PrivacyError<'ra> { ident: Ident, - binding: NameBinding<'ra>, + binding: Decl<'ra>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'ra>, @@ -912,36 +915,34 @@ impl AmbiguityKind { struct AmbiguityError<'ra> { kind: AmbiguityKind, ident: Ident, - b1: NameBinding<'ra>, - b2: NameBinding<'ra>, + b1: Decl<'ra>, + b2: Decl<'ra>, // `empty_module` in module scope serves as an unknown module here. scope1: Scope<'ra>, scope2: Scope<'ra>, warning: bool, } -impl<'ra> NameBindingData<'ra> { +impl<'ra> DeclData<'ra> { fn res(&self) -> Res { match self.kind { - NameBindingKind::Res(res) => res, - NameBindingKind::Import { binding, .. } => binding.res(), + DeclKind::Def(res) => res, + DeclKind::Import { binding, .. } => binding.res(), } } - fn import_source(&self) -> NameBinding<'ra> { + fn import_source(&self) -> Decl<'ra> { match self.kind { - NameBindingKind::Import { binding, .. } => binding, + DeclKind::Import { binding, .. } => binding, _ => unreachable!(), } } - fn descent_to_ambiguity( - self: NameBinding<'ra>, - ) -> Option<(NameBinding<'ra>, NameBinding<'ra>)> { + fn descent_to_ambiguity(self: Decl<'ra>) -> Option<(Decl<'ra>, Decl<'ra>)> { match self.ambiguity { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { - NameBindingKind::Import { binding, .. } => binding.descent_to_ambiguity(), + DeclKind::Import { binding, .. } => binding.descent_to_ambiguity(), _ => None, }, } @@ -950,7 +951,7 @@ impl<'ra> NameBindingData<'ra> { fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_ambiguity_recursive(), + DeclKind::Import { binding, .. } => binding.is_ambiguity_recursive(), _ => false, } } @@ -958,46 +959,45 @@ impl<'ra> NameBindingData<'ra> { fn warn_ambiguity_recursive(&self) -> bool { self.warn_ambiguity || match self.kind { - NameBindingKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), + DeclKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), _ => false, } } fn is_possibly_imported_variant(&self) -> bool { match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), - NameBindingKind::Res(Res::Def( - DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), - _, - )) => true, - NameBindingKind::Res(..) => false, + DeclKind::Import { binding, .. } => binding.is_possibly_imported_variant(), + DeclKind::Def(Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _)) => { + true + } + DeclKind::Def(..) => false, } } fn is_extern_crate(&self) -> bool { match self.kind { - NameBindingKind::Import { import, .. } => { + DeclKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), + DeclKind::Def(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } fn is_import(&self) -> bool { - matches!(self.kind, NameBindingKind::Import { .. }) + matches!(self.kind, DeclKind::Import { .. }) } /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might /// not be perceived as such by users, so treat it as a non-import in some diagnostics. fn is_import_user_facing(&self) -> bool { - matches!(self.kind, NameBindingKind::Import { import, .. } + matches!(self.kind, DeclKind::Import { import, .. } if !matches!(import.kind, ImportKind::MacroExport)) } fn is_glob_import(&self) -> bool { match self.kind { - NameBindingKind::Import { import, .. } => import.is_glob(), + DeclKind::Import { import, .. } => import.is_glob(), _ => false, } } @@ -1010,10 +1010,10 @@ impl<'ra> NameBindingData<'ra> { self.res().macro_kinds() } - fn reexport_chain(self: NameBinding<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { + fn reexport_chain(self: Decl<'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 { + while let DeclKind::Import { binding, import, .. } = next_binding.kind { reexport_chain.push(import.simplify(r)); next_binding = binding; } @@ -1026,11 +1026,7 @@ impl<'ra> NameBindingData<'ra> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after( - &self, - invoc_parent_expansion: LocalExpnId, - binding: NameBinding<'_>, - ) -> bool { + fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, binding: Decl<'_>) -> bool { // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. @@ -1048,7 +1044,7 @@ impl<'ra> NameBindingData<'ra> { // FIXME: How can we integrate it with the `update_resolution`? fn determined(&self) -> bool { match &self.kind { - NameBindingKind::Import { binding, import, .. } if import.is_glob() => { + DeclKind::Import { binding, import, .. } if import.is_glob() => { import.parent_scope.module.unexpanded_invocations.borrow().is_empty() && binding.determined() } @@ -1061,7 +1057,7 @@ struct ExternPreludeEntry<'ra> { /// Binding from an `extern crate` item. /// The boolean flag is true is `item_binding` is non-redundant, happens either when /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. - item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>, + item_binding: Option<(Decl<'ra>, /* introduced by item */ bool)>, /// Binding from an `--extern` flag, lazily populated on first use. flag_binding: Option, /* finalized */ bool)>>, } @@ -1181,7 +1177,7 @@ pub struct Resolver<'ra, 'tcx> { local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. extern_module_map: CacheRefCell>>, - binding_parent_modules: FxHashMap, Module<'ra>>, + binding_parent_modules: FxHashMap, Module<'ra>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1206,14 +1202,14 @@ pub struct Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: FxHashMap, arenas: &'ra ResolverArenas<'ra>, - dummy_binding: NameBinding<'ra>, - builtin_types_bindings: FxHashMap>, - builtin_attrs_bindings: FxHashMap>, - registered_tool_bindings: FxHashMap>, + dummy_binding: Decl<'ra>, + builtin_types_bindings: FxHashMap>, + builtin_attrs_bindings: FxHashMap>, + registered_tool_bindings: FxHashMap>, macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxIndexMap>, + macro_use_prelude: FxIndexMap>, /// Eagerly populated map of all local macro definitions. local_macro_map: FxHashMap, /// Lazily populated cache of macro definitions loaded from external crates. @@ -1229,7 +1225,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - CmRefCell, Option>, Option)>>, + CmRefCell, Option>, Option)>>, multi_segment_macro_resolutions: CmRefCell, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, @@ -1246,7 +1242,7 @@ pub struct Resolver<'ra, 'tcx> { /// `macro_rules` scopes produced by `macro_rules` item definitions. macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap)>>, + helper_attrs: FxHashMap)>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. derive_data: FxHashMap, @@ -1344,9 +1340,9 @@ impl<'ra> ResolverArenas<'ra> { vis: Visibility, span: Span, expansion: LocalExpnId, - ) -> NameBinding<'ra> { - self.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(res), + ) -> Decl<'ra> { + self.alloc_name_binding(DeclData { + kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: false, vis, @@ -1355,12 +1351,7 @@ impl<'ra> ResolverArenas<'ra> { }) } - fn new_pub_res_binding( - &'ra self, - res: Res, - span: Span, - expn_id: LocalExpnId, - ) -> NameBinding<'ra> { + fn new_pub_res_binding(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { self.new_res_binding(res, Visibility::Public, span, expn_id) } @@ -1387,7 +1378,7 @@ impl<'ra> ResolverArenas<'ra> { self_binding, )))) } - fn alloc_name_binding(&'ra self, name_binding: NameBindingData<'ra>) -> NameBinding<'ra> { + fn alloc_name_binding(&'ra self, name_binding: DeclData<'ra>) -> Decl<'ra> { Interned::new_unchecked(self.dropless.alloc(name_binding)) } fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { @@ -1994,11 +1985,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn find_transitive_imports( &mut self, - mut kind: &NameBindingKind<'_>, + mut kind: &DeclKind<'_>, trait_name: Ident, ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; - while let NameBindingKind::Import { import, binding, .. } = kind { + while let DeclKind::Import { import, binding, .. } = kind { if let Some(node_id) = import.id() { let def_id = self.local_def_id(node_id); self.maybe_unused_trait_imports.insert(def_id); @@ -2053,14 +2044,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false } - fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'ra>, used: Used) { + fn record_use(&mut self, ident: Ident, used_binding: Decl<'ra>, used: Used) { self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity); } fn record_use_inner( &mut self, ident: Ident, - used_binding: NameBinding<'ra>, + used_binding: Decl<'ra>, used: Used, warn_ambiguity: bool, ) { @@ -2079,7 +2070,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let NameBindingKind::Import { import, binding } = used_binding.kind { + if let DeclKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2236,7 +2227,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: NameBinding<'ra>, module: Module<'ra>) { + fn set_binding_parent_module(&mut self, binding: Decl<'ra>, module: Module<'ra>) { if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { if module != old_module { span_bug!(binding.span, "parent module is reset for binding"); @@ -2246,8 +2237,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn disambiguate_macro_rules_vs_modularized( &self, - macro_rules: NameBinding<'ra>, - modularized: NameBinding<'ra>, + macro_rules: Decl<'ra>, + modularized: Decl<'ra>, ) -> bool { // Some non-controversial subset of ambiguities "modularized macro name" vs "macro_rules" // is disambiguated to mitigate regressions from macro modularization. @@ -2266,7 +2257,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut self: CmResolver<'r, 'ra, 'tcx>, ident: Ident, finalize: bool, - ) -> Option> { + ) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { if finalize { @@ -2276,7 +2267,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { + fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { let (pending_binding, finalized) = flag_binding.get(); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6bba985d87dd..07dd5d8fc889 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -38,9 +38,9 @@ use crate::errors::{ }; use crate::imports::Import; use crate::{ - BindingKey, CacheCell, CmResolver, DeriveData, Determinacy, Finalize, InvocationParent, - MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, - PathResult, ResolutionError, Resolver, ScopeSet, Segment, Used, + BindingKey, CacheCell, CmResolver, Decl, DeclKind, DeriveData, Determinacy, Finalize, + InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, + ResolutionError, Resolver, ScopeSet, Segment, Used, }; type Res = def::Res; @@ -49,7 +49,7 @@ type Res = def::Res; /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] pub(crate) struct MacroRulesBinding<'ra> { - pub(crate) binding: NameBinding<'ra>, + pub(crate) binding: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, pub(crate) ident: Ident, @@ -1062,7 +1062,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option>, + binding: Option>, res: Option, span: Span, ) { @@ -1084,12 +1084,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, + binding: Option>, ) { if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr && let Some(binding) = binding // This is a `macro_rules` itself, not some import. - && let NameBindingKind::Res(res) = binding.kind + && let DeclKind::Def(res) = binding.kind && let Res::Def(DefKind::Macro(kinds), def_id) = res && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, From 7a34af2f67bde4d4ab067c5a41c2b388adfc9531 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:36:30 +0300 Subject: [PATCH 171/340] resolve: Rename `LexicalScopeBinding::(Item,Res)` to `LateDecl::(Decl,RibDef)` --- compiler/rustc_resolve/src/check_unused.rs | 4 ++-- compiler/rustc_resolve/src/diagnostics.rs | 13 +++++----- compiler/rustc_resolve/src/ident.rs | 17 +++++++------ compiler/rustc_resolve/src/late.rs | 28 +++++++++++----------- compiler/rustc_resolve/src/lib.rs | 21 ++++++++-------- 5 files changed, 40 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index b7705773041f..a2e903ce48eb 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -36,7 +36,7 @@ use rustc_session::lint::builtin::{ use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{DeclKind, LexicalScopeBinding, Resolver, module_to_string}; +use crate::{DeclKind, LateDecl, Resolver, module_to_string}; struct UnusedImport { use_tree: ast::UseTree, @@ -542,7 +542,7 @@ impl Resolver<'_, '_> { // Deleting both unused imports and unnecessary segments of an item may result // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { - if let LexicalScopeBinding::Item(name_binding) = unn_qua.binding + if let LateDecl::Decl(name_binding) = unn_qua.binding && let DeclKind::Import { import, .. } = name_binding.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7e78f66574ed..99812fe4df53 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -45,10 +45,9 @@ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityKind, BindingError, BindingKey, Decl, DeclKind, Finalize, - ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, - ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, - Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, - path_names_to_string, + ForwardGenericParamBanReason, HasGenericParams, LateDecl, MacroRulesScope, Module, ModuleKind, + ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError, Resolver, Scope, + ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs, path_names_to_string, }; type Res = def::Res; @@ -2528,7 +2527,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ) { // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Some(binding), + Some(LateDecl::Decl(binding)) => Some(binding), _ => None, } } else { @@ -2590,7 +2589,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // // variable `Foo`. // } // ``` - Some(LexicalScopeBinding::Res(Res::Local(id))) => { + Some(LateDecl::RibDef(Res::Local(id))) => { Some(*self.pat_span_map.get(&id).unwrap()) } // Name matches item from a local name binding @@ -2604,7 +2603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // // binding `Foo`. // } // ``` - Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span), + Some(LateDecl::Decl(name_binding)) => Some(name_binding.span), _ => None, }; let suggestion = match_span.map(|span| { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7ebc75abca89..a6a8545ac69e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -20,9 +20,8 @@ use crate::late::{ use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, - ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, - PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, - Used, errors, + ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, + PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, Stage, Used, errors, }; #[derive(Copy, Clone)] @@ -307,7 +306,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ribs: &[Rib<'ra>], ignore_binding: Option>, diag_metadata: Option<&DiagMetadata<'_>>, - ) -> Option> { + ) -> Option> { let orig_ident = ident; let (general_span, normalized_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene @@ -330,7 +329,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident }; if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( + return Some(LateDecl::RibDef(self.validate_res_from_ribs( i, rib_ident, *res, @@ -351,7 +350,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { // The ident resolves to an item in a block. - return Some(LexicalScopeBinding::Item(binding)); + return Some(LateDecl::Decl(binding)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. let parent_scope = &ParentScope { module, ..*parent_scope }; @@ -368,7 +367,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ) .ok() - .map(LexicalScopeBinding::Item); + .map(LateDecl::Decl); } if let RibKind::MacroDefinition(def) = rib.kind @@ -1836,9 +1835,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ) { // we found a locally-imported or available item/module - Some(LexicalScopeBinding::Item(binding)) => Ok(binding), + Some(LateDecl::Decl(binding)) => Ok(binding), // we found a local variable or type param - Some(LexicalScopeBinding::Res(res)) => { + Some(LateDecl::RibDef(res)) => { record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0ec17a2d6d57..2685efa28b64 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -43,9 +43,9 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Decl, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - ParentScope, PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, - errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Decl, Finalize, LateDecl, Module, ModuleOrUniformRoot, ParentScope, + PathResult, ResolutionError, Resolver, Segment, Stage, TyCtxt, UseError, Used, errors, + path_names_to_string, rustdoc, }; mod diagnostics; @@ -677,7 +677,7 @@ impl MaybeExported<'_> { /// Used for recording UnnecessaryQualification. #[derive(Debug)] pub(crate) struct UnnecessaryQualification<'ra> { - pub binding: LexicalScopeBinding<'ra>, + pub binding: LateDecl<'ra>, pub node_id: NodeId, pub path_span: Span, pub removal_span: Span, @@ -1472,7 +1472,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, ident: Ident, ns: Namespace, - ) -> Option> { + ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -1490,7 +1490,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ns: Namespace, finalize: Option, ignore_binding: Option>, - ) -> Option> { + ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, ns, @@ -2685,11 +2685,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for &ns in nss { match self.maybe_resolve_ident_in_lexical_scope(ident, ns) { - Some(LexicalScopeBinding::Res(..)) => { + Some(LateDecl::RibDef(..)) => { report_error(self, ns); } - Some(LexicalScopeBinding::Item(binding)) => { - if let Some(LexicalScopeBinding::Res(..)) = + Some(LateDecl::Decl(binding)) => { + if let Some(LateDecl::RibDef(..)) = self.resolve_ident_in_lexical_scope(ident, ns, None, Some(binding)) { report_error(self, ns); @@ -4257,7 +4257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { - LexicalScopeBinding::Item(binding) + LateDecl::Decl(binding) if is_syntactic_ambiguity && binding.is_ambiguity_recursive() => { // For ambiguous bindings we don't know all their definitions and cannot check @@ -4267,8 +4267,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.r.record_use(ident, binding, Used::Other); return None; } - LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)), - LexicalScopeBinding::Res(res) => (res, None), + LateDecl::Decl(binding) => (binding.res(), Some(binding)), + LateDecl::RibDef(res) => (res, None), }; match res { @@ -4641,13 +4641,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn self_type_is_available(&mut self) -> bool { let binding = self .maybe_resolve_ident_in_lexical_scope(Ident::with_dummy_span(kw::SelfUpper), TypeNS); - if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + if let Some(LateDecl::RibDef(res)) = binding { res != Res::Err } else { false } } fn self_value_is_available(&mut self, self_span: Span) -> bool { let ident = Ident::new(kw::SelfLower, self_span); let binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS); - if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } + if let Some(LateDecl::RibDef(res)) = binding { res != Res::Err } else { false } } /// A wrapper around [`Resolver::report_error`]. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a0fda5511048..8982ec15de8f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -424,22 +424,21 @@ impl<'a> From<&'a ast::PathSegment> for Segment { } } -/// An intermediate resolution result. -/// -/// This refers to the thing referred by a name. The difference between `Res` and `Item` is that -/// items are visible in their whole block, while `Res`es only from the place they are defined -/// forward. +/// Name declaration used during late resolution. #[derive(Debug, Copy, Clone)] -enum LexicalScopeBinding<'ra> { - Item(Decl<'ra>), - Res(Res), +enum LateDecl<'ra> { + /// A regular name declaration. + Decl(Decl<'ra>), + /// A name definition from a rib, e.g. a local variable. + /// Omits most of the data from regular `Decl` for performance reasons. + RibDef(Res), } -impl<'ra> LexicalScopeBinding<'ra> { +impl<'ra> LateDecl<'ra> { fn res(self) -> Res { match self { - LexicalScopeBinding::Item(binding) => binding.res(), - LexicalScopeBinding::Res(res) => res, + LateDecl::Decl(binding) => binding.res(), + LateDecl::RibDef(res) => res, } } } From 844e085de69c4d17cc21cbfda08d58caa286fa49 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 20:47:03 +0300 Subject: [PATCH 172/340] resolve: `MacroRulesScope::Binding` -> `MacroRulesScope::Def` `MacroRulesBinding` -> `MacroRulesDef` --- compiler/rustc_resolve/src/build_reduced_graph.rs | 6 +++--- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 6 ++---- compiler/rustc_resolve/src/lib.rs | 6 +++--- compiler/rustc_resolve/src/macros.rs | 6 +++--- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d31723844290..d23e86273e52 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -33,7 +33,7 @@ use tracing::debug; use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; -use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, MacroData, Module, @@ -1326,8 +1326,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.insert_unused_macro(ident, def_id, item.id); } self.r.feed_visibility(feed, vis); - let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( - self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding { + let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( + self.r.arenas.alloc_macro_rules_binding(MacroRulesDecl { parent_macro_rules_scope: parent_scope.macro_rules, binding, ident, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 99812fe4df53..21328b39623e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1195,7 +1195,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { - if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { + if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { let res = macro_rules_binding.binding.res(); if filter_fn(res) { suggestions.push(TypoSuggestion::typo_from_ident( diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index a6a8545ac69e..7438403a4745 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -182,7 +182,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(binding) => { + MacroRulesScope::Def(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } MacroRulesScope::Invocation(invoc_id) => { @@ -559,9 +559,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(macro_rules_binding) - if ident == macro_rules_binding.ident => - { + MacroRulesScope::Def(macro_rules_binding) if ident == macro_rules_binding.ident => { Ok(macro_rules_binding.binding) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8982ec15de8f..ea13125f5417 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -38,7 +38,7 @@ use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, }; -use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; +use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{ @@ -1391,8 +1391,8 @@ impl<'ra> ResolverArenas<'ra> { } fn alloc_macro_rules_binding( &'ra self, - binding: MacroRulesBinding<'ra>, - ) -> &'ra MacroRulesBinding<'ra> { + binding: MacroRulesDecl<'ra>, + ) -> &'ra MacroRulesDecl<'ra> { self.dropless.alloc(binding) } fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 07dd5d8fc889..e07bb46ac568 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -45,10 +45,10 @@ use crate::{ type Res = def::Res; -/// Binding produced by a `macro_rules` item. +/// Name declaration produced by a `macro_rules` item definition. /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] -pub(crate) struct MacroRulesBinding<'ra> { +pub(crate) struct MacroRulesDecl<'ra> { pub(crate) binding: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, @@ -65,7 +65,7 @@ pub(crate) enum MacroRulesScope<'ra> { /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. - Binding(&'ra MacroRulesBinding<'ra>), + Def(&'ra MacroRulesDecl<'ra>), /// The scope introduced by a macro invocation that can potentially /// create a `macro_rules!` macro definition. Invocation(LocalExpnId), From a67e289b4d9f0aaf3fef25a819b42a58536474c0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 21:32:07 +0300 Subject: [PATCH 173/340] Update some function names and fields from bindings to declarations --- .../rustc_resolve/src/build_reduced_graph.rs | 52 +++---- compiler/rustc_resolve/src/diagnostics.rs | 12 +- .../src/effective_visibilities.rs | 22 +-- compiler/rustc_resolve/src/ident.rs | 18 +-- compiler/rustc_resolve/src/imports.rs | 90 ++++++------- compiler/rustc_resolve/src/lib.rs | 127 +++++++++--------- compiler/rustc_resolve/src/macros.rs | 18 ++- 7 files changed, 167 insertions(+), 172 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d23e86273e52..7569fc3d716b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -51,10 +51,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent: Module<'ra>, ident: Ident, ns: Namespace, - binding: Decl<'ra>, + decl: Decl<'ra>, ) { - if let Err(old_binding) = self.try_define_local(parent, ident, ns, binding, false) { - self.report_conflict(parent, ident, ns, old_binding, binding); + if let Err(old_binding) = self.try_define_local(parent, ident, ns, decl, false) { + self.report_conflict(parent, ident, ns, old_binding, decl); } } @@ -68,7 +68,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, expn_id: LocalExpnId, ) { - let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); + let binding = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); self.define_binding_local(parent, ident, ns, binding); } @@ -84,7 +84,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expansion: LocalExpnId, ambiguity: Option>, ) { - let binding = self.arenas.alloc_name_binding(DeclData { + let binding = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. @@ -284,7 +284,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child; let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); - self.arenas.new_res_binding(res, vis, span, expansion) + self.arenas.new_def_decl(res, vis, span, expansion) }); // Record primary definitions. @@ -977,7 +977,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; - let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower { + let (used, module, decl) = if orig_name.is_none() && ident.name == kw::SelfLower { self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp }); return; } else if orig_name == Some(kw::SelfLower) { @@ -997,10 +997,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); - (used, Some(ModuleOrUniformRoot::Module(module)), binding) + let decl = self.r.arenas.new_pub_def_decl(module.res().unwrap(), sp, expansion); + (used, Some(ModuleOrUniformRoot::Module(module)), decl) }) - .unwrap_or((true, None, self.r.dummy_binding)); + .unwrap_or((true, None, self.r.dummy_decl)); let import = self.r.arenas.alloc_import(ImportData { kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, @@ -1019,7 +1019,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.import_use_map.insert(import, Used::Other); } self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(binding, import); + let imported_binding = self.r.import(decl, import); if ident.name != kw::Underscore && parent == self.r.graph_root { let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into @@ -1027,7 +1027,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() - && entry.item_binding.is_none() + && entry.item_decl.is_none() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, @@ -1038,17 +1038,17 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { match self.r.extern_prelude.entry(norm_ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); - if entry.item_binding.is_some() { + if entry.item_decl.is_some() { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_binding = Some((imported_binding, orig_name.is_some())); + entry.item_decl = Some((imported_binding, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_binding: Some((imported_binding, true)), - flag_binding: None, + item_decl: Some((imported_binding, true)), + flag_decl: None, }), }; } @@ -1089,14 +1089,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } - fn add_macro_use_binding( + fn add_macro_use_decl( &mut self, name: Symbol, - binding: Decl<'ra>, + decl: Decl<'ra>, span: Span, allow_shadowing: bool, ) { - if self.r.macro_use_prelude.insert(name, binding).is_some() && !allow_shadowing { + if self.r.macro_use_prelude.insert(name, decl).is_some() && !allow_shadowing { self.r.dcx().emit_err(errors::MacroUseNameAlreadyInUse { span, name }); } } @@ -1168,7 +1168,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { macro_use_import(this, span, true) }; let import_binding = this.r.import(binding, import); - this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing); + this.add_macro_use_decl(ident.name, import_binding, span, allow_shadowing); } }); } else { @@ -1184,7 +1184,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let import = macro_use_import(self, ident.span, false); self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - self.add_macro_use_binding( + self.add_macro_use_decl( ident.name, imported_binding, ident.span, @@ -1300,8 +1300,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else { Visibility::Restricted(CRATE_DEF_ID) }; - let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); - self.r.set_binding_parent_module(binding, parent_scope.module); + let decl = self.r.arenas.new_def_decl(res, vis.to_def_id(), span, expansion); + self.r.set_decl_parent_module(decl, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { let import = self.r.arenas.alloc_import(ImportData { @@ -1319,7 +1319,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); - let import_binding = self.r.import(binding, import); + let import_binding = self.r.import(decl, import); self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); @@ -1327,9 +1327,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.feed_visibility(feed, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( - self.r.arenas.alloc_macro_rules_binding(MacroRulesDecl { + self.r.arenas.alloc_macro_rules_decl(MacroRulesDecl { parent_macro_rules_scope: parent_scope.macro_rules, - binding, + decl, ident, }), )); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 21328b39623e..b77481d1b3ad 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1196,7 +1196,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::MacroRules(macro_rules_scope) => { if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { - let res = macro_rules_binding.binding.res(); + let res = macro_rules_binding.decl.res(); if filter_fn(res) { suggestions.push(TypoSuggestion::typo_from_ident( macro_rules_binding.ident, @@ -1969,7 +1969,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } - fn binding_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { + fn decl_description(&self, b: Decl<'_>, ident: Ident, scope: Scope<'_>) -> String { let res = b.res(); if b.span.is_dummy() || !self.tcx.sess.source_map().is_span_accessible(b.span) { let (built_in, from) = match scope { @@ -2005,7 +2005,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && self .extern_prelude .get(&Macros20NormalizedIdent::new(ident)) - .is_some_and(|entry| entry.item_binding.map(|(b, _)| b) == Some(b1)) + .is_some_and(|entry| entry.item_decl.map(|(b, _)| b) == Some(b1)) }; let (b1, b2, scope1, scope2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. @@ -2015,7 +2015,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let could_refer_to = |b: Decl<'_>, scope: Scope<'ra>, also: &str| { - let what = self.binding_description(b, ident, scope); + let what = self.decl_description(b, ident, scope); let note_msg = format!("`{ident}` could{also} refer to {what}"); let thing = b.res().descr(); @@ -2073,9 +2073,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. - fn ctor_fields_span(&self, binding: Decl<'_>) -> Option { + fn ctor_fields_span(&self, decl: Decl<'_>) -> Option { let DeclKind::Def(Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id)) = - binding.kind + decl.kind else { return None; }; diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 5d78f3752439..389bdbbec62b 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -42,8 +42,8 @@ impl Resolver<'_, '_> { self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local() } - fn private_vis_import(&self, binding: Decl<'_>) -> Visibility { - let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; + fn private_vis_import(&self, decl: Decl<'_>) -> Visibility { + let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; Visibility::Restricted( import .id() @@ -94,14 +94,14 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based // information, but are used by later passes. Effective visibility of an import def id // is the maximum value among visibilities of bindings corresponding to that def id. - for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { - let DeclKind::Import { import, .. } = binding.kind else { unreachable!() }; - if !binding.is_ambiguity_recursive() { + for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { + let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; + if !decl.is_ambiguity_recursive() { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) } - } else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { - exported_ambiguities.insert(*binding); + } else if decl.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + exported_ambiguities.insert(*decl); } } @@ -188,15 +188,15 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } } - fn update_import(&mut self, binding: Decl<'ra>, parent_id: ParentId<'ra>) { - let nominal_vis = binding.vis.expect_local(); + fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>) { + let nominal_vis = decl.vis.expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( - binding, + decl, Some(nominal_vis), - || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), + || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(decl)), inherited_eff_vis, parent_id.level(), tcx, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7438403a4745..a5d9c1bae74f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -543,7 +543,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = self.arenas.new_pub_res_binding( + let binding = self.arenas.new_pub_def_decl( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), derive.span, LocalExpnId::ROOT, @@ -559,8 +559,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Def(macro_rules_binding) if ident == macro_rules_binding.ident => { - Ok(macro_rules_binding.binding) + MacroRulesScope::Def(macro_rules_def) if ident == macro_rules_def.ident => { + Ok(macro_rules_def.decl) } MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), @@ -671,7 +671,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, - Scope::BuiltinAttrs => match self.builtin_attrs_bindings.get(&ident.name) { + Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) { Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, @@ -689,7 +689,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), } } - Scope::ToolPrelude => match self.registered_tool_bindings.get(&ident) { + Scope::ToolPrelude => match self.registered_tool_decls.get(&ident) { Some(binding) => Ok(*binding), None => Err(Determinacy::Determined), }, @@ -713,7 +713,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { result } - Scope::BuiltinTypes => match self.builtin_types_bindings.get(&ident.name) { + Scope::BuiltinTypes => match self.builtin_type_decls.get(&ident.name) { Some(binding) => { if matches!(ident.name, sym::f16) && !self.tcx.features().f16() @@ -959,7 +959,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - return Ok(module.self_binding.unwrap()); + return Ok(module.self_decl.unwrap()); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. @@ -1287,9 +1287,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { unreachable!(); }; if source != target { - if bindings.iter().all(|binding| binding.get().binding().is_none()) { + if bindings.iter().all(|binding| binding.get().decl().is_none()) { return true; - } else if bindings[ns].get().binding().is_none() && binding.is_some() { + } else if bindings[ns].get().decl().is_none() && binding.is_some() { return true; } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7648b980ec5c..4f8877401638 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -39,19 +39,20 @@ use crate::{ type Res = def::Res; -/// A [`Decl`] in the process of being resolved. +/// A potential import declaration in the process of being planted into a module. +/// Also used for lazily planting names from `--extern` flags to extern prelude. #[derive(Clone, Copy, Default, PartialEq)] -pub(crate) enum PendingBinding<'ra> { +pub(crate) enum PendingDecl<'ra> { Ready(Option>), #[default] Pending, } -impl<'ra> PendingBinding<'ra> { - pub(crate) fn binding(self) -> Option> { +impl<'ra> PendingDecl<'ra> { + pub(crate) fn decl(self) -> Option> { match self { - PendingBinding::Ready(binding) => binding, - PendingBinding::Pending => None, + PendingDecl::Ready(decl) => decl, + PendingDecl::Pending => None, } } } @@ -66,7 +67,7 @@ pub(crate) enum ImportKind<'ra> { /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings introduced by the import. - bindings: PerNS>>, + bindings: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -116,7 +117,7 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { // Ignore the nested bindings to avoid an infinite loop while printing. .field( "bindings", - &bindings.clone().map(|b| b.into_inner().binding().map(|_| format_args!(".."))), + &bindings.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -282,10 +283,10 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: Decl<'_>) -> Option { - match (&import.kind, &binding.kind) { - (ImportKind::Single { .. }, DeclKind::Import { import: binding_import, .. }) - if let ImportKind::ExternCrate { id, .. } = binding_import.kind +fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> Option { + match (&import.kind, &decl.kind) { + (ImportKind::Single { .. }, DeclKind::Import { import: decl_import, .. }) + if let ImportKind::ExternCrate { id, .. } = decl_import.kind && import.vis.is_public() => { Some(id) @@ -314,7 +315,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { max_vis.set_unchecked(Some(vis.expect_local())) } - self.arenas.alloc_name_binding(DeclData { + self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { binding, import }, ambiguity: None, warn_ambiguity: false, @@ -335,7 +336,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Result<(), Decl<'ra>> { let res = binding.res(); self.check_reserved_macro_name(ident, res); - self.set_binding_parent_module(binding, module); + self.set_decl_parent_module(binding, module); // 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. @@ -364,7 +365,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // they have the same resolution or not. resolution.glob_binding = Some(glob_binding); } else if res != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_ambiguity_binding( + resolution.glob_binding = Some(this.new_decl_with_ambiguity( old_glob_binding, glob_binding, warn_ambiguity, @@ -374,7 +375,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.glob_binding = Some(glob_binding); } else if binding.is_ambiguity_recursive() { resolution.glob_binding = - Some(this.new_warn_ambiguity_binding(glob_binding)); + Some(this.new_decl_with_warn_ambiguity(glob_binding)); } } (old_glob @ true, false) | (old_glob @ false, true) => { @@ -384,7 +385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(old_glob_binding) = resolution.glob_binding { assert!(old_glob_binding.is_glob_import()); if glob_binding.res() != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_ambiguity_binding( + resolution.glob_binding = Some(this.new_decl_with_ambiguity( old_glob_binding, glob_binding, false, @@ -412,20 +413,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn new_ambiguity_binding( + fn new_decl_with_ambiguity( &self, - primary_binding: Decl<'ra>, - secondary_binding: Decl<'ra>, + primary_decl: Decl<'ra>, + secondary_decl: Decl<'ra>, warn_ambiguity: bool, ) -> Decl<'ra> { - let ambiguity = Some(secondary_binding); - let data = DeclData { ambiguity, warn_ambiguity, ..*primary_binding }; - self.arenas.alloc_name_binding(data) + let ambiguity = Some(secondary_decl); + let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; + self.arenas.alloc_decl(data) } - fn new_warn_ambiguity_binding(&self, binding: Decl<'ra>) -> Decl<'ra> { - assert!(binding.is_ambiguity_recursive()); - self.arenas.alloc_name_binding(DeclData { warn_ambiguity: true, ..*binding }) + fn new_decl_with_warn_ambiguity(&self, decl: Decl<'ra>) -> Decl<'ra> { + assert!(decl.is_ambiguity_recursive()); + self.arenas.alloc_decl(DeclData { warn_ambiguity: true, ..*decl }) } // Use `f` to mutate the resolution of the name in the module. @@ -488,16 +489,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { if let ImportKind::Single { target, ref bindings, .. } = import.kind { - if !(is_indeterminate - || bindings.iter().all(|binding| binding.get().binding().is_none())) + if !(is_indeterminate || bindings.iter().all(|binding| binding.get().decl().is_none())) { return; // Has resolution, do not create the dummy binding } - let dummy_binding = self.dummy_binding; - let dummy_binding = self.import(dummy_binding, import); + let dummy_decl = self.dummy_decl; + let dummy_decl = self.import(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = this.try_define_local(module, target, ns, dummy_binding, false); + let _ = this.try_define_local(module, target, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -506,7 +506,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } }); - self.record_use(target, dummy_binding, Used::Other); + self.record_use(target, dummy_decl, Used::Other); } else if import.imported_module.get().is_none() { self.import_use_map.insert(import, Used::Other); if let Some(id) = import.id() { @@ -577,7 +577,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let ImportKind::Single { source, ref bindings, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let PendingBinding::Ready(None) = bindings.value_ns.get() + && let PendingDecl::Ready(None) = bindings.value_ns.get() { continue; } @@ -851,7 +851,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate_count = 0; self.per_ns_cm(|this, ns| { if !type_ns_only || ns == TypeNS { - if bindings[ns].get() != PendingBinding::Pending { + if bindings[ns].get() != PendingDecl::Pending { return; }; let binding_result = this.reborrow().maybe_resolve_ident_in_module( @@ -883,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, imported_binding, ); - PendingBinding::Ready(Some(imported_binding)) + PendingDecl::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. @@ -898,11 +898,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - PendingBinding::Ready(None) + PendingDecl::Ready(None) } Err(Determinacy::Undetermined) => { indeterminate_count += 1; - PendingBinding::Pending + PendingDecl::Pending } }; bindings[ns].set_unchecked(binding); @@ -918,7 +918,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option { let ignore_binding = match &import.kind { - ImportKind::Single { bindings, .. } => bindings[TypeNS].get().binding(), + ImportKind::Single { bindings, .. } => bindings[TypeNS].get().decl(), _ => None, }; let ambiguity_errors_len = @@ -1113,14 +1113,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &import.parent_scope, Some(Finalize { report_private: false, ..finalize }), - bindings[ns].get().binding(), + bindings[ns].get().decl(), Some(import), ); match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - let initial_res = bindings[ns].get().binding().map(|binding| { + let initial_res = bindings[ns].get().decl().map(|binding| { let initial_binding = binding.import_source(); all_ns_err = false; if target.name == kw::Underscore @@ -1287,7 +1287,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) else { + let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) else { return; }; @@ -1362,7 +1362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { - if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { + if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } }); @@ -1372,7 +1372,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| { - if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { + if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1410,7 +1410,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - let binding = bindings[ns].get().binding().map(|b| b.import_source()); + let binding = bindings[ns].get().decl().map(|b| b.import_source()); if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; @@ -1422,7 +1422,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - bindings[ns].get().binding(), + bindings[ns].get().decl(), None, ) { Ok(other_binding) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ea13125f5417..67449050aea9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -33,7 +33,7 @@ use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use effective_visibilities::EffectiveVisibilitiesVisitor; use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use imports::{Import, ImportData, ImportKind, NameResolution, PendingBinding}; +use imports::{Import, ImportData, ImportKind, NameResolution, PendingDecl}; use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, @@ -630,9 +630,9 @@ struct ModuleData<'ra> { expansion: ExpnId, - /// Binding for implicitly declared names that come with a module, + /// Declaration for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). - self_binding: Option>, + self_decl: Option>, } /// All modules are unique and allocated on a same arena, @@ -661,7 +661,7 @@ impl<'ra> ModuleData<'ra> { expansion: ExpnId, span: Span, no_implicit_prelude: bool, - self_binding: Option>, + self_decl: Option>, ) -> Self { let is_foreign = match kind { ModuleKind::Def(_, def_id, _) => !def_id.is_local(), @@ -680,7 +680,7 @@ impl<'ra> ModuleData<'ra> { traits: CmRefCell::new(None), span, expansion, - self_binding, + self_decl, } } } @@ -1025,12 +1025,12 @@ impl<'ra> DeclData<'ra> { // in some later round and screw up our previously found resolution. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, binding: Decl<'_>) -> bool { - // self > max(invoc, binding) => !(self <= invoc || self <= binding) + fn may_appear_after(&self, invoc_parent_expansion: LocalExpnId, decl: Decl<'_>) -> bool { + // self > max(invoc, decl) => !(self <= invoc || self <= decl) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. let self_parent_expansion = self.expansion; - let other_parent_expansion = binding.expansion; + let other_parent_expansion = decl.expansion; let certainly_before_other_or_simultaneously = other_parent_expansion.is_descendant_of(self_parent_expansion); let certainly_before_invoc_or_simultaneously = @@ -1053,23 +1053,23 @@ impl<'ra> DeclData<'ra> { } struct ExternPreludeEntry<'ra> { - /// Binding from an `extern crate` item. - /// The boolean flag is true is `item_binding` is non-redundant, happens either when - /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. - item_binding: Option<(Decl<'ra>, /* introduced by item */ bool)>, - /// Binding from an `--extern` flag, lazily populated on first use. - flag_binding: Option, /* finalized */ bool)>>, + /// Name declaration from an `extern crate` item. + /// The boolean flag is true is `item_decl` is non-redundant, happens either when + /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming. + item_decl: Option<(Decl<'ra>, /* introduced by item */ bool)>, + /// Name declaration from an `--extern` flag, lazily populated on first use. + flag_decl: Option, /* finalized */ bool)>>, } impl ExternPreludeEntry<'_> { fn introduced_by_item(&self) -> bool { - matches!(self.item_binding, Some((_, true))) + matches!(self.item_decl, Some((_, true))) } fn flag() -> Self { ExternPreludeEntry { - item_binding: None, - flag_binding: Some(CacheCell::new((PendingBinding::Pending, false))), + item_decl: None, + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))), } } } @@ -1176,7 +1176,7 @@ pub struct Resolver<'ra, 'tcx> { local_module_map: FxIndexMap>, /// Lazily populated cache of modules loaded from external crates. extern_module_map: CacheRefCell>>, - binding_parent_modules: FxHashMap, Module<'ra>>, + decl_parent_modules: FxHashMap, Module<'ra>>, /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, @@ -1201,10 +1201,10 @@ pub struct Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: FxHashMap, arenas: &'ra ResolverArenas<'ra>, - dummy_binding: Decl<'ra>, - builtin_types_bindings: FxHashMap>, - builtin_attrs_bindings: FxHashMap>, - registered_tool_bindings: FxHashMap>, + dummy_decl: Decl<'ra>, + builtin_type_decls: FxHashMap>, + builtin_attr_decls: FxHashMap>, + registered_tool_decls: FxHashMap>, macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, @@ -1333,14 +1333,14 @@ pub struct ResolverArenas<'ra> { } impl<'ra> ResolverArenas<'ra> { - fn new_res_binding( + fn new_def_decl( &'ra self, res: Res, vis: Visibility, span: Span, expansion: LocalExpnId, ) -> Decl<'ra> { - self.alloc_name_binding(DeclData { + self.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: false, @@ -1350,8 +1350,8 @@ impl<'ra> ResolverArenas<'ra> { }) } - fn new_pub_res_binding(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { - self.new_res_binding(res, Visibility::Public, span, expn_id) + fn new_pub_def_decl(&'ra self, res: Res, span: Span, expn_id: LocalExpnId) -> Decl<'ra> { + self.new_def_decl(res, Visibility::Public, span, expn_id) } fn new_module( @@ -1362,9 +1362,9 @@ impl<'ra> ResolverArenas<'ra> { span: Span, no_implicit_prelude: bool, ) -> Module<'ra> { - let self_binding = match kind { + let self_decl = match kind { ModuleKind::Def(def_kind, def_id, _) => { - Some(self.new_pub_res_binding(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) + Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT)) } ModuleKind::Block => None, }; @@ -1374,11 +1374,11 @@ impl<'ra> ResolverArenas<'ra> { expn_id, span, no_implicit_prelude, - self_binding, + self_decl, )))) } - fn alloc_name_binding(&'ra self, name_binding: DeclData<'ra>) -> Decl<'ra> { - Interned::new_unchecked(self.dropless.alloc(name_binding)) + fn alloc_decl(&'ra self, data: DeclData<'ra>) -> Decl<'ra> { + Interned::new_unchecked(self.dropless.alloc(data)) } fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { Interned::new_unchecked(self.imports.alloc(import)) @@ -1389,11 +1389,8 @@ impl<'ra> ResolverArenas<'ra> { fn alloc_macro_rules_scope(&'ra self, scope: MacroRulesScope<'ra>) -> MacroRulesScopeRef<'ra> { self.dropless.alloc(CacheCell::new(scope)) } - fn alloc_macro_rules_binding( - &'ra self, - binding: MacroRulesDecl<'ra>, - ) -> &'ra MacroRulesDecl<'ra> { - self.dropless.alloc(binding) + fn alloc_macro_rules_decl(&'ra self, decl: MacroRulesDecl<'ra>) -> &'ra MacroRulesDecl<'ra> { + self.dropless.alloc(decl) } fn alloc_ast_paths(&'ra self, paths: &[ast::Path]) -> &'ra [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) @@ -1609,7 +1606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { local_module_map, extern_module_map: Default::default(), block_map: Default::default(), - binding_parent_modules: FxHashMap::default(), + decl_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), @@ -1618,29 +1615,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { inaccessible_ctor_reexport: Default::default(), arenas, - dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), - builtin_types_bindings: PrimTy::ALL + dummy_decl: arenas.new_pub_def_decl(Res::Err, DUMMY_SP, LocalExpnId::ROOT), + builtin_type_decls: PrimTy::ALL .iter() .map(|prim_ty| { let res = Res::PrimTy(*prim_ty); - let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - (prim_ty.name(), binding) + let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT); + (prim_ty.name(), decl) }) .collect(), - builtin_attrs_bindings: BUILTIN_ATTRIBUTES + builtin_attr_decls: BUILTIN_ATTRIBUTES .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - (builtin_attr.name, binding) + let decl = arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT); + (builtin_attr.name, decl) }) .collect(), - registered_tool_bindings: registered_tools + registered_tool_decls: registered_tools .iter() .map(|ident| { let res = Res::ToolMod; - let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); - (*ident, binding) + let decl = arenas.new_pub_def_decl(res, ident.span, LocalExpnId::ROOT); + (*ident, decl) }) .collect(), macro_names: FxHashSet::default(), @@ -2043,8 +2040,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false } - fn record_use(&mut self, ident: Ident, used_binding: Decl<'ra>, used: Used) { - self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity); + fn record_use(&mut self, ident: Ident, used_decl: Decl<'ra>, used: Used) { + self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity); } fn record_use_inner( @@ -2099,7 +2096,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) - && entry.item_binding == Some((used_binding, false)) + && entry.item_decl == Some((used_binding, false)) { return; } @@ -2226,10 +2223,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } - fn set_binding_parent_module(&mut self, binding: Decl<'ra>, module: Module<'ra>) { - if let Some(old_module) = self.binding_parent_modules.insert(binding, module) { + fn set_decl_parent_module(&mut self, decl: Decl<'ra>, module: Module<'ra>) { + if let Some(old_module) = self.decl_parent_modules.insert(decl, module) { if module != old_module { - span_bug!(binding.span, "parent module is reset for binding"); + span_bug!(decl.span, "parent module is reset for a name declaration"); } } } @@ -2246,8 +2243,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // panic on index should be impossible, the only name_bindings passed in should be from // `resolve_ident_in_scope_set` which will always refer to a local binding from an // import or macro definition - let macro_rules = &self.binding_parent_modules[¯o_rules]; - let modularized = &self.binding_parent_modules[&modularized]; + let macro_rules = &self.decl_parent_modules[¯o_rules]; + let modularized = &self.decl_parent_modules[&modularized]; macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() && modularized.is_ancestor_of(*macro_rules) } @@ -2258,7 +2255,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: bool, ) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { + entry.and_then(|entry| entry.item_decl).map(|(binding, _)| { if finalize { self.get_mut().record_use(ident, binding, Used::Scope); } @@ -2268,16 +2265,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { - let (pending_binding, finalized) = flag_binding.get(); - let binding = match pending_binding { - PendingBinding::Ready(binding) => { + entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { + let (pending_decl, finalized) = flag_decl.get(); + let decl = match pending_decl { + PendingDecl::Ready(decl) => { if finalize && !finalized { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - binding + decl } - PendingBinding::Pending => { + PendingDecl::Pending => { debug_assert!(!finalized); let crate_id = if finalize { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) @@ -2286,12 +2283,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; crate_id.map(|crate_id| { let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) + self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) }) } }; - flag_binding.set((PendingBinding::Ready(binding), finalize || finalized)); - binding.or_else(|| finalize.then_some(self.dummy_binding)) + flag_decl.set((PendingDecl::Ready(decl), finalize || finalized)); + decl.or_else(|| finalize.then_some(self.dummy_decl)) }) } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index e07bb46ac568..898d198c5475 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -49,7 +49,7 @@ type Res = def::Res; /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] pub(crate) struct MacroRulesDecl<'ra> { - pub(crate) binding: Decl<'ra>, + pub(crate) decl: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, pub(crate) ident: Ident, @@ -431,8 +431,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); - (*ident, binding) + (*ident, self.arenas.new_pub_def_decl(res, ident.span, expn_id)) }) .collect(); self.helper_attrs.insert(expn_id, helper_attrs); @@ -1062,18 +1061,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn prohibit_imported_non_macro_attrs( &self, - binding: Option>, + decl: Option>, res: Option, span: Span, ) { if let Some(Res::NonMacroAttr(kind)) = res { - if kind != NonMacroAttrKind::Tool && binding.is_none_or(|b| b.is_import()) { - let binding_span = binding.map(|binding| binding.span); + if kind != NonMacroAttrKind::Tool && decl.is_none_or(|b| b.is_import()) { self.dcx().emit_err(errors::CannotUseThroughAnImport { span, article: kind.article(), descr: kind.descr(), - binding_span, + binding_span: decl.map(|d| d.span), }); } } @@ -1084,12 +1082,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &ast::Path, parent_scope: &ParentScope<'ra>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, + decl: Option>, ) { if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr - && let Some(binding) = binding + && let Some(decl) = decl // This is a `macro_rules` itself, not some import. - && let DeclKind::Def(res) = binding.kind + && let DeclKind::Def(res) = decl.kind && let Res::Def(DefKind::Macro(kinds), def_id) = res && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, From a0ea3b0635064a9191e5df6e36ecb75cd5168df8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 22:27:43 +0300 Subject: [PATCH 174/340] Update more function names and fields from bindings to declarations --- .../rustc_resolve/src/build_reduced_graph.rs | 50 +++-- compiler/rustc_resolve/src/check_unused.rs | 8 +- compiler/rustc_resolve/src/diagnostics.rs | 38 ++-- .../src/effective_visibilities.rs | 33 ++- compiler/rustc_resolve/src/ident.rs | 165 +++++++-------- compiler/rustc_resolve/src/imports.rs | 200 +++++++++--------- compiler/rustc_resolve/src/late.rs | 28 +-- .../rustc_resolve/src/late/diagnostics.rs | 34 ++- compiler/rustc_resolve/src/lib.rs | 22 +- compiler/rustc_resolve/src/macros.rs | 2 +- 10 files changed, 284 insertions(+), 296 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7569fc3d716b..d56ca7c079cb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -44,20 +44,22 @@ use crate::{ type Res = def::Res; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { - /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; - /// otherwise, reports an error. - pub(crate) fn define_binding_local( + /// Attempt to put the declaration with the given name and namespace into the module, + /// and report an error in case of a collision. + pub(crate) fn plant_decl_into_local_module( &mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, decl: Decl<'ra>, ) { - if let Err(old_binding) = self.try_define_local(parent, ident, ns, decl, false) { - self.report_conflict(parent, ident, ns, old_binding, decl); + if let Err(old_decl) = self.try_plant_decl_into_local_module(parent, ident, ns, decl, false) + { + self.report_conflict(parent, ident, ns, old_decl, decl); } } + /// Create a name definitinon from the given components, and put it into the local module. fn define_local( &mut self, parent: Module<'ra>, @@ -68,10 +70,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, expn_id: LocalExpnId, ) { - let binding = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); - self.define_binding_local(parent, ident, ns, binding); + let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); + self.plant_decl_into_local_module(parent, ident, ns, decl); } + /// Create a name definitinon from the given components, and put it into the extern module. fn define_extern( &self, parent: Module<'ra>, @@ -84,7 +87,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expansion: LocalExpnId, ambiguity: Option>, ) { - let binding = self.arenas.alloc_decl(DeclData { + let decl = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. @@ -101,8 +104,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if self .resolution_or_default(parent, key) .borrow_mut_unchecked() - .non_glob_binding - .replace(binding) + .non_glob_decl + .replace(decl) .is_some() { span_bug!(span, "an external binding was already defined"); @@ -691,7 +694,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let kind = ImportKind::Single { source: source.ident, target: ident, - bindings: Default::default(), + decls: Default::default(), type_ns_only, nested, id, @@ -1019,7 +1022,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.import_use_map.insert(import, Used::Other); } self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(decl, import); + let import_decl = self.r.new_import_decl(decl, import); if ident.name != kw::Underscore && parent == self.r.graph_root { let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into @@ -1042,17 +1045,17 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_decl = Some((imported_binding, orig_name.is_some())); + entry.item_decl = Some((import_decl, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_decl: Some((imported_binding, true)), + item_decl: Some((import_decl, true)), flag_decl: None, }), }; } - self.r.define_binding_local(parent, ident, TypeNS, imported_binding); + self.r.plant_decl_into_local_module(parent, ident, TypeNS, import_decl); } /// Constructs the reduced graph for one foreign item. @@ -1167,8 +1170,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } macro_use_import(this, span, true) }; - let import_binding = this.r.import(binding, import); - this.add_macro_use_decl(ident.name, import_binding, span, allow_shadowing); + let import_decl = this.r.new_import_decl(binding, import); + this.add_macro_use_decl(ident.name, import_decl, span, allow_shadowing); } }); } else { @@ -1183,13 +1186,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if let Ok(binding) = result { let import = macro_use_import(self, ident.span, false); self.r.potentially_unused_imports.push(import); - let imported_binding = self.r.import(binding, import); - self.add_macro_use_decl( - ident.name, - imported_binding, - ident.span, - allow_shadowing, - ); + let import_decl = self.r.new_import_decl(binding, import); + self.add_macro_use_decl(ident.name, import_decl, ident.span, allow_shadowing); } else { self.r.dcx().emit_err(errors::ImportedMacroNotFound { span: ident.span }); } @@ -1319,8 +1317,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); - let import_binding = self.r.import(decl, import); - self.r.define_binding_local(self.r.graph_root, ident, MacroNS, import_binding); + let import_decl = self.r.new_import_decl(decl, import); + self.r.plant_decl_into_local_module(self.r.graph_root, ident, MacroNS, import_decl); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index a2e903ce48eb..3724fcfce40f 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -514,8 +514,8 @@ impl Resolver<'_, '_> { let mut check_redundant_imports = FxIndexSet::default(); for module in &self.local_modules { for (_key, resolution) in self.resolutions(*module).borrow().iter() { - if let Some(binding) = resolution.borrow().best_binding() - && let DeclKind::Import { import, .. } = binding.kind + if let Some(decl) = resolution.borrow().best_decl() + && let DeclKind::Import { import, .. } = decl.kind && let ImportKind::Single { id, .. } = import.kind { if let Some(unused_import) = unused_imports.get(&import.root_id) @@ -542,8 +542,8 @@ impl Resolver<'_, '_> { // Deleting both unused imports and unnecessary segments of an item may result // in the item not being found. for unn_qua in &self.potentially_unnecessary_qualifications { - if let LateDecl::Decl(name_binding) = unn_qua.binding - && let DeclKind::Import { import, .. } = name_binding.kind + if let LateDecl::Decl(decl) = unn_qua.decl + && let DeclKind::Import { import, .. } = decl.kind && (is_unused_import(import, &unused_imports) || is_redundant_import(import, &redundant_imports)) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b77481d1b3ad..7ed29b91b67a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1195,13 +1195,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { - if let MacroRulesScope::Def(macro_rules_binding) = macro_rules_scope.get() { - let res = macro_rules_binding.decl.res(); + if let MacroRulesScope::Def(macro_rules_def) = macro_rules_scope.get() { + let res = macro_rules_def.decl.res(); if filter_fn(res) { - suggestions.push(TypoSuggestion::typo_from_ident( - macro_rules_binding.ident, - res, - )) + suggestions + .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident, res)) } } } @@ -1581,9 +1579,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |(key, name_resolution)| { if key.ns == TypeNS && key.ident == ident - && let Some(binding) = name_resolution.borrow().best_binding() + && let Some(decl) = name_resolution.borrow().best_decl() { - match binding.res() { + match decl.res() { // No disambiguation needed if the identically named item we // found in scope actually refers to the crate in question. Res::Def(_, def_id) => def_id != crate_def_id, @@ -2087,7 +2085,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { let PrivacyError { ident, - binding, + decl, outermost_res, parent_scope, single_nested, @@ -2095,8 +2093,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ref source, } = *privacy_error; - let res = binding.res(); - let ctor_fields_span = self.ctor_fields_span(binding); + let res = decl.res(); + let ctor_fields_span = self.ctor_fields_span(decl); let plain_descr = res.descr().to_string(); let nonimport_descr = if ctor_fields_span.is_some() { plain_descr + " constructor" } else { plain_descr }; @@ -2104,7 +2102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let get_descr = |b: Decl<'_>| if b.is_import() { &import_descr } else { &nonimport_descr }; // Print the primary message. - let ident_descr = get_descr(binding); + let ident_descr = get_descr(decl); let mut err = self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); @@ -2204,8 +2202,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Print the whole import chain to make it easier to see what happens. - let first_binding = binding; - let mut next_binding = Some(binding); + let first_binding = decl; + let mut next_binding = Some(decl); let mut next_ident = ident; let mut path = vec![]; while let Some(binding) = next_binding { @@ -2413,7 +2411,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, module: Option>, failed_segment_idx: usize, @@ -2509,7 +2507,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns_to_try, parent_scope, None, - ignore_binding, + ignore_decl, ignore_import, ) .ok() @@ -2523,7 +2521,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, &ribs[ns_to_try], - ignore_binding, + ignore_decl, diag_metadata, ) { // we found a locally-imported or available item/module @@ -2538,7 +2536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) .ok() @@ -2574,7 +2572,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, &ribs[ValueNS], - ignore_binding, + ignore_decl, diag_metadata, ) } else { @@ -2642,7 +2640,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) { let descr = binding.res().descr(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 389bdbbec62b..87be913df535 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -28,9 +28,9 @@ impl ParentId<'_> { pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { r: &'a mut Resolver<'ra, 'tcx>, def_effective_visibilities: EffectiveVisibilities, - /// While walking import chains we need to track effective visibilities per-binding, and def id + /// While walking import chains we need to track effective visibilities per-decl, and def id /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple - /// bindings can correspond to a single def id in imports. So we keep a separate table. + /// declarations can correspond to a single def id in imports. So we keep a separate table. import_effective_visibilities: EffectiveVisibilities>, // It's possible to recalculate this at any point, but it's relatively expensive. current_private_vis: Visibility, @@ -91,9 +91,9 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let mut exported_ambiguities = FxHashSet::default(); // Update visibilities for import def ids. These are not used during the - // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based + // `EffectiveVisibilitiesVisitor` pass, because we have more detailed declaration-based // information, but are used by later passes. Effective visibility of an import def id - // is the maximum value among visibilities of bindings corresponding to that def id. + // is the maximum value among visibilities of declarations corresponding to that def id. for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; if !decl.is_ambiguity_recursive() { @@ -110,12 +110,12 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { exported_ambiguities } - /// Update effective visibilities of bindings in the given module, + /// Update effective visibilities of name declarations in the given module, /// including their whole reexport chains. fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { let module = self.r.expect_module(module_id.to_def_id()); for (_, name_resolution) in self.r.resolutions(module).borrow().iter() { - let Some(mut binding) = name_resolution.borrow().binding() else { + let Some(mut decl) = name_resolution.borrow().binding() else { continue; }; // Set the given effective visibility level to `Level::Direct` and @@ -125,28 +125,27 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // If the binding is ambiguous, put the root ambiguity binding and all reexports // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = - |binding: Decl<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = binding.warn_ambiguity; - while let DeclKind::Import { binding: nested_binding, .. } = binding.kind { - self.update_import(binding, parent_id); + let mut warn_ambiguity = decl.warn_ambiguity; + while let DeclKind::Import { binding: nested_binding, .. } = decl.kind { + self.update_import(decl, parent_id); - if is_ambiguity(binding, warn_ambiguity) { + if is_ambiguity(decl, warn_ambiguity) { // Stop at the root ambiguity, further bindings in the chain should not // be reexported because the root ambiguity blocks any access to them. // (Those further bindings are most likely not ambiguities themselves.) break; } - parent_id = ParentId::Import(binding); - binding = nested_binding; + parent_id = ParentId::Import(decl); + decl = nested_binding; warn_ambiguity |= nested_binding.warn_ambiguity; } - if !is_ambiguity(binding, warn_ambiguity) - && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) + if !is_ambiguity(decl, warn_ambiguity) + && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + self.update_def(def_id, decl.vis.expect_local(), parent_id); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index a5d9c1bae74f..e0acf043ffcf 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -304,7 +304,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, ribs: &[Rib<'ra>], - ignore_binding: Option>, + ignore_decl: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> Option> { let orig_ident = ident; @@ -345,7 +345,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), finalize.is_some(), - ignore_binding, + ignore_decl, None, ) { @@ -363,7 +363,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, None, ) .ok() @@ -391,7 +391,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { assert!(force || finalize.is_none()); // `finalize` implies `force` @@ -442,13 +442,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ctxt, scope_set, parent_scope, - // Shadowed bindings don't need to be marked as used or non-speculatively loaded. + // Shadowed decls don't need to be marked as used or non-speculatively loaded. if innermost_results.is_empty() { finalize } else { None }, force, - ignore_binding, + ignore_decl, ignore_import, ) { - Ok(binding) => Ok(binding), + Ok(decl) => Ok(decl), // We can break with an error at this step, it means we cannot determine the // resolution right now, but we must block and wait until we can, instead of // considering outer scopes. Although there's no need to do that if we already @@ -459,32 +459,32 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(determinacy) => Err(determinacy.into_value()), }; match res { - Ok(binding) if sub_namespace_match(binding.macro_kinds(), macro_kind) => { + Ok(decl) if sub_namespace_match(decl.macro_kinds(), macro_kind) => { // Below we report various ambiguity errors. // We do not need to report them if we are either in speculative resolution, // or in late resolution when everything is already imported and expanded // and no ambiguities exist. if matches!(finalize, None | Some(Finalize { stage: Stage::Late, .. })) { - return ControlFlow::Break(Ok(binding)); + return ControlFlow::Break(Ok(decl)); } - if let Some(&(innermost_binding, _)) = innermost_results.first() { + if let Some(&(innermost_decl, _)) = innermost_results.first() { // Found another solution, if the first one was "weak", report an error. if this.get_mut().maybe_push_ambiguity( orig_ident, ns, scope_set, parent_scope, - binding, + decl, scope, &innermost_results, ) { // No need to search for more potential ambiguities, one is enough. - return ControlFlow::Break(Ok(innermost_binding)); + return ControlFlow::Break(Ok(innermost_decl)); } } - innermost_results.push((binding, scope)); + innermost_results.push((decl, scope)); } Ok(_) | Err(Determinacy::Determined) => {} Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, @@ -501,7 +501,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Scope visiting walked all the scopes and maybe found something in one of them. match innermost_results.first() { - Some(&(binding, ..)) => Ok(binding), + Some(&(decl, ..)) => Ok(decl), None => Err(Determinacy::determined(determinacy == Determinacy::Determined || force)), } } @@ -517,16 +517,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, finalize: Option, force: bool, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ret = match scope { Scope::DeriveHelpers(expn_id) => { - if let Some(binding) = self.helper_attrs.get(&expn_id).and_then(|attrs| { - attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, binding)| *binding) - }) { - Ok(binding) + if let Some(decl) = self + .helper_attrs + .get(&expn_id) + .and_then(|attrs| attrs.iter().rfind(|(i, _)| ident == *i).map(|(_, d)| *d)) + { + Ok(decl) } else { Err(Determinacy::Determined) } @@ -543,12 +545,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = self.arenas.new_pub_def_decl( + let decl = self.arenas.new_pub_def_decl( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), derive.span, LocalExpnId::ROOT, ); - result = Ok(binding); + result = Ok(decl); break; } } @@ -577,7 +579,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( + let decl = self.reborrow().resolve_ident_in_module_non_globs_unadjusted( module, ident, ns, @@ -588,11 +590,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Shadowing::Restricted }, adjusted_finalize, - ignore_binding, + ignore_decl, ignore_import, ); - match binding { - Ok(binding) => { + match decl { + Ok(decl) => { if let Some(lint_id) = derive_fallback_lint_id { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, @@ -605,7 +607,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); } - Ok(binding) + Ok(decl) } Err(ControlFlow::Continue(determinacy)) => Err(determinacy), Err(ControlFlow::Break(determinacy)) => { @@ -638,7 +640,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Shadowing::Restricted }, adjusted_finalize, - ignore_binding, + ignore_decl, ignore_import, ); match binding { @@ -666,18 +668,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), }, Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) { - Some(binding) => Ok(*binding), + Some(decl) => Ok(*decl), None => Err(Determinacy::Determined), }, Scope::ExternPreludeItems => { match self.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::determined( self.graph_root.unexpanded_invocations.borrow().is_empty(), )), @@ -685,36 +687,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::ExternPreludeFlags => { match self.extern_prelude_get_flag(ident, finalize.is_some()) { - Some(binding) => Ok(binding), + Some(decl) => Ok(decl), None => Err(Determinacy::Determined), } } Scope::ToolPrelude => match self.registered_tool_decls.get(&ident) { - Some(binding) => Ok(*binding), + Some(decl) => Ok(*decl), None => Err(Determinacy::Determined), }, Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude - && let Ok(binding) = self.reborrow().resolve_ident_in_scope_set( + && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( ident, ScopeSet::Module(ns, prelude), parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ) - && (matches!(use_prelude, UsePrelude::Yes) - || self.is_builtin_macro(binding.res())) + && (matches!(use_prelude, UsePrelude::Yes) || self.is_builtin_macro(decl.res())) { - result = Ok(binding) + result = Ok(decl) } result } Scope::BuiltinTypes => match self.builtin_type_decls.get(&ident.name) { - Some(binding) => { + Some(decl) => { if matches!(ident.name, sym::f16) && !self.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) @@ -741,7 +742,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - Ok(*binding) + Ok(*decl) } None => Err(Determinacy::Determined), }, @@ -756,12 +757,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - binding: Decl<'ra>, + decl: Decl<'ra>, scope: Scope<'ra>, innermost_results: &[(Decl<'ra>, Scope<'ra>)], ) -> bool { - let (innermost_binding, innermost_scope) = *innermost_results.first().unwrap(); - let (res, innermost_res) = (binding.res(), innermost_binding.res()); + let (innermost_decl, innermost_scope) = innermost_results[0]; + let (res, innermost_res) = (decl.res(), innermost_decl.res()); if res == innermost_res { return false; } @@ -781,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span_bug!(orig_ident.span, "impossible inner resolution kind") } else if matches!(innermost_scope, Scope::MacroRules(_)) && matches!(scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..)) - && !self.disambiguate_macro_rules_vs_modularized(innermost_binding, binding) + && !self.disambiguate_macro_rules_vs_modularized(innermost_decl, decl) { Some(AmbiguityKind::MacroRulesVsModularized) } else if matches!(scope, Scope::MacroRules(_)) @@ -797,13 +798,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { "ambiguous scoped macro resolutions with path-based \ scope resolution as first candidate" ) - } else if innermost_binding.is_glob_import() { + } else if innermost_decl.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) - } else if !module_only - && innermost_binding.may_appear_after(parent_scope.expansion, binding) - { + } else if !module_only && innermost_decl.may_appear_after(parent_scope.expansion, decl) { Some(AmbiguityKind::MoreExpandedVsOuter) - } else if innermost_binding.expansion != LocalExpnId::ROOT + } else if innermost_decl.expansion != LocalExpnId::ROOT && (!module_only || ns == MacroNS) && let Scope::ModuleGlobs(m1, _) = scope && let Scope::ModuleNonGlobs(m2, _) = innermost_scope @@ -822,9 +821,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // by extern item bindings. // FIXME: Remove with lang team approval. let issue_145575_hack = matches!(scope, Scope::ExternPreludeFlags) - && innermost_results[1..].iter().any(|(b, s)| { - matches!(s, Scope::ExternPreludeItems) && *b != innermost_binding - }); + && innermost_results[1..] + .iter() + .any(|(b, s)| matches!(s, Scope::ExternPreludeItems) && *b != innermost_decl); // Skip ambiguity errors for nonglob module bindings "overridden" // by glob module bindings in the same module. // FIXME: Remove with lang team approval. @@ -845,8 +844,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, - b1: innermost_binding, - b2: binding, + b1: innermost_decl, + b2: decl, scope1: innermost_scope, scope2: scope, warning: false, @@ -878,7 +877,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { let tmp_parent_scope; @@ -904,7 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, adjusted_parent_scope, finalize, - ignore_binding, + ignore_decl, ignore_import, ) } @@ -918,7 +917,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns: Namespace, parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, Determinacy> { match module { @@ -928,7 +927,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ), ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( @@ -937,7 +936,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ), ModuleOrUniformRoot::ExternPrelude => { @@ -950,7 +949,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) } @@ -973,7 +972,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) } @@ -991,7 +990,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: Option, // This binding should be ignored during in-module resolution, so that we don't get // "self-confirming" import resolutions during import validation and checking. - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); @@ -1003,7 +1002,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .try_borrow_mut_unchecked() .map_err(|_| ControlFlow::Continue(Determined))?; - let binding = resolution.non_glob_binding.filter(|b| Some(*b) != ignore_binding); + let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1028,7 +1027,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ns, ignore_import, - ignore_binding, + ignore_decl, parent_scope, ) { return Err(ControlFlow::Break(Undetermined)); @@ -1052,7 +1051,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, shadowing: Shadowing, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { let key = BindingKey::new(ident, ns); @@ -1064,7 +1063,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .try_borrow_mut_unchecked() .map_err(|_| ControlFlow::Continue(Determined))?; - let binding = resolution.glob_binding.filter(|b| Some(*b) != ignore_binding); + let binding = resolution.glob_decl.filter(|b| Some(*b) != ignore_decl); if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( @@ -1084,7 +1083,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, ns, ignore_import, - ignore_binding, + ignore_decl, parent_scope, ) { return Err(ControlFlow::Break(Undetermined)); @@ -1154,7 +1153,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { adjusted_parent_scope, None, false, - ignore_binding, + ignore_decl, ignore_import, ); @@ -1192,7 +1191,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if report_private { self.privacy_errors.push(PrivacyError { ident, - binding, + decl: binding, dedup_span: path_span, outermost_res: None, source: None, @@ -1255,12 +1254,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option>, ns: Namespace, ignore_import: Option>, - ignore_binding: Option>, + ignore_decl: Option>, parent_scope: &ParentScope<'ra>, ) -> bool { for single_import in &resolution.single_imports { - if let Some(binding) = resolution.non_glob_binding - && let DeclKind::Import { import, .. } = binding.kind + if let Some(decl) = resolution.non_glob_decl + && let DeclKind::Import { import, .. } = decl.kind && import == *single_import { // Single import has already defined the name and we are aware of it, @@ -1273,7 +1272,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !self.is_accessible_from(single_import.vis, parent_scope.module) { continue; } - if let Some(ignored) = ignore_binding + if let Some(ignored) = ignore_decl && let DeclKind::Import { import, .. } = ignored.kind && import == *single_import { @@ -1283,13 +1282,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(module) = single_import.imported_module.get() else { return true; }; - let ImportKind::Single { source, target, bindings, .. } = &single_import.kind else { + let ImportKind::Single { source, target, decls, .. } = &single_import.kind else { unreachable!(); }; if source != target { - if bindings.iter().all(|binding| binding.get().decl().is_none()) { + if decls.iter().all(|d| d.get().decl().is_none()) { return true; - } else if bindings[ns].get().decl().is_none() && binding.is_some() { + } else if decls[ns].get().decl().is_none() && binding.is_some() { return true; } } @@ -1300,7 +1299,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &single_import.parent_scope, None, - ignore_binding, + ignore_decl, ignore_import, ) { Err(Determined) => continue, @@ -1665,7 +1664,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, ) -> PathResult<'ra> { self.resolve_path_with_ribs( @@ -1675,7 +1674,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, finalize, None, - ignore_binding, + ignore_decl, ignore_import, None, ) @@ -1689,7 +1688,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { source: Option>, finalize: Option, ribs: Option<&PerNS>>>, - ignore_binding: Option>, + ignore_decl: Option>, ignore_import: Option>, diag_metadata: Option<&DiagMetadata<'_>>, ) -> PathResult<'ra> { @@ -1816,7 +1815,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, parent_scope, finalize, - ignore_binding, + ignore_decl, ignore_import, ) } else if let Some(ribs) = ribs @@ -1829,7 +1828,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, &ribs[ns], - ignore_binding, + ignore_decl, diag_metadata, ) { // we found a locally-imported or available item/module @@ -1851,7 +1850,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope, finalize, finalize.is_some(), - ignore_binding, + ignore_decl, ignore_import, ) }; @@ -1951,7 +1950,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { opt_ns, parent_scope, ribs, - ignore_binding, + ignore_decl, ignore_import, module, segment_idx, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4f8877401638..0fbfbd95a026 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -66,8 +66,8 @@ pub(crate) enum ImportKind<'ra> { /// `target` in `use prefix::source as target`. /// It will directly use `source` when the format is `use prefix::source`. target: Ident, - /// Bindings introduced by the import. - bindings: PerNS>>, + /// Name declarations introduced by the import. + decls: PerNS>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -110,14 +110,14 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { - Single { source, target, bindings, type_ns_only, nested, id, .. } => f + Single { source, target, decls, type_ns_only, nested, id, .. } => f .debug_struct("Single") .field("source", source) .field("target", target) // Ignore the nested bindings to avoid an infinite loop while printing. .field( - "bindings", - &bindings.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), + "decls", + &decls.clone().map(|b| b.into_inner().decl().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -244,16 +244,16 @@ pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet>, - /// The non-glob binding for this name, if it is known to exist. - pub non_glob_binding: Option>, - /// The glob binding for this name, if it is known to exist. - pub glob_binding: Option>, + /// The non-glob declaration for this name, if it is known to exist. + pub non_glob_decl: Option>, + /// The glob declaration for this name, if it is known to exist. + pub glob_decl: Option>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. pub(crate) fn binding(&self) -> Option> { - self.best_binding().and_then(|binding| { + self.best_decl().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { @@ -262,8 +262,8 @@ impl<'ra> NameResolution<'ra> { }) } - pub(crate) fn best_binding(&self) -> Option> { - self.non_glob_binding.or(self.glob_binding) + pub(crate) fn best_decl(&self) -> Option> { + self.non_glob_decl.or(self.glob_decl) } } @@ -296,16 +296,16 @@ fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> O } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { - /// Given a binding and an import that resolves to it, - /// return the corresponding binding defined by the import. - pub(crate) fn import(&self, binding: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { + /// Given an import and the declaration that it points to, + /// create the corresponding import declaration. + pub(crate) fn new_import_decl(&self, decl: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); - let vis = if binding.vis.is_at_least(import_vis, self.tcx) - || pub_use_of_private_extern_crate_hack(import, binding).is_some() + let vis = if decl.vis.is_at_least(import_vis, self.tcx) + || pub_use_of_private_extern_crate_hack(import, decl).is_some() { import_vis } else { - binding.vis + decl.vis }; if let ImportKind::Glob { ref max_vis, .. } = import.kind @@ -316,7 +316,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.arenas.alloc_decl(DeclData { - kind: DeclKind::Import { binding, import }, + kind: DeclKind::Import { binding: decl, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -325,18 +325,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - /// Define the name or return the existing binding if there is a collision. - pub(crate) fn try_define_local( + /// Attempt to put the declaration with the given name and namespace into the module, + /// and return existing declaration if there is a collision. + pub(crate) fn try_plant_decl_into_local_module( &mut self, module: Module<'ra>, ident: Ident, ns: Namespace, - binding: Decl<'ra>, + decl: Decl<'ra>, warn_ambiguity: bool, ) -> Result<(), Decl<'ra>> { - let res = binding.res(); + let res = decl.res(); self.check_reserved_macro_name(ident, res); - self.set_decl_parent_module(binding, module); + self.set_decl_parent_module(decl, module); // 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. @@ -345,67 +346,66 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.underscore_disambiguator.get() }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { - if let Some(old_binding) = resolution.best_binding() { - if res == Res::Err && old_binding.res() != Res::Err { - // Do not override real bindings with `Res::Err`s from error recovery. + if let Some(old_decl) = resolution.best_decl() { + if res == Res::Err && old_decl.res() != Res::Err { + // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); } - match (old_binding.is_glob_import(), binding.is_glob_import()) { + match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { - let (glob_binding, old_glob_binding) = (binding, old_binding); - // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. - if !binding.is_ambiguity_recursive() - && let DeclKind::Import { import: old_import, .. } = - old_glob_binding.kind - && let DeclKind::Import { import, .. } = glob_binding.kind + let (glob_decl, old_glob_decl) = (decl, old_decl); + // FIXME: remove `!decl.is_ambiguity_recursive()` after delete the warning ambiguity. + if !decl.is_ambiguity_recursive() + && let DeclKind::Import { import: old_import, .. } = old_glob_decl.kind + && let DeclKind::Import { import, .. } = glob_decl.kind && old_import == import { // When imported from the same glob-import statement, we should replace - // `old_glob_binding` with `glob_binding`, regardless of whether + // `old_glob_decl` with `glob_decl`, regardless of whether // they have the same resolution or not. - resolution.glob_binding = Some(glob_binding); - } else if res != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_decl_with_ambiguity( - old_glob_binding, - glob_binding, + resolution.glob_decl = Some(glob_decl); + } else if res != old_glob_decl.res() { + resolution.glob_decl = Some(this.new_decl_with_ambiguity( + old_glob_decl, + glob_decl, warn_ambiguity, )); - } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { + } else if !old_decl.vis.is_at_least(decl.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. - resolution.glob_binding = Some(glob_binding); - } else if binding.is_ambiguity_recursive() { - resolution.glob_binding = - Some(this.new_decl_with_warn_ambiguity(glob_binding)); + resolution.glob_decl = Some(glob_decl); + } else if decl.is_ambiguity_recursive() { + resolution.glob_decl = + Some(this.new_decl_with_warn_ambiguity(glob_decl)); } } (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_binding, non_glob_binding) = - if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - resolution.non_glob_binding = Some(non_glob_binding); - if let Some(old_glob_binding) = resolution.glob_binding { - assert!(old_glob_binding.is_glob_import()); - if glob_binding.res() != old_glob_binding.res() { - resolution.glob_binding = Some(this.new_decl_with_ambiguity( - old_glob_binding, - glob_binding, + let (glob_decl, non_glob_decl) = + if old_glob { (old_decl, decl) } else { (decl, old_decl) }; + resolution.non_glob_decl = Some(non_glob_decl); + if let Some(old_glob_decl) = resolution.glob_decl { + assert!(old_glob_decl.is_glob_import()); + if glob_decl.res() != old_glob_decl.res() { + resolution.glob_decl = Some(this.new_decl_with_ambiguity( + old_glob_decl, + glob_decl, false, )); - } else if !old_glob_binding.vis.is_at_least(binding.vis, this.tcx) { - resolution.glob_binding = Some(glob_binding); + } else if !old_glob_decl.vis.is_at_least(decl.vis, this.tcx) { + resolution.glob_decl = Some(glob_decl); } } else { - resolution.glob_binding = Some(glob_binding); + resolution.glob_decl = Some(glob_decl); } } (false, false) => { - return Err(old_binding); + return Err(old_decl); } } } else { - if binding.is_glob_import() { - resolution.glob_binding = Some(binding); + if decl.is_glob_import() { + resolution.glob_decl = Some(decl); } else { - resolution.non_glob_binding = Some(binding); + resolution.non_glob_decl = Some(decl); } } @@ -445,14 +445,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t, warn_ambiguity) = { let resolution = &mut *self.resolution_or_default(module, key).borrow_mut_unchecked(); - let old_binding = resolution.binding(); + let old_decl = resolution.binding(); let t = f(self, resolution); if let Some(binding) = resolution.binding() - && old_binding != Some(binding) + && old_decl != Some(binding) { - (binding, t, warn_ambiguity || old_binding.is_some()) + (binding, t, warn_ambiguity || old_decl.is_some()) } else { return t; } @@ -471,12 +471,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, *import); - let _ = self.try_define_local( + let import_decl = self.new_import_decl(binding, *import); + let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, ident.0, key.ns, - imported_binding, + import_decl, warn_ambiguity, ); } @@ -488,16 +488,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { - if let ImportKind::Single { target, ref bindings, .. } = import.kind { - if !(is_indeterminate || bindings.iter().all(|binding| binding.get().decl().is_none())) - { + if let ImportKind::Single { target, ref decls, .. } = import.kind { + if !(is_indeterminate || decls.iter().all(|d| d.get().decl().is_none())) { return; // Has resolution, do not create the dummy binding } let dummy_decl = self.dummy_decl; - let dummy_decl = self.import(dummy_decl, import); + let dummy_decl = self.new_import_decl(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = this.try_define_local(module, target, ns, dummy_decl, false); + let _ = + this.try_plant_decl_into_local_module(module, target, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -574,10 +574,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_error |= import.is_glob(); - if let ImportKind::Single { source, ref bindings, .. } = import.kind + if let ImportKind::Single { source, ref decls, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let PendingDecl::Ready(None) = bindings.value_ns.get() + && let PendingDecl::Ready(None) = decls.value_ns.get() { continue; } @@ -631,7 +631,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for module in &self.local_modules { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - let Some(binding) = resolution.best_binding() else { continue }; + let Some(binding) = resolution.best_decl() else { continue }; if let DeclKind::Import { import, .. } = binding.kind && let Some(amb_binding) = binding.ambiguity @@ -651,16 +651,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - if let Some(glob_binding) = resolution.glob_binding - && resolution.non_glob_binding.is_some() + if let Some(glob_decl) = resolution.glob_decl + && resolution.non_glob_decl.is_some() { if binding.res() != Res::Err - && glob_binding.res() != Res::Err - && let DeclKind::Import { import: glob_import, .. } = glob_binding.kind + && glob_decl.res() != Res::Err + && let DeclKind::Import { import: glob_import, .. } = glob_decl.kind && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_binding.vis.is_public() + && glob_decl.vis.is_public() && !binding.vis.is_public() { let binding_id = match binding.kind { @@ -677,7 +677,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { BuiltinLintDiag::HiddenGlobReexports { name: key.ident.name.to_string(), namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, + glob_reexport_span: glob_decl.span, private_item_span: binding.span, }, ); @@ -838,8 +838,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { import.imported_module.set_unchecked(Some(module)); let (source, target, bindings, type_ns_only) = match import.kind { - ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { - (source, target, bindings, type_ns_only) + ImportKind::Single { source, target, ref decls, type_ns_only, .. } => { + (source, target, decls, type_ns_only) } ImportKind::Glob { .. } => { self.get_mut_unchecked().resolve_glob_import(import); @@ -876,14 +876,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit(); } // We need the `target`, `source` can be extracted. - let imported_binding = this.import(binding, import); - this.get_mut_unchecked().define_binding_local( + let import_decl = this.new_import_decl(binding, import); + this.get_mut_unchecked().plant_decl_into_local_module( parent, target, ns, - imported_binding, + import_decl, ); - PendingDecl::Ready(Some(imported_binding)) + PendingDecl::Ready(Some(import_decl)) } Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. @@ -917,8 +917,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option { - let ignore_binding = match &import.kind { - ImportKind::Single { bindings, .. } => bindings[TypeNS].get().decl(), + let ignore_decl = match &import.kind { + ImportKind::Single { decls, .. } => decls[TypeNS].get().decl(), _ => None, }; let ambiguity_errors_len = @@ -934,7 +934,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, &import.parent_scope, Some(finalize), - ignore_binding, + ignore_decl, Some(import), ); @@ -1037,8 +1037,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let (ident, target, bindings, type_ns_only, import_id) = match import.kind { - ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { - (source, target, bindings, type_ns_only, id) + ImportKind::Single { source, target, ref decls, type_ns_only, id, .. } => { + (source, target, decls, type_ns_only, id) } ImportKind::Glob { ref max_vis, id } => { if import.module_path.len() <= 1 { @@ -1094,7 +1094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, &import.parent_scope, Some(finalize), - ignore_binding, + ignore_decl, None, ) { let res = module.res().map(|r| (r, ident)); @@ -1197,7 +1197,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Never suggest the same name let resolution = resolution.borrow(); - if let Some(name_binding) = resolution.best_binding() { + if let Some(name_binding) = resolution.best_decl() { match name_binding.kind { DeclKind::Import { binding, .. } => { match binding.kind { @@ -1383,7 +1383,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. - let ImportKind::Single { source, target, ref bindings, id, .. } = import.kind else { + let ImportKind::Single { source, target, ref decls, id, .. } = import.kind else { unreachable!() }; @@ -1410,7 +1410,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - let binding = bindings[ns].get().decl().map(|b| b.import_source()); + let binding = decls[ns].get().decl().map(|b| b.import_source()); if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; @@ -1422,7 +1422,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - bindings[ns].get().decl(), + decls[ns].get().decl(), None, ) { Ok(other_binding) => { @@ -1497,16 +1497,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, import); + let import_decl = self.new_import_decl(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) .and_then(|r| r.binding()) .is_some_and(|binding| binding.warn_ambiguity_recursive()); - let _ = self.try_define_local( + let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, key.ident.0, key.ns, - imported_binding, + import_decl, warn_ambiguity, ); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2685efa28b64..b4941a6f5b99 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -677,7 +677,7 @@ impl MaybeExported<'_> { /// Used for recording UnnecessaryQualification. #[derive(Debug)] pub(crate) struct UnnecessaryQualification<'ra> { - pub binding: LateDecl<'ra>, + pub decl: LateDecl<'ra>, pub node_id: NodeId, pub path_span: Span, pub removal_span: Span, @@ -1489,7 +1489,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, finalize: Option, - ignore_binding: Option>, + ignore_decl: Option>, ) -> Option> { self.r.resolve_ident_in_lexical_scope( ident, @@ -1497,7 +1497,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &self.parent_scope, finalize, &self.ribs[ns], - ignore_binding, + ignore_decl, Some(&self.diag_metadata), ) } @@ -3630,9 +3630,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); - debug!(?binding); - if binding.is_none() { + let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); + debug!(?decl); + if decl.is_none() { // We could not find the trait item in the correct namespace. // Check the other namespace to report an error. let ns = match ns { @@ -3641,8 +3641,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = self.r.resolution(module, key).and_then(|r| r.best_binding()); - debug!(?binding); + decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); + debug!(?decl); } let feed_visibility = |this: &mut Self, def_id| { @@ -3659,7 +3659,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.r.feed_visibility(this.r.feed(id), vis); }; - let Some(binding) = binding else { + let Some(decl) = decl else { // We could not find the method: report an error. let candidate = self.find_similarly_named_assoc_item(ident.name, kind); let path = &self.current_trait_ref.as_ref().unwrap().1.path; @@ -3669,7 +3669,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return; }; - let res = binding.res(); + let res = decl.res(); let Res::Def(def_kind, id_in_trait) = res else { bug!() }; feed_visibility(self, id_in_trait); @@ -3680,7 +3680,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ResolutionError::TraitImplDuplicate { name: ident, old_span: *entry.get(), - trait_item_span: binding.span, + trait_item_span: decl.span, }, ); return; @@ -3720,7 +3720,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { kind, code, trait_path, - trait_item_span: binding.span, + trait_item_span: decl.span, }, ); } @@ -5356,9 +5356,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { (res == binding.res()).then_some((seg, binding)) }); - if let Some((seg, binding)) = unqualified { + if let Some((seg, decl)) = unqualified { self.r.potentially_unnecessary_qualifications.push(UnnecessaryQualification { - binding, + decl, node_id: finalize.node_id, path_span: finalize.path_span, removal_span: path[0].ident.span.until(seg.ident.span), diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f75ac400dc0b..73e1a8f0c3bc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -891,10 +891,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { for resolution in r.resolutions(m).borrow().values() { - let Some(did) = resolution - .borrow() - .best_binding() - .and_then(|binding| binding.res().opt_def_id()) + let Some(did) = + resolution.borrow().best_decl().and_then(|binding| binding.res().opt_def_id()) else { continue; }; @@ -1589,19 +1587,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, None, None, *source) { - let targets: Vec<_> = self - .r - .resolutions(module) - .borrow() - .iter() - .filter_map(|(key, resolution)| { - resolution - .borrow() - .best_binding() - .map(|binding| binding.res()) - .and_then(|res| if filter_fn(res) { Some((*key, res)) } else { None }) - }) - .collect(); + let targets: Vec<_> = + self.r + .resolutions(module) + .borrow() + .iter() + .filter_map(|(key, resolution)| { + resolution.borrow().best_decl().map(|binding| binding.res()).and_then( + |res| if filter_fn(res) { Some((*key, res)) } else { None }, + ) + }) + .collect(); if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident( target.0.ident.0, @@ -2486,9 +2482,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .resolutions(*module) .borrow() .iter() - .filter_map(|(key, res)| { - res.borrow().best_binding().map(|binding| (key, binding.res())) - }) + .filter_map(|(key, res)| res.borrow().best_decl().map(|binding| (key, binding.res()))) .filter(|(_, res)| match (kind, res) { (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 67449050aea9..27817c0473ab 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -692,8 +692,8 @@ impl<'ra> Module<'ra> { mut f: impl FnMut(&R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_ref().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().best_binding() { - f(resolver, key.ident, key.ns, binding); + if let Some(decl) = name_resolution.borrow().best_decl() { + f(resolver, key.ident, key.ns, decl); } } } @@ -704,8 +704,8 @@ impl<'ra> Module<'ra> { mut f: impl FnMut(&mut R, Macros20NormalizedIdent, Namespace, Decl<'ra>), ) { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().best_binding() { - f(resolver, key.ident, key.ns, binding); + if let Some(decl) = name_resolution.borrow().best_decl() { + f(resolver, key.ident, key.ns, decl); } } } @@ -842,7 +842,7 @@ enum DeclKind<'ra> { } impl<'ra> DeclKind<'ra> { - /// Is this a name binding of an import? + /// Is this an import declaration? fn is_import(&self) -> bool { matches!(*self, DeclKind::Import { .. }) } @@ -851,7 +851,7 @@ impl<'ra> DeclKind<'ra> { #[derive(Debug)] struct PrivacyError<'ra> { ident: Ident, - binding: Decl<'ra>, + decl: Decl<'ra>, dedup_span: Span, outermost_res: Option<(Res, Ident)>, parent_scope: ParentScope<'ra>, @@ -2047,15 +2047,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn record_use_inner( &mut self, ident: Ident, - used_binding: Decl<'ra>, + used_decl: Decl<'ra>, used: Used, warn_ambiguity: bool, ) { - if let Some(b2) = used_binding.ambiguity { + if let Some(b2) = used_decl.ambiguity { let ambiguity_error = AmbiguityError { kind: AmbiguityKind::GlobVsGlob, ident, - b1: used_binding, + b1: used_decl, b2, scope1: Scope::ModuleGlobs(self.empty_module, None), scope2: Scope::ModuleGlobs(self.empty_module, None), @@ -2066,7 +2066,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let DeclKind::Import { import, binding } = used_binding.kind { + if let DeclKind::Import { import, binding } = used_decl.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2096,7 +2096,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) - && entry.item_decl == Some((used_binding, false)) + && entry.item_decl == Some((used_decl, false)) { return; } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 898d198c5475..c9c754374c87 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -46,7 +46,7 @@ use crate::{ type Res = def::Res; /// Name declaration produced by a `macro_rules` item definition. -/// Not modularized, can shadow previous `macro_rules` bindings, etc. +/// Not modularized, can shadow previous `macro_rules` definitions, etc. #[derive(Debug)] pub(crate) struct MacroRulesDecl<'ra> { pub(crate) decl: Decl<'ra>, From db26d01211b55e1834b427049fc06c64a1ca0d0c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 23:51:07 +0300 Subject: [PATCH 175/340] resolve: `DeclKind::Import::binding` -> `DeclKind::Import::source_decl` --- compiler/rustc_resolve/src/diagnostics.rs | 12 +++---- .../src/effective_visibilities.rs | 6 ++-- compiler/rustc_resolve/src/imports.rs | 10 +++--- compiler/rustc_resolve/src/lib.rs | 32 +++++++++---------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7ed29b91b67a..7c86ed91a07a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1357,8 +1357,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let DeclKind::Import { binding, .. } = name_binding.kind - && this.is_accessible_from(binding.vis, parent_scope.module) + if let DeclKind::Import { source_decl, .. } = name_binding.kind + && this.is_accessible_from(source_decl.vis, parent_scope.module) && !this.is_accessible_from(name_binding.vis, parent_scope.module) { return; @@ -2210,15 +2210,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let name = next_ident; next_binding = match binding.kind { _ if res == Res::Err => None, - DeclKind::Import { binding, import, .. } => match import.kind { - _ if binding.span.is_dummy() => None, + DeclKind::Import { source_decl, import, .. } => match import.kind { + _ if source_decl.span.is_dummy() => None, ImportKind::Single { source, .. } => { next_ident = source; - Some(binding) + Some(source_decl) } ImportKind::Glob { .. } | ImportKind::MacroUse { .. } - | ImportKind::MacroExport => Some(binding), + | ImportKind::MacroExport => Some(source_decl), ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 87be913df535..e5144332f2b7 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = decl.warn_ambiguity; - while let DeclKind::Import { binding: nested_binding, .. } = decl.kind { + while let DeclKind::Import { source_decl, .. } = decl.kind { self.update_import(decl, parent_id); if is_ambiguity(decl, warn_ambiguity) { @@ -139,8 +139,8 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } parent_id = ParentId::Import(decl); - decl = nested_binding; - warn_ambiguity |= nested_binding.warn_ambiguity; + decl = source_decl; + warn_ambiguity |= source_decl.warn_ambiguity; } if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0fbfbd95a026..a8bb53cc7f27 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -316,7 +316,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.arenas.alloc_decl(DeclData { - kind: DeclKind::Import { binding: decl, import }, + kind: DeclKind::Import { source_decl: decl, import }, ambiguity: None, warn_ambiguity: false, span: import.span, @@ -1199,10 +1199,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = resolution.borrow(); if let Some(name_binding) = resolution.best_decl() { match name_binding.kind { - DeclKind::Import { binding, .. } => { - match binding.kind { - // Never suggest the name that has binding error - // i.e., the name that cannot be previously resolved + DeclKind::Import { source_decl, .. } => { + match source_decl.kind { + // Never suggest names that previously could not + // be resolved. DeclKind::Def(Res::Err) => None, _ => Some(i.name), } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 27817c0473ab..063b6b4058f0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -838,7 +838,7 @@ enum DeclKind<'ra> { /// can be provided by source code or built into the language. Def(Res), /// The name declaration is a link to another name declaration. - Import { binding: Decl<'ra>, import: Import<'ra> }, + Import { source_decl: Decl<'ra>, import: Import<'ra> }, } impl<'ra> DeclKind<'ra> { @@ -926,13 +926,13 @@ impl<'ra> DeclData<'ra> { fn res(&self) -> Res { match self.kind { DeclKind::Def(res) => res, - DeclKind::Import { binding, .. } => binding.res(), + DeclKind::Import { source_decl, .. } => source_decl.res(), } } fn import_source(&self) -> Decl<'ra> { match self.kind { - DeclKind::Import { binding, .. } => binding, + DeclKind::Import { source_decl, .. } => source_decl, _ => unreachable!(), } } @@ -941,7 +941,7 @@ impl<'ra> DeclData<'ra> { match self.ambiguity { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { - DeclKind::Import { binding, .. } => binding.descent_to_ambiguity(), + DeclKind::Import { source_decl, .. } => source_decl.descent_to_ambiguity(), _ => None, }, } @@ -950,7 +950,7 @@ impl<'ra> DeclData<'ra> { fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { - DeclKind::Import { binding, .. } => binding.is_ambiguity_recursive(), + DeclKind::Import { source_decl, .. } => source_decl.is_ambiguity_recursive(), _ => false, } } @@ -958,14 +958,14 @@ impl<'ra> DeclData<'ra> { fn warn_ambiguity_recursive(&self) -> bool { self.warn_ambiguity || match self.kind { - DeclKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), + DeclKind::Import { source_decl, .. } => source_decl.warn_ambiguity_recursive(), _ => false, } } fn is_possibly_imported_variant(&self) -> bool { match self.kind { - DeclKind::Import { binding, .. } => binding.is_possibly_imported_variant(), + DeclKind::Import { source_decl, .. } => source_decl.is_possibly_imported_variant(), DeclKind::Def(Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _)) => { true } @@ -1012,9 +1012,9 @@ impl<'ra> DeclData<'ra> { fn reexport_chain(self: Decl<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { let mut reexport_chain = SmallVec::new(); let mut next_binding = self; - while let DeclKind::Import { binding, import, .. } = next_binding.kind { + while let DeclKind::Import { source_decl, import, .. } = next_binding.kind { reexport_chain.push(import.simplify(r)); - next_binding = binding; + next_binding = source_decl; } reexport_chain } @@ -1043,9 +1043,9 @@ impl<'ra> DeclData<'ra> { // FIXME: How can we integrate it with the `update_resolution`? fn determined(&self) -> bool { match &self.kind { - DeclKind::Import { binding, import, .. } if import.is_glob() => { + DeclKind::Import { source_decl, import, .. } if import.is_glob() => { import.parent_scope.module.unexpanded_invocations.borrow().is_empty() - && binding.determined() + && source_decl.determined() } _ => true, } @@ -1985,14 +1985,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_name: Ident, ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; - while let DeclKind::Import { import, binding, .. } = kind { + while let DeclKind::Import { import, source_decl, .. } = kind { if let Some(node_id) = import.id() { let def_id = self.local_def_id(node_id); self.maybe_unused_trait_imports.insert(def_id); import_ids.push(def_id); } self.add_to_glob_map(*import, trait_name); - kind = &binding.kind; + kind = &source_decl.kind; } import_ids } @@ -2066,7 +2066,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.ambiguity_errors.push(ambiguity_error); } } - if let DeclKind::Import { import, binding } = used_decl.kind { + if let DeclKind::Import { import, source_decl } = used_decl.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. @@ -2110,9 +2110,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.add_to_glob_map(import, ident); self.record_use_inner( ident, - binding, + source_decl, Used::Other, - warn_ambiguity || binding.warn_ambiguity, + warn_ambiguity || source_decl.warn_ambiguity, ); } } From 14ac6a1d3a3e153a546d3e71b51866ca77a02dcd Mon Sep 17 00:00:00 2001 From: sgasho Date: Wed, 7 Jan 2026 00:19:09 +0900 Subject: [PATCH 176/340] Modified to output error messages appropriate to the situation --- compiler/rustc_codegen_llvm/messages.ftl | 6 ++-- compiler/rustc_codegen_llvm/src/errors.rs | 8 ++++- compiler/rustc_codegen_llvm/src/lib.rs | 12 ++++--- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 34 ++++++++++++++----- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 018d240b2ae5..85cb7499cca4 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -1,5 +1,7 @@ -codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend. - .note = load error: {$err} +codegen_llvm_autodiff_component_missing = autodiff backend not found in the sysroot: {$err} + .note = it will be distributed via rustup in the future + +codegen_llvm_autodiff_component_unavailable = failed to load our autodiff backend: {$err} codegen_llvm_autodiff_without_enable = using the autodiff feature requires -Z autodiff=Enable codegen_llvm_autodiff_without_lto = using the autodiff feature requires setting `lto="fat"` in your Cargo.toml diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 439664b8b9a2..bd42cf556966 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -34,11 +34,17 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_component_unavailable)] -#[note] pub(crate) struct AutoDiffComponentUnavailable { pub err: String, } +#[derive(Diagnostic)] +#[diag(codegen_llvm_autodiff_component_missing)] +#[note] +pub(crate) struct AutoDiffComponentMissing { + pub err: String, +} + #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_lto)] pub(crate) struct AutoDiffWithoutLto; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 801d23342973..438a74e0a091 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -249,10 +249,14 @@ impl CodegenBackend for LlvmCodegenBackend { use crate::back::lto::enable_autodiff_settings; if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { - if let Err(err) = llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { - err: format!("{err:?}"), - }); + match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { + Ok(_) => {} + Err(llvm::EnzymeLibraryError::NotFound { err }) => { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + } + Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { + sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index b11310b970d0..67fbc0f53adc 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -153,7 +153,7 @@ pub(crate) mod Enzyme_AD { fn load_ptr_by_symbol_mut_void( lib: &libloading::Library, bytes: &[u8], - ) -> Result<*mut c_void, Box> { + ) -> Result<*mut c_void, libloading::Error> { unsafe { let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?; // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some @@ -192,15 +192,27 @@ pub(crate) mod Enzyme_AD { static ENZYME_INSTANCE: OnceLock> = OnceLock::new(); + #[derive(Debug)] + pub(crate) enum EnzymeLibraryError { + NotFound { err: String }, + LoadFailed { err: String }, + } + + impl From for EnzymeLibraryError { + fn from(err: libloading::Error) -> Self { + Self::LoadFailed { err: format!("{err:?}") } + } + } + impl EnzymeWrapper { /// Initialize EnzymeWrapper with the given sysroot if not already initialized. /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock. pub(crate) fn get_or_init( sysroot: &rustc_session::config::Sysroot, - ) -> Result, Box> { + ) -> Result, EnzymeLibraryError> { let mtx: &'static Mutex = ENZYME_INSTANCE.get_or_try_init(|| { let w = Self::call_dynamic(sysroot)?; - Ok::<_, Box>(Mutex::new(w)) + Ok::<_, EnzymeLibraryError>(Mutex::new(w)) })?; Ok(mtx.lock().unwrap()) @@ -351,7 +363,7 @@ pub(crate) mod Enzyme_AD { #[allow(non_snake_case)] fn call_dynamic( sysroot: &rustc_session::config::Sysroot, - ) -> Result> { + ) -> Result { let enzyme_path = Self::get_enzyme_path(sysroot)?; let lib = unsafe { libloading::Library::new(enzyme_path)? }; @@ -416,7 +428,7 @@ pub(crate) mod Enzyme_AD { }) } - fn get_enzyme_path(sysroot: &Sysroot) -> Result { + fn get_enzyme_path(sysroot: &Sysroot) -> Result { let llvm_version_major = unsafe { LLVMRustVersionMajor() }; let path_buf = sysroot @@ -434,15 +446,19 @@ pub(crate) mod Enzyme_AD { .map(|p| p.join("lib").display().to_string()) .collect::>() .join("\n* "); - format!( - "failed to find a `libEnzyme-{llvm_version_major}` folder \ + EnzymeLibraryError::NotFound { + err: format!( + "failed to find a `libEnzyme-{llvm_version_major}` folder \ in the sysroot candidates:\n* {candidates}" - ) + ), + } })?; Ok(path_buf .to_str() - .ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))? + .ok_or_else(|| EnzymeLibraryError::LoadFailed { + err: format!("invalid UTF-8 in path: {}", path_buf.display()), + })? .to_string()) } } From 76d0843f8d05e34b49b4ec830ff745593269d8e4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 31 Oct 2025 19:07:29 +0100 Subject: [PATCH 177/340] naked functions: emit `.private_extern` on macos --- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 3 +- .../rustc_monomorphize/src/partitioning.rs | 10 +++++ tests/assembly-llvm/naked-functions/aix.rs | 2 +- tests/assembly-llvm/naked-functions/hidden.rs | 41 +++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/assembly-llvm/naked-functions/hidden.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 4a47799b2bdc..4bbb7470debe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -181,7 +181,8 @@ fn prefix_and_suffix<'tcx>( } } Linkage::Internal => { - // write nothing + // LTO can fail when internal linkage is used. + emit_fatal("naked functions may not have internal linkage") } Linkage::Common => emit_fatal("Functions may not have common linkage"), Linkage::AvailableExternally => { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1c8d6db08c31..e7af1d45cff8 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -580,6 +580,16 @@ fn internalize_symbols<'tcx>( } } + // When LTO inlines the caller of a naked function, it will attempt but fail to make the + // naked function symbol visible. To ensure that LTO works correctly, do not default + // naked functions to internal linkage and default visibility. + if let MonoItem::Fn(instance) = item { + let flags = cx.tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { + continue; + } + } + // If we got here, we did not find any uses from other CGUs, so // it's fine to make this monomorphization internal. data.linkage = Linkage::Internal; diff --git a/tests/assembly-llvm/naked-functions/aix.rs b/tests/assembly-llvm/naked-functions/aix.rs index 3cc84fa0c9c6..8391331d8341 100644 --- a/tests/assembly-llvm/naked-functions/aix.rs +++ b/tests/assembly-llvm/naked-functions/aix.rs @@ -9,7 +9,7 @@ //@[aix] needs-llvm-components: powerpc #![crate_type = "lib"] -#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] +#![feature(no_core, asm_experimental_arch)] #![no_core] // tests that naked functions work for the `powerpc64-ibm-aix` target. diff --git a/tests/assembly-llvm/naked-functions/hidden.rs b/tests/assembly-llvm/naked-functions/hidden.rs new file mode 100644 index 000000000000..7686dbab07fb --- /dev/null +++ b/tests/assembly-llvm/naked-functions/hidden.rs @@ -0,0 +1,41 @@ +//@ revisions: macos-x86 macos-aarch64 linux-x86 +//@ add-minicore +//@ assembly-output: emit-asm +// +//@[macos-aarch64] compile-flags: --target aarch64-apple-darwin +//@[macos-aarch64] needs-llvm-components: aarch64 +// +//@[macos-x86] compile-flags: --target x86_64-apple-darwin +//@[macos-x86] needs-llvm-components: x86 +// +//@[linux-x86] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux-x86] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +// Tests that naked functions that are not externally linked (e.g. via `no_mangle`) +// are marked as `Visibility::Hidden` and emit `.private_extern` or `.hidden`. +// +// Without this directive, LTO may fail because the symbol is not visible. +// See also https://github.com/rust-lang/rust/issues/148307. + +extern crate minicore; +use minicore::*; + +// CHECK: .p2align 2 +// macos-x86,macos-aarch64: .private_extern +// linux-x86: .globl +// linux-x86: .hidden +// CHECK: ret +#[unsafe(naked)] +extern "C" fn ret() { + naked_asm!("ret") +} + +// CHECK-LABEL: entry +#[no_mangle] +pub fn entry() { + ret() +} From 021a551d5da251d91251ad08f976319dc78d25c4 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 00:51:54 +0900 Subject: [PATCH 178/340] add test for repeats --- ...can-have-side-effects-depend-on-element.rs | 19 +++++++++++++++++++ ...have-side-effects-depend-on-element.stderr | 13 +++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs create mode 100644 tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs new file mode 100644 index 000000000000..cd385587d491 --- /dev/null +++ b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs @@ -0,0 +1,19 @@ +//@ check-pass + +#![allow(unused)] + +// Test if `Expr::can_have_side_effects` considers element of repeat expressions. + +fn drop_repeat_in_arm_body() { + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` (See rust-clippy#9482) + + match () { + () => drop([0; 1]), // No side effects + //~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing + } + match () { + () => drop([return; 1]), // Definitely has side effects + } +} + +fn main() {} diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr new file mode 100644 index 000000000000..0f15e7577dca --- /dev/null +++ b/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr @@ -0,0 +1,13 @@ +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/can-have-side-effects-depend-on-element.rs:11:15 + | +LL | () => drop([0; 1]), // No side effects + | ^^^^^------^ + | | + | argument has type `[i32; 1]` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(dropping_copy_types)]` on by default + +warning: 1 warning emitted + From 61ca012d4b6b1678fb6649811187d8f1335d1df8 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 00:55:58 +0900 Subject: [PATCH 179/340] rename test --- ...-on-element.rs => can-have-side-effects-consider-element.rs} | 0 ...ent.stderr => can-have-side-effects-consider-element.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/repeat-expr/{can-have-side-effects-depend-on-element.rs => can-have-side-effects-consider-element.rs} (100%) rename tests/ui/repeat-expr/{can-have-side-effects-depend-on-element.stderr => can-have-side-effects-consider-element.stderr} (87%) diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs similarity index 100% rename from tests/ui/repeat-expr/can-have-side-effects-depend-on-element.rs rename to tests/ui/repeat-expr/can-have-side-effects-consider-element.rs diff --git a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr similarity index 87% rename from tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr rename to tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr index 0f15e7577dca..6948d64ebcc3 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-depend-on-element.stderr +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/can-have-side-effects-depend-on-element.rs:11:15 + --> $DIR/can-have-side-effects-consider-element.rs:11:15 | LL | () => drop([0; 1]), // No side effects | ^^^^^------^ From 1cd87525e6b566b560a540626de9bfac6cc90b4a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 4 Jan 2026 11:23:35 +0100 Subject: [PATCH 180/340] Unix implementation for stdio set/take/replace --- library/std/src/os/unix/io/mod.rs | 129 ++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 6d4090ee31cf..708ebaec362e 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -92,9 +92,138 @@ #![stable(feature = "rust1", since = "1.0.0")] +use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; #[stable(feature = "rust1", since = "1.0.0")] pub use crate::os::fd::*; +#[allow(unused_imports)] // not used on all targets +use crate::sys::cvt; // Tests for this module #[cfg(test)] mod tests; + +#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +pub trait StdioExt: crate::sealed::Sealed { + /// Redirects the stdio file descriptor to point to the file description underpinning `fd`. + /// + /// Rust std::io write buffers (if any) are flushed, but other runtimes + /// (e.g. C stdio) or libraries that acquire a clone of the file descriptor + /// will not be aware of this change. + /// + /// # Platform-specific behavior + /// + /// This is [currently] implemented using + /// + /// - `fd_renumber` on wasip1 + /// - `dup2` on most unixes + /// + /// [currently]: crate::io#platform-specific-behavior + /// + /// ``` + /// #![feature(stdio_swap)] + /// use std::io::{self, Read, Write}; + /// use std::os::unix::io::StdioExt; + /// + /// fn main() -> io::Result<()> { + /// let (reader, mut writer) = io::pipe()?; + /// let mut stdin = io::stdin(); + /// stdin.set_fd(reader)?; + /// writer.write_all(b"Hello, world!")?; + /// let mut buffer = vec![0; 13]; + /// assert_eq!(stdin.read(&mut buffer)?, 13); + /// assert_eq!(&buffer, b"Hello, world!"); + /// Ok(()) + /// } + /// ``` + fn set_fd>(&mut self, fd: T) -> io::Result<()>; + + /// Redirects the stdio file descriptor and returns a new `OwnedFd` + /// backed by the previous file description. + /// + /// See [`set_fd()`] for details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn replace_fd>(&mut self, replace_with: T) -> io::Result; + + /// Redirects the stdio file descriptor to the null device (`/dev/null`) + /// and returns a new `OwnedFd` backed by the previous file description. + /// + /// Programs that communicate structured data via stdio can use this early in `main()` to + /// extract the fds, treat them as other IO types (`File`, `UnixStream`, etc), + /// apply custom buffering or avoid interference from stdio use later in the program. + /// + /// See [`set_fd()`] for additional details. + /// + /// [`set_fd()`]: StdioExt::set_fd + fn take_fd(&mut self) -> io::Result; +} + +macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $writer:literal) { + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + self.lock().set_fd(fd) + } + + fn take_fd(&mut self) -> io::Result { + self.lock().take_fd() + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + self.lock().replace_fd(replace_with) + } + } + + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_lock_ty { + fn set_fd>(&mut self, fd: T) -> io::Result<()> { + #[cfg($writer)] + self.flush()?; + replace_stdio_fd(self.as_fd(), fd.into()) + } + + fn take_fd(&mut self) -> io::Result { + let null = null_fd()?; + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(null)?; + Ok(cloned) + } + + fn replace_fd>(&mut self, replace_with: T) -> io::Result { + let cloned = self.as_fd().try_clone_to_owned()?; + self.set_fd(replace_with)?; + Ok(cloned) + } + } +} + +io_ext_impl!(Stdout, StdoutLock<'_>, true); +io_ext_impl!(Stdin, StdinLock<'_>, false); +io_ext_impl!(Stderr, StderrLock<'_>, true); + +fn null_fd() -> io::Result { + let null_dev = crate::fs::OpenOptions::new().read(true).write(true).open("/dev/null")?; + Ok(null_dev.into()) +} + +/// Replaces the underlying file descriptor with the one from `other`. +/// Does not set CLOEXEC. +fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { + cfg_select! { + all(target_os = "wasi", target_env = "p1") => { + cvt(unsafe { libc::__wasilibc_fd_renumber(other.as_raw_fd(), this.as_raw_fd()) }).map(|_| ()) + } + not(any( + target_arch = "wasm32", + target_os = "hermit", + target_os = "trusty", + target_os = "motor" + )) => { + cvt(unsafe {libc::dup2(other.as_raw_fd(), this.as_raw_fd())}).map(|_| ()) + } + _ => { + let _ = (this, other); + Err(io::Error::UNSUPPORTED_PLATFORM) + } + } +} From 630c7596e959e6ab9b18552e81081e5ff346b1c3 Mon Sep 17 00:00:00 2001 From: kulst Date: Thu, 1 Jan 2026 19:25:29 +0100 Subject: [PATCH 181/340] Ensure that static initializers are acyclic for NVPTX NVPTX does not support cycles in static initializers. LLVM produces an error when attempting to codegen such constructs (like self referential structs). To not produce LLVM UB we instead emit a post-monomorphization error on Rust side before reaching codegen. This is achieved by analysing a subgraph of the "mono item graph" that only contains statics: 1. Calculate the strongly connected components (SCCs) of the graph 2. Check for cycles (more than one node in a SCC or exactly one node which references itself) --- Cargo.lock | 1 + compiler/rustc_monomorphize/Cargo.toml | 1 + compiler/rustc_monomorphize/messages.ftl | 4 + compiler/rustc_monomorphize/src/collector.rs | 3 +- compiler/rustc_monomorphize/src/errors.rs | 12 ++ .../src/graph_checks/mod.rs | 18 +++ .../src/graph_checks/statics.rs | 115 ++++++++++++++++++ compiler/rustc_monomorphize/src/lib.rs | 1 + .../rustc_monomorphize/src/partitioning.rs | 3 + compiler/rustc_target/src/spec/json.rs | 3 + compiler/rustc_target/src/spec/mod.rs | 4 + .../src/spec/targets/nvptx64_nvidia_cuda.rs | 3 + .../platform-support/nvptx64-nvidia-cuda.md | 33 +++++ tests/auxiliary/minicore.rs | 2 +- ...static-initializer-acyclic-issue-146787.rs | 29 +++++ ...ic-initializer-acyclic-issue-146787.stderr | 32 +++++ 16 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/graph_checks/mod.rs create mode 100644 compiler/rustc_monomorphize/src/graph_checks/statics.rs create mode 100644 tests/ui/static/static-initializer-acyclic-issue-146787.rs create mode 100644 tests/ui/static/static-initializer-acyclic-issue-146787.stderr diff --git a/Cargo.lock b/Cargo.lock index 816bb1a37859..d0d47f882a89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4421,6 +4421,7 @@ dependencies = [ "rustc_errors", "rustc_fluent_macro", "rustc_hir", + "rustc_index", "rustc_macros", "rustc_middle", "rustc_session", diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 09a55f0b5f8d..0829d52283ab 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -10,6 +10,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index edb91d8f2eda..09500ba73359 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -75,4 +75,8 @@ monomorphize_recursion_limit = monomorphize_start_not_found = using `fn main` requires the standard library .help = use `#![no_main]` to bypass the Rust generated entrypoint and declare a platform specific entrypoint yourself, usually with `#[no_mangle]` +monomorphize_static_initializer_cyclic = static initializer forms a cycle involving `{$head}` + .label = part of this cycle + .note = cyclic static initializers are not supported for target `{$target}` + monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4b2f8e03afc1..070db1ae6b5e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -267,7 +267,8 @@ pub(crate) struct UsageMap<'tcx> { // Maps every mono item to the mono items used by it. pub used_map: UnordMap, Vec>>, - // Maps every mono item to the mono items that use it. + // Maps each mono item with users to the mono items that use it. + // Be careful: subsets `used_map`, so unused items are vacant. user_map: UnordMap, Vec>>, } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 4949d9ae3922..723649f22117 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -117,3 +117,15 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, } + +#[derive(Diagnostic)] +#[diag(monomorphize_static_initializer_cyclic)] +#[note] +pub(crate) struct StaticInitializerCyclic<'a> { + #[primary_span] + pub span: Span, + #[label] + pub labels: Vec, + pub head: &'a str, + pub target: &'a str, +} diff --git a/compiler/rustc_monomorphize/src/graph_checks/mod.rs b/compiler/rustc_monomorphize/src/graph_checks/mod.rs new file mode 100644 index 000000000000..2b9b7cfff0b2 --- /dev/null +++ b/compiler/rustc_monomorphize/src/graph_checks/mod.rs @@ -0,0 +1,18 @@ +//! Checks that need to operate on the entire mono item graph +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::TyCtxt; + +use crate::collector::UsageMap; +use crate::graph_checks::statics::check_static_initializers_are_acyclic; + +mod statics; + +pub(super) fn target_specific_checks<'tcx, 'a, 'b>( + tcx: TyCtxt<'tcx>, + mono_items: &'a [MonoItem<'tcx>], + usage_map: &'b UsageMap<'tcx>, +) { + if tcx.sess.target.options.static_initializer_must_be_acyclic { + check_static_initializers_are_acyclic(tcx, mono_items, usage_map); + } +} diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs new file mode 100644 index 000000000000..a764d307b3d4 --- /dev/null +++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs @@ -0,0 +1,115 @@ +use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::graph::scc::Sccs; +use rustc_data_structures::graph::{DirectedGraph, Successors}; +use rustc_data_structures::unord::UnordMap; +use rustc_hir::def_id::DefId; +use rustc_index::{Idx, IndexVec, newtype_index}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::TyCtxt; + +use crate::collector::UsageMap; +use crate::errors; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +struct StaticNodeIdx(usize); + +impl Idx for StaticNodeIdx { + fn new(idx: usize) -> Self { + Self(idx) + } + + fn index(self) -> usize { + self.0 + } +} + +impl From for StaticNodeIdx { + fn from(value: usize) -> Self { + StaticNodeIdx(value) + } +} + +newtype_index! { + #[derive(Ord, PartialOrd)] + struct StaticSccIdx {} +} + +// Adjacency-list graph for statics using `StaticNodeIdx` as node type. +// We cannot use `DefId` as the node type directly because each node must be +// represented by an index in the range `0..num_nodes`. +struct StaticRefGraph<'a, 'b, 'tcx> { + // maps from `StaticNodeIdx` to `DefId` and vice versa + statics: &'a FxIndexSet, + // contains for each `MonoItem` the `MonoItem`s it uses + used_map: &'b UnordMap, Vec>>, +} + +impl<'a, 'b, 'tcx> DirectedGraph for StaticRefGraph<'a, 'b, 'tcx> { + type Node = StaticNodeIdx; + + fn num_nodes(&self) -> usize { + self.statics.len() + } +} + +impl<'a, 'b, 'tcx> Successors for StaticRefGraph<'a, 'b, 'tcx> { + fn successors(&self, node_idx: StaticNodeIdx) -> impl Iterator { + let def_id = self.statics[node_idx.index()]; + self.used_map[&MonoItem::Static(def_id)].iter().filter_map(|&mono_item| match mono_item { + MonoItem::Static(def_id) => self.statics.get_index_of(&def_id).map(|idx| idx.into()), + _ => None, + }) + } +} + +pub(super) fn check_static_initializers_are_acyclic<'tcx, 'a, 'b>( + tcx: TyCtxt<'tcx>, + mono_items: &'a [MonoItem<'tcx>], + usage_map: &'b UsageMap<'tcx>, +) { + // Collect statics + let statics: FxIndexSet = mono_items + .iter() + .filter_map(|&mono_item| match mono_item { + MonoItem::Static(def_id) => Some(def_id), + _ => None, + }) + .collect(); + + // If we don't have any statics the check is not necessary + if statics.is_empty() { + return; + } + // Create a subgraph from the mono item graph, which only contains statics + let graph = StaticRefGraph { statics: &statics, used_map: &usage_map.used_map }; + // Calculate its SCCs + let sccs: Sccs = Sccs::new(&graph); + // Group statics by SCCs + let mut nodes_of_sccs: IndexVec> = + IndexVec::from_elem_n(Vec::new(), sccs.num_sccs()); + for i in graph.iter_nodes() { + nodes_of_sccs[sccs.scc(i)].push(i); + } + let is_cyclic = |nodes_of_scc: &[StaticNodeIdx]| -> bool { + match nodes_of_scc.len() { + 0 => false, + 1 => graph.successors(nodes_of_scc[0]).any(|x| x == nodes_of_scc[0]), + 2.. => true, + } + }; + // Emit errors for all cycles + for nodes in nodes_of_sccs.iter_mut().filter(|nodes| is_cyclic(nodes)) { + // We sort the nodes by their Span to have consistent error line numbers + nodes.sort_by_key(|node| tcx.def_span(statics[node.index()])); + + let head_def = statics[nodes[0].index()]; + let head_span = tcx.def_span(head_def); + + tcx.dcx().emit_err(errors::StaticInitializerCyclic { + span: head_span, + labels: nodes.iter().map(|&n| tcx.def_span(statics[n.index()])).collect(), + head: &tcx.def_path_str(head_def), + target: &tcx.sess.target.llvm_target, + }); + } +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8b48cf5a6501..5b4f74ca6a70 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed; mod collector; mod errors; +mod graph_checks; mod mono_checks; mod partitioning; mod util; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 1c8d6db08c31..6a1d64bd28bc 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -124,6 +124,7 @@ use tracing::debug; use crate::collector::{self, MonoItemCollectionStrategy, UsageMap}; use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined}; +use crate::graph_checks::target_specific_checks; struct PartitioningCx<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -1125,6 +1126,8 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio }; let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_strategy); + // Perform checks that need to operate on the entire mono item graph + target_specific_checks(tcx, &items, &usage_map); // If there was an error during collection (e.g. from one of the constants we evaluated), // then we stop here. This way codegen does not have to worry about failing constants. diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index a972299deeac..20fbb687b308 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -163,6 +163,7 @@ impl Target { forward!(relro_level); forward!(archive_format); forward!(allow_asm); + forward!(static_initializer_must_be_acyclic); forward!(main_needs_argc_argv); forward!(has_thread_local); forward!(obj_is_bitcode); @@ -360,6 +361,7 @@ impl ToJson for Target { target_option_val!(relro_level); target_option_val!(archive_format); target_option_val!(allow_asm); + target_option_val!(static_initializer_must_be_acyclic); target_option_val!(main_needs_argc_argv); target_option_val!(has_thread_local); target_option_val!(obj_is_bitcode); @@ -581,6 +583,7 @@ struct TargetSpecJson { relro_level: Option, archive_format: Option>, allow_asm: Option, + static_initializer_must_be_acyclic: Option, main_needs_argc_argv: Option, has_thread_local: Option, obj_is_bitcode: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index b06339f59425..89c9fdc935cc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2394,6 +2394,9 @@ pub struct TargetOptions { pub archive_format: StaticCow, /// Is asm!() allowed? Defaults to true. pub allow_asm: bool, + /// Static initializers must be acyclic. + /// Defaults to false + pub static_initializer_must_be_acyclic: bool, /// Whether the runtime startup code requires the `main` function be passed /// `argc` and `argv` values. pub main_needs_argc_argv: bool, @@ -2777,6 +2780,7 @@ impl Default for TargetOptions { archive_format: "gnu".into(), main_needs_argc_argv: true, allow_asm: true, + static_initializer_must_be_acyclic: false, has_thread_local: false, obj_is_bitcode: false, min_atomic_width: None, diff --git a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs index be09681b1f35..87c2693e9877 100644 --- a/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/targets/nvptx64_nvidia_cuda.rs @@ -59,6 +59,9 @@ pub(crate) fn target() -> Target { // Support using `self-contained` linkers like the llvm-bitcode-linker link_self_contained: LinkSelfContainedDefault::True, + // Static initializers must not have cycles on this target + static_initializer_must_be_acyclic: true, + ..Default::default() }, } diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md index 0eb7e1d84bd0..c722a7086967 100644 --- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md +++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md @@ -49,6 +49,39 @@ $ rustup component add llvm-tools --toolchain nightly $ rustup component add llvm-bitcode-linker --toolchain nightly ``` +## Target specific restrictions + +The PTX instruction set architecture has special requirements regarding what is +and isn't allowed. In order to avoid producing invalid PTX or generating undefined +behavior by LLVM, some Rust language features are disallowed when compiling for this target. + +### Static initializers must be acyclic + +A static's initializer must not form a cycle with itself or another static's +initializer. Therefore, the compiler will reject not only the self-referencing static `A`, +but all of the following statics. + +```Rust +struct Foo(&'static Foo); + +static A: Foo = Foo(&A); //~ ERROR static initializer forms a cycle involving `A` + +static B0: Foo = Foo(&B1); //~ ERROR static initializer forms a cycle involving `B0` +static B1: Foo = Foo(&B0); + +static C0: Foo = Foo(&C1); //~ ERROR static initializer forms a cycle involving `C0` +static C1: Foo = Foo(&C2); +static C2: Foo = Foo(&C0); +``` + +Initializers that are acyclic are allowed: + +```Rust +struct Bar(&'static u32); + +static BAR: Bar = Bar(&INT); // is allowed +static INT: u32 = 42u32; // also allowed +``` $DIR/static-initializer-acyclic-issue-146787.rs:21:1 + | +LL | static C0: Foo = Foo(&C1); + | ^^^^^^^^^^^^^^ part of this cycle +LL | static C1: Foo = Foo(&C2); + | -------------- part of this cycle +LL | static C2: Foo = Foo(&C0); + | -------------- part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: static initializer forms a cycle involving `B0` + --> $DIR/static-initializer-acyclic-issue-146787.rs:18:1 + | +LL | static B0: Foo = Foo(&B1); + | ^^^^^^^^^^^^^^ part of this cycle +LL | static B1: Foo = Foo(&B0); + | -------------- part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: static initializer forms a cycle involving `A` + --> $DIR/static-initializer-acyclic-issue-146787.rs:16:1 + | +LL | static A: Foo = Foo(&A); + | ^^^^^^^^^^^^^ part of this cycle + | + = note: cyclic static initializers are not supported for target `nvptx64-nvidia-cuda` + +error: aborting due to 3 previous errors + From f805d1b210b5bd1e765e07903804b7cdea1d48ae Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 01:08:19 +0900 Subject: [PATCH 182/340] format --- tests/ui/repeat-expr/can-have-side-effects-consider-element.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs index cd385587d491..d0b5d12455dc 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs @@ -5,7 +5,8 @@ // Test if `Expr::can_have_side_effects` considers element of repeat expressions. fn drop_repeat_in_arm_body() { - // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` (See rust-clippy#9482) + // Built-in lint `dropping_copy_types` relies on + // `Expr::can_have_side_effects` (See rust-clippy#9482) match () { () => drop([0; 1]), // No side effects From c73b64b8c518e055681ba3a35802f2f316b58988 Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 02:02:26 +0900 Subject: [PATCH 183/340] update expected output as well --- .../repeat-expr/can-have-side-effects-consider-element.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr index 6948d64ebcc3..70c7e8b404e0 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.stderr @@ -1,5 +1,5 @@ warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing - --> $DIR/can-have-side-effects-consider-element.rs:11:15 + --> $DIR/can-have-side-effects-consider-element.rs:12:15 | LL | () => drop([0; 1]), // No side effects | ^^^^^------^ From d101412517a4fdbb108c193eb1cf5632c89534f3 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 6 Jan 2026 17:23:16 +0000 Subject: [PATCH 184/340] Cleanup some ui tests for const-traits --- tests/ui/const-generics/issues/issue-88119.rs | 3 +- .../const-generics/issues/issue-88119.stderr | 95 ------------------- .../consts/rustc-impl-const-stability.stderr | 11 --- .../ui/specialization/const_trait_impl.stderr | 59 ------------ .../derive-const-non-const-type.rs | 12 +-- .../derive-const-non-const-type.stderr | 21 ++-- .../rustc-impl-const-stability.rs | 9 +- ...fault-bound-non-const-specialized-bound.rs | 8 +- ...t-bound-non-const-specialized-bound.stderr | 8 +- .../const-traits/specialization/pass.rs} | 14 ++- .../specializing-constness-2.rs | 5 +- .../specializing-constness-2.stderr | 2 +- .../specializing-constness.rs | 0 .../specializing-constness.stderr | 0 14 files changed, 35 insertions(+), 212 deletions(-) delete mode 100644 tests/ui/const-generics/issues/issue-88119.stderr delete mode 100644 tests/ui/consts/rustc-impl-const-stability.stderr delete mode 100644 tests/ui/specialization/const_trait_impl.stderr rename tests/ui/{consts => traits/const-traits}/rustc-impl-const-stability.rs (63%) rename tests/ui/{specialization/const_trait_impl.rs => traits/const-traits/specialization/pass.rs} (70%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness-2.rs (81%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness-2.stderr (88%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness.rs (100%) rename tests/ui/traits/const-traits/{ => specialization}/specializing-constness.stderr (100%) diff --git a/tests/ui/const-generics/issues/issue-88119.rs b/tests/ui/const-generics/issues/issue-88119.rs index d44b5ab985b0..fb279dd824f8 100644 --- a/tests/ui/const-generics/issues/issue-88119.rs +++ b/tests/ui/const-generics/issues/issue-88119.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 -//@ compile-flags: -Znext-solver +//@ check-pass #![allow(incomplete_features)] #![feature(const_trait_impl, generic_const_exprs)] diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr deleted file mode 100644 index 0bdf153468bc..000000000000 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ /dev/null @@ -1,95 +0,0 @@ -error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed - --> $DIR/issue-88119.rs:4:30 - | -LL | #![feature(const_trait_impl, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = help: remove one of these features - -error[E0275]: overflow evaluating the requirement `&T: [const] ConstName` - --> $DIR/issue-88119.rs:18:49 - | -LL | impl const ConstName for &T - | ^^ - -error[E0275]: overflow evaluating the requirement `&T: ConstName` - --> $DIR/issue-88119.rs:18:49 - | -LL | impl const ConstName for &T - | ^^ - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&T as ConstName>` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:20:10 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&T as ConstName>` - --> $DIR/issue-88119.rs:20:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` - -error[E0275]: overflow evaluating the requirement `&mut T: [const] ConstName` - --> $DIR/issue-88119.rs:25:49 - | -LL | impl const ConstName for &mut T - | ^^^^^^ - -error[E0275]: overflow evaluating the requirement `&mut T: ConstName` - --> $DIR/issue-88119.rs:25:49 - | -LL | impl const ConstName for &mut T - | ^^^^^^ - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&mut T as ConstName>` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` - -error[E0275]: overflow evaluating the requirement `[(); name_len::()] well-formed` - --> $DIR/issue-88119.rs:27:10 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^ - | -note: required by a bound in `<&mut T as ConstName>` - --> $DIR/issue-88119.rs:27:5 - | -LL | [(); name_len::()]:, - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` - -error[E0275]: overflow evaluating the requirement `&&mut u8: ConstName` - --> $DIR/issue-88119.rs:32:35 - | -LL | pub const ICE_1: &'static [u8] = <&&mut u8 as ConstName>::NAME_BYTES; - | ^^^^^^^^ - -error[E0275]: overflow evaluating the requirement `&mut &u8: ConstName` - --> $DIR/issue-88119.rs:33:35 - | -LL | pub const ICE_2: &'static [u8] = <&mut &u8 as ConstName>::NAME_BYTES; - | ^^^^^^^^ - -error: aborting due to 11 previous errors - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr deleted file mode 100644 index 55c085396882..000000000000 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: const `impl` for trait `Debug` which is not `const` - --> $DIR/rustc-impl-const-stability.rs:15:12 - | -LL | impl const std::fmt::Debug for Data { - | ^^^^^^^^^^^^^^^ this trait is not `const` - | - = note: marking a trait with `const` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error: aborting due to 1 previous error - diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr deleted file mode 100644 index 93ed7234e563..000000000000 --- a/tests/ui/specialization/const_trait_impl.stderr +++ /dev/null @@ -1,59 +0,0 @@ -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:33:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:39:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:45:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:39:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:33:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `const` traits - --> $DIR/const_trait_impl.rs:45:9 - | -LL | impl const A for T { - | ^^^^^^^ can't be applied to `Debug` - | -note: `Debug` can't be used with `[const]` because it isn't `const` - --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors - diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs index 0bc25ce5f650..e61ae2760aab 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.rs @@ -1,15 +1,15 @@ -//@ known-bug: #110395 -#![feature(derive_const)] +#![feature(const_default, derive_const)] pub struct A; -impl std::fmt::Debug for A { - fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - panic!() +impl Default for A { + fn default() -> A { + A } } -#[derive_const(Debug)] +#[derive_const(Default)] pub struct S(A); +//~^ ERROR: cannot call non-const associated function fn main() {} diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index 93638801895d..558957985328 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -1,20 +1,13 @@ -error: const `impl` for trait `Debug` which is not `const` - --> $DIR/derive-const-non-const-type.rs:12:16 +error[E0015]: cannot call non-const associated function `::default` in constant functions + --> $DIR/derive-const-non-const-type.rs:12:14 | -LL | #[derive_const(Debug)] - | ^^^^^ this trait is not `const` - | - = note: marking a trait with `const` ensures all default method bodies are `const` - = note: adding a non-const method body in the future would be a breaking change - -error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions - --> $DIR/derive-const-non-const-type.rs:12:16 - | -LL | #[derive_const(Debug)] - | ^^^^^ +LL | #[derive_const(Default)] + | ------- in this derive macro expansion +LL | pub struct S(A); + | ^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/rustc-impl-const-stability.rs b/tests/ui/traits/const-traits/rustc-impl-const-stability.rs similarity index 63% rename from tests/ui/consts/rustc-impl-const-stability.rs rename to tests/ui/traits/const-traits/rustc-impl-const-stability.rs index 93a5e8e4f458..7d30342d11ca 100644 --- a/tests/ui/consts/rustc-impl-const-stability.rs +++ b/tests/ui/traits/const-traits/rustc-impl-const-stability.rs @@ -1,5 +1,4 @@ -//@ compile-flags: -Znext-solver -//@ known-bug: #110395 +//@ check-pass #![crate_type = "lib"] #![feature(staged_api, const_trait_impl, const_default)] @@ -12,8 +11,8 @@ pub struct Data { #[stable(feature = "potato", since = "1.27.0")] #[rustc_const_unstable(feature = "data_foo", issue = "none")] -impl const std::fmt::Debug for Data { - fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - Ok(()) +impl const Default for Data { + fn default() -> Data { + Data { _data: 0xbeef } } } diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs index 5125d2580238..f771107ec068 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.rs @@ -1,7 +1,5 @@ // Tests that trait bounds on specializing trait impls must be `[const]` if the // same bound is present on the default impl and is `[const]` there. -//@ known-bug: #110395 -// FIXME(const_trait_impl) ^ should error #![feature(const_trait_impl)] #![feature(rustc_attrs)] @@ -23,9 +21,9 @@ where default fn bar() {} } -impl Bar for T +impl Bar for T //~ ERROR conflicting implementations of trait `Bar` where - T: Foo, //FIXME ~ ERROR missing `[const]` qualifier + T: Foo, T: Specialize, { fn bar() {} @@ -42,7 +40,7 @@ where default fn baz() {} } -impl const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz` +impl const Baz for T //~ ERROR conflicting implementations of trait `Baz` where T: Foo, T: Specialize, diff --git a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr index 85e9fda5c2a3..ff27559c8ec6 100644 --- a/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/tests/ui/traits/const-traits/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Bar` - --> $DIR/const-default-bound-non-const-specialized-bound.rs:26:1 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:24:1 | LL | / impl const Bar for T LL | | where @@ -8,19 +8,19 @@ LL | | T: [const] Foo, ... LL | / impl Bar for T LL | | where -LL | | T: Foo, //FIXME ~ ERROR missing `[const]` qualifier +LL | | T: Foo, LL | | T: Specialize, | |__________________^ conflicting implementation error[E0119]: conflicting implementations of trait `Baz` - --> $DIR/const-default-bound-non-const-specialized-bound.rs:45:1 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:43:1 | LL | / impl const Baz for T LL | | where LL | | T: [const] Foo, | |___________________- first implementation here ... -LL | / impl const Baz for T //FIXME ~ ERROR conflicting implementations of trait `Baz` +LL | / impl const Baz for T LL | | where LL | | T: Foo, LL | | T: Specialize, diff --git a/tests/ui/specialization/const_trait_impl.rs b/tests/ui/traits/const-traits/specialization/pass.rs similarity index 70% rename from tests/ui/specialization/const_trait_impl.rs rename to tests/ui/traits/const-traits/specialization/pass.rs index adfef77a15ca..0ba4e40ee30a 100644 --- a/tests/ui/specialization/const_trait_impl.rs +++ b/tests/ui/traits/const-traits/specialization/pass.rs @@ -1,8 +1,6 @@ -//@ known-bug: #110395 - -#![feature(const_trait_impl, min_specialization, rustc_attrs)] - -use std::fmt::Debug; +//@ check-pass +#![feature(const_trait_impl, const_default, min_specialization, rustc_attrs)] +#![allow(internal_features)] #[rustc_specialization_trait] pub const unsafe trait Sup { @@ -30,19 +28,19 @@ pub const trait A { fn a() -> u32; } -impl const A for T { +impl const A for T { default fn a() -> u32 { 2 } } -impl const A for T { +impl const A for T { default fn a() -> u32 { 3 } } -impl const A for T { +impl const A for T { fn a() -> u32 { T::foo() } diff --git a/tests/ui/traits/const-traits/specializing-constness-2.rs b/tests/ui/traits/const-traits/specialization/specializing-constness-2.rs similarity index 81% rename from tests/ui/traits/const-traits/specializing-constness-2.rs rename to tests/ui/traits/const-traits/specialization/specializing-constness-2.rs index 455dd111603d..78cfbe361d91 100644 --- a/tests/ui/traits/const-traits/specializing-constness-2.rs +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.rs @@ -1,5 +1,6 @@ #![feature(const_trait_impl, min_specialization, rustc_attrs)] -//@ known-bug: #110395 +#![allow(internal_features)] + #[rustc_specialization_trait] pub const trait Sup {} @@ -23,7 +24,7 @@ impl const A for T { const fn generic() { ::a(); - //FIXME ~^ ERROR: the trait bound `T: [const] Sup` is not satisfied + //~^ ERROR: the trait bound `T: [const] A` is not satisfied } fn main() {} diff --git a/tests/ui/traits/const-traits/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr similarity index 88% rename from tests/ui/traits/const-traits/specializing-constness-2.stderr rename to tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr index bd6ffa544d0e..bb1c9ac78531 100644 --- a/tests/ui/traits/const-traits/specializing-constness-2.stderr +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `T: [const] A` is not satisfied - --> $DIR/specializing-constness-2.rs:25:6 + --> $DIR/specializing-constness-2.rs:26:6 | LL | ::a(); | ^ diff --git a/tests/ui/traits/const-traits/specializing-constness.rs b/tests/ui/traits/const-traits/specialization/specializing-constness.rs similarity index 100% rename from tests/ui/traits/const-traits/specializing-constness.rs rename to tests/ui/traits/const-traits/specialization/specializing-constness.rs diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness.stderr similarity index 100% rename from tests/ui/traits/const-traits/specializing-constness.stderr rename to tests/ui/traits/const-traits/specialization/specializing-constness.stderr From 064b95ed04dca45f583c96001ef3b9eaa953fc3a Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 27 Dec 2025 22:37:19 +0000 Subject: [PATCH 185/340] Allow `expect` on `impl` for `derive_ord_xor_partial_ord` --- .../src/derive/derive_ord_xor_partial_ord.rs | 9 ++++++--- clippy_lints/src/derive/mod.rs | 2 +- tests/ui/derive_ord_xor_partial_ord.rs | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs index 2bd5e2cbfb1a..316d800a70c9 100644 --- a/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs +++ b/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs @@ -1,15 +1,16 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; +use clippy_utils::fulfill_or_allowed; use rustc_hir::{self as hir, HirId}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; -use rustc_span::{Span, sym}; +use rustc_span::sym; use super::DERIVE_ORD_XOR_PARTIAL_ORD; /// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - span: Span, + item: &hir::Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>, adt_hir_id: HirId, @@ -19,6 +20,8 @@ pub(super) fn check<'tcx>( && let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait() && let Some(def_id) = &trait_ref.trait_def_id() && *def_id == ord_trait_def_id + && let item_hir_id = cx.tcx.local_def_id_to_hir_id(item.owner_id) + && !fulfill_or_allowed(cx, DERIVE_ORD_XOR_PARTIAL_ORD, [adt_hir_id]) { // Look for the PartialOrd implementations for `ty` cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { @@ -39,7 +42,7 @@ pub(super) fn check<'tcx>( "you are deriving `Ord` but have implemented `PartialOrd` explicitly" }; - span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, adt_hir_id, span, mess, |diag| { + span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, item_hir_id, item.span, mess, |diag| { if let Some(local_def_id) = impl_id.as_local() { let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here"); diff --git a/clippy_lints/src/derive/mod.rs b/clippy_lints/src/derive/mod.rs index eafe7c4bb9f2..86614201c406 100644 --- a/clippy_lints/src/derive/mod.rs +++ b/clippy_lints/src/derive/mod.rs @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive { let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id()); derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); - derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived); + derive_ord_xor_partial_ord::check(cx, item, trait_ref, ty, adt_hir_id, is_automatically_derived); if is_automatically_derived { unsafe_derive_deserialize::check(cx, item, trait_ref, ty, adt_hir_id); diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index b4bb24b0d2fe..386ab39401c5 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -91,3 +91,17 @@ mod issue15708 { } } } + +mod issue16298 { + #[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)] + struct Normalized(S); + + impl Eq for Normalized {} + + #[expect(clippy::derive_ord_xor_partial_ord)] + impl Ord for Normalized { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } + } +} From 1f207edc5a646a6c4d98f929423974bbe3a1cb5e Mon Sep 17 00:00:00 2001 From: keir Date: Wed, 17 Dec 2025 19:04:50 +0530 Subject: [PATCH 186/340] fix(useless_conversion): stop adjustments when target type is reached --- clippy_lints/src/useless_conversion.rs | 14 ++- tests/ui/useless_conversion.fixed | 10 ++ tests/ui/useless_conversion.rs | 10 ++ tests/ui/useless_conversion.stderr | 135 ++++++++++++++----------- 4 files changed, 109 insertions(+), 60 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c06313d1a4c4..423301edfe83 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -456,13 +456,25 @@ fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) fn adjustments(cx: &LateContext<'_>, expr: &Expr<'_>) -> String { let mut prefix = String::new(); - for adj in cx.typeck_results().expr_adjustments(expr) { + + let adjustments = cx.typeck_results().expr_adjustments(expr); + + let [.., last] = adjustments else { return prefix }; + let target = last.target; + + for adj in adjustments { match adj.kind { Adjust::Deref(_) => prefix = format!("*{prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) => prefix = format!("&mut {prefix}"), Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Not)) => prefix = format!("&{prefix}"), _ => {}, } + + // Stop once we reach the final target type. + // This prevents over-adjusting (e.g. suggesting &**y instead of *y). + if adj.target == target { + break; + } } prefix } diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index adf5e58d9a1a..4832e922fa8e 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(*items); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index d95fe49e2e2b..6ef1f93a5606 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] @@ -131,6 +132,15 @@ fn main() { dont_lint_into_iter_on_copy_iter(); dont_lint_into_iter_on_static_copy_iter(); + { + // triggers the IntoIterator trait + fn consume(_: impl IntoIterator) {} + + // Should suggest `*items` instead of `&**items` + let items = &&[1, 2, 3]; + consume(items.into_iter()); //~ useless_conversion + } + let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 052c664f6f2e..d28b7a5cbfb6 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:9:13 + --> tests/ui/useless_conversion.rs:10:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,115 +11,132 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:11:5 + --> tests/ui/useless_conversion.rs:12:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:24:22 + --> tests/ui/useless_conversion.rs:25:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:55:22 + --> tests/ui/useless_conversion.rs:56:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:61:21 + --> tests/ui/useless_conversion.rs:62:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:68:22 + --> tests/ui/useless_conversion.rs:69:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:75:13 + --> tests/ui/useless_conversion.rs:76:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:81:17 + --> tests/ui/useless_conversion.rs:82:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:141:17 + | +LL | consume(items.into_iter()); + | ^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:137:28 + | +LL | fn consume(_: impl IntoIterator) {} + | ^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - consume(items.into_iter()); +LL + consume(*items); + | + error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:144:21 + --> tests/ui/useless_conversion.rs:154:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:146:21 + --> tests/ui/useless_conversion.rs:156:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:148:13 + --> tests/ui/useless_conversion.rs:158:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:150:13 + --> tests/ui/useless_conversion.rs:160:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:152:13 + --> tests/ui/useless_conversion.rs:162:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:154:13 + --> tests/ui/useless_conversion.rs:164:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:156:21 + --> tests/ui/useless_conversion.rs:166:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:162:13 + --> tests/ui/useless_conversion.rs:172:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:169:23 + --> tests/ui/useless_conversion.rs:179:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:172:13 + --> tests/ui/useless_conversion.rs:182:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:175:13 + --> tests/ui/useless_conversion.rs:185:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:208:7 + --> tests/ui/useless_conversion.rs:218:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -127,13 +144,13 @@ LL | b(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:210:7 + --> tests/ui/useless_conversion.rs:220:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -141,13 +158,13 @@ LL | c(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:199:18 + --> tests/ui/useless_conversion.rs:209:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:212:7 + --> tests/ui/useless_conversion.rs:222:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -155,13 +172,13 @@ LL | d(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:202:12 + --> tests/ui/useless_conversion.rs:212:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:216:7 + --> tests/ui/useless_conversion.rs:226:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^------------------------ @@ -169,13 +186,13 @@ LL | b(vec![1, 2].into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:218:7 + --> tests/ui/useless_conversion.rs:228:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^------------------------------------ @@ -183,13 +200,13 @@ LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:198:13 + --> tests/ui/useless_conversion.rs:208:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:265:24 + --> tests/ui/useless_conversion.rs:275:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -197,13 +214,13 @@ LL | foo2::([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:244:12 + --> tests/ui/useless_conversion.rs:254:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:274:14 + --> tests/ui/useless_conversion.rs:284:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -211,13 +228,13 @@ LL | foo3([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:253:12 + --> tests/ui/useless_conversion.rs:263:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:284:16 + --> tests/ui/useless_conversion.rs:294:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^------------ @@ -225,13 +242,13 @@ LL | S1.foo([1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:281:27 + --> tests/ui/useless_conversion.rs:291:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:304:44 + --> tests/ui/useless_conversion.rs:314:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^------------ @@ -239,67 +256,67 @@ LL | v0.into_iter().interleave_shortest(v1.into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:291:20 + --> tests/ui/useless_conversion.rs:301:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:332:58 + --> tests/ui/useless_conversion.rs:342:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:335:58 + --> tests/ui/useless_conversion.rs:345:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:338:58 + --> tests/ui/useless_conversion.rs:348:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:341:58 + --> tests/ui/useless_conversion.rs:351:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:345:31 + --> tests/ui/useless_conversion.rs:355:31 | LL | let _: ControlFlow<()> = c.map_break(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:349:31 + --> tests/ui/useless_conversion.rs:359:31 | LL | let _: ControlFlow<()> = c.map_continue(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `u32` - --> tests/ui/useless_conversion.rs:363:41 + --> tests/ui/useless_conversion.rs:373:41 | LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:374:18 + --> tests/ui/useless_conversion.rs:384:18 | LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:390:29 + --> tests/ui/useless_conversion.rs:400:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -310,13 +327,13 @@ LL + takes_into_iter(&self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:398:29 + --> tests/ui/useless_conversion.rs:408:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,13 +344,13 @@ LL + takes_into_iter(&mut self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:407:29 + --> tests/ui/useless_conversion.rs:417:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -344,13 +361,13 @@ LL + takes_into_iter(*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:416:29 + --> tests/ui/useless_conversion.rs:426:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,13 +378,13 @@ LL + takes_into_iter(&*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:425:29 + --> tests/ui/useless_conversion.rs:435:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:379:32 + --> tests/ui/useless_conversion.rs:389:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -378,22 +395,22 @@ LL + takes_into_iter(&mut *self.my_field); | error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:440:5 + --> tests/ui/useless_conversion.rs:450:5 | LL | R.into_iter().for_each(|_x| {}); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:442:13 + --> tests/ui/useless_conversion.rs:452:13 | LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::slice::Iter<'_, i32>` - --> tests/ui/useless_conversion.rs:453:14 + --> tests/ui/useless_conversion.rs:463: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 +error: aborting due to 45 previous errors From af69f157129e154f050a224ba384703e57115032 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Tue, 6 Jan 2026 22:09:11 +0100 Subject: [PATCH 187/340] Add AtomicPtr::null --- library/core/src/sync/atomic.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1eae06ebd33e..c675fd1381d8 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1550,6 +1550,23 @@ impl AtomicPtr { unsafe { &*ptr.cast() } } + /// Creates a new `AtomicPtr` initialized with a null pointer. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let atomic_ptr = AtomicPtr::<()>::null(); + /// assert!(atomic_ptr.load(Ordering::Relaxed).is_null()); + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "atomic_ptr_null", issue = "150733")] + pub const fn null() -> AtomicPtr { + AtomicPtr::new(crate::ptr::null_mut()) + } + /// Returns a mutable reference to the underlying pointer. /// /// This is safe because the mutable reference guarantees that no other threads are From 0dfff23114662255119e33030de7ccc289a385b0 Mon Sep 17 00:00:00 2001 From: Shunpoco Date: Tue, 6 Jan 2026 21:43:21 +0000 Subject: [PATCH 188/340] address reviews --- src/tools/tidy/src/extra_checks/mod.rs | 3 +- src/tools/tidy/src/extra_checks/tests.rs | 46 ++++++++++++------------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index a1d9ad436885..1c81a485608a 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -121,12 +121,12 @@ fn check_impl( .collect(), None => vec![], }; + lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); if lint_args.iter().any(|ck| ck.auto) { crate::files_modified_batch_filter(ci_info, &mut lint_args, |ck, path| { ck.is_non_auto_or_matches(path) }); } - lint_args.retain(|ck| ck.is_non_if_installed_or_matches(root_path, outdir)); macro_rules! extra_check { ($lang:ident, $kind:ident) => { @@ -963,7 +963,6 @@ impl FromStr for ExtraCheckArg { }; if_installed = true; first = part; - continue; } _ => break, } diff --git a/src/tools/tidy/src/extra_checks/tests.rs b/src/tools/tidy/src/extra_checks/tests.rs index 62501803b255..5d274069a80c 100644 --- a/src/tools/tidy/src/extra_checks/tests.rs +++ b/src/tools/tidy/src/extra_checks/tests.rs @@ -7,80 +7,80 @@ fn test_extra_check_arg_from_str_ok() { let test_cases = [ ( "auto:if-installed:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "if-installed:auto:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "auto:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: true, if_installed: false, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "if-installed:spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: true, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "spellcheck", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: false, lang: ExtraCheckLang::Spellcheck, kind: None, - }), + }, ), ( "js:lint", - Ok(ExtraCheckArg { + ExtraCheckArg { auto: false, if_installed: false, lang: ExtraCheckLang::Js, kind: Some(ExtraCheckKind::Lint), - }), + }, ), ]; for (s, expected) in test_cases { - assert_eq!(ExtraCheckArg::from_str(s), expected); + assert_eq!(ExtraCheckArg::from_str(s), Ok(expected)); } } #[test] fn test_extra_check_arg_from_str_err() { let test_cases = [ - ("some:spellcheck", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), - ("spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), - ("spellcheck:lint", Err(ExtraCheckParseError::UnsupportedKindForLang)), - ("auto:spellcheck:some", Err(ExtraCheckParseError::UnknownKind("some".to_string()))), - ("auto:js:lint:some", Err(ExtraCheckParseError::TooManyParts)), - ("some", Err(ExtraCheckParseError::UnknownLang("some".to_string()))), - ("auto", Err(ExtraCheckParseError::AutoRequiresLang)), - ("if-installed", Err(ExtraCheckParseError::IfInstalledRequiresLang)), - ("", Err(ExtraCheckParseError::Empty)), + ("some:spellcheck", ExtraCheckParseError::UnknownLang("some".to_string())), + ("spellcheck:some", ExtraCheckParseError::UnknownKind("some".to_string())), + ("spellcheck:lint", ExtraCheckParseError::UnsupportedKindForLang), + ("auto:spellcheck:some", ExtraCheckParseError::UnknownKind("some".to_string())), + ("auto:js:lint:some", ExtraCheckParseError::TooManyParts), + ("some", ExtraCheckParseError::UnknownLang("some".to_string())), + ("auto", ExtraCheckParseError::AutoRequiresLang), + ("if-installed", ExtraCheckParseError::IfInstalledRequiresLang), + ("", ExtraCheckParseError::Empty), ]; for (s, expected) in test_cases { - assert_eq!(ExtraCheckArg::from_str(s), expected); + assert_eq!(ExtraCheckArg::from_str(s), Err(expected)); } } From bd0d0f707e10fe9ee278c53c58f5cd7bce7f2bda Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 6 Jan 2026 23:02:48 +0100 Subject: [PATCH 189/340] Factorize triagebot float parsing mentions with a glob matching --- triagebot.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index fbb2bac2267b..2d3757d241f5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1059,14 +1059,10 @@ gets adapted for the changes, if necessary. """ cc = ["@rust-lang/miri", "@RalfJung", "@oli-obk", "@lcnr"] -[mentions."library/core/src/num/dec2flt"] +[mentions."library/core/src/num/{dec2flt,flt2dec}"] message = "Some changes occurred in float parsing" cc = ["@tgross35"] -[mentions."library/core/src/num/flt2dec"] -message = "Some changes occurred in float printing" -cc = ["@tgross35"] - [mentions."library/core/src/fmt/num.rs"] message = "Some changes occurred in integer formatting" cc = ["@tgross35"] From fff9c623bfc75bce9f9e5c64ed67d9b04ea655c1 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Tue, 6 Jan 2026 23:38:31 +0100 Subject: [PATCH 190/340] Add feature to doc example --- library/core/src/sync/atomic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index c675fd1381d8..22f46ec385ce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1555,6 +1555,7 @@ impl AtomicPtr { /// # Examples /// /// ``` + /// #![feature(atomic_ptr_null)] /// use std::sync::atomic::{AtomicPtr, Ordering}; /// /// let atomic_ptr = AtomicPtr::<()>::null(); From af76a2456d1ce3ff200215e3593c10090ddfa725 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 4 Jan 2026 10:36:36 +0800 Subject: [PATCH 191/340] MGCA: Support tuple expressions as direct const arguments --- compiler/rustc_ast_lowering/src/lib.rs | 18 +++++ compiler/rustc_hir/src/hir.rs | 2 + compiler/rustc_hir/src/intravisit.rs | 4 ++ compiler/rustc_hir_analysis/src/collect.rs | 9 +-- .../src/hir_ty_lowering/mod.rs | 68 ++++++++++++++----- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 10 +++ .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 4 +- src/librustdoc/clean/mod.rs | 7 +- .../doesnt_unify_evaluatable.stderr | 4 +- .../mgca/adt_expr_arg_tuple_expr_complex.rs | 20 ++++++ .../adt_expr_arg_tuple_expr_complex.stderr | 26 +++++++ .../mgca/adt_expr_arg_tuple_expr_simple.rs | 22 ++++++ ...ce-hir-wf-check-anon-const-issue-122989.rs | 1 - ...ir-wf-check-anon-const-issue-122989.stderr | 26 +------ 18 files changed, 177 insertions(+), 53 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e11e24c0263f..5c65aa192b7e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2427,6 +2427,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), } } + ExprKind::Tup(exprs) => { + let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| { + let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind { + let def_id = self.local_def_id(anon_const.id); + let def_kind = self.tcx.def_kind(def_id); + assert_eq!(DefKind::AnonConst, def_kind); + + self.lower_anon_const_to_const_arg(anon_const) + } else { + self.lower_expr_to_const_arg_direct(&expr) + }; + + &*self.arena.alloc(expr) + })); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(expr.span, exprs) } + } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( expr.id, @@ -2495,6 +2512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | ExprKind::Path(..) | ExprKind::Struct(..) | ExprKind::Call(..) + | ExprKind::Tup(..) ) { return self.lower_expr_to_const_arg_direct(expr); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..5c3f0e5ccd31 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -497,6 +497,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { pub fn span(&self) -> Span { match self.kind { + ConstArgKind::Tup(span, ..) => span, ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), ConstArgKind::TupleCall(path, _) => path.span(), @@ -511,6 +512,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { + Tup(Span, &'hir [&'hir ConstArg<'hir, Unambig>]), /// **Note:** Currently this is only used for bare const params /// (`N` where `fn foo(...)`), /// not paths to any const (`N` where `const N: usize = ...`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 853e7db0757a..576f74b8b02b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1081,6 +1081,10 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( let ConstArg { hir_id, kind } = const_arg; try_visit!(visitor.visit_id(*hir_id)); match kind { + ConstArgKind::Tup(_, exprs) => { + walk_list!(visitor, visit_const_arg, *exprs); + V::Result::output() + } ConstArgKind::Struct(qpath, field_exprs) => { try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9343bcd27a33..9d4cb6d7684b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1493,9 +1493,10 @@ fn const_param_default<'tcx>( }; let icx = ItemCtxt::new(tcx, def_id); let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); - let ct = icx - .lowerer() - .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + let ct = icx.lowerer().lower_const_arg( + default_ct, + FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args), + ); ty::EarlyBinder::bind(ct) } @@ -1553,7 +1554,7 @@ fn const_of_item<'tcx>( let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let ct = icx .lowerer() - .lower_const_arg(ct_arg, FeedConstTy::Param(def_id.to_def_id(), identity_args)); + .lower_const_arg(ct_arg, FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args)); if let Err(e) = icx.check_tainted_by_errors() && !ct.references_error() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a22729fd287e..ad037c195d55 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -259,17 +259,26 @@ impl AssocItemQSelf { /// Use this enum with `::lower_const_arg` to instruct it with the /// desired behavior. #[derive(Debug, Clone, Copy)] -pub enum FeedConstTy<'a, 'tcx> { - /// Feed the type. - /// +pub enum FeedConstTy<'tcx> { + /// Feed the type to the (anno) const arg. + WithTy(Ty<'tcx>), + /// Don't feed the type. + No, +} + +impl<'tcx> FeedConstTy<'tcx> { /// The `DefId` belongs to the const param that we are supplying /// this (anon) const arg to. /// /// The list of generic args is used to instantiate the parameters /// used by the type of the const param specified by `DefId`. - Param(DefId, &'a [ty::GenericArg<'tcx>]), - /// Don't feed the type. - No, + pub fn with_type_of( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generic_args: &[ty::GenericArg<'tcx>], + ) -> Self { + Self::WithTy(tcx.type_of(def_id).instantiate(tcx, generic_args)) + } } #[derive(Debug, Clone, Copy)] @@ -723,7 +732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Ambig portions of `ConstArg` are handled in the match arm below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(tcx, param.def_id, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { @@ -2303,15 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_const_arg( &self, const_arg: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); - if let FeedConstTy::Param(param_def_id, args) = feed + if let FeedConstTy::WithTy(anon_const_type) = feed && let hir::ConstArgKind::Anon(anon) = &const_arg.kind { - let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args); - // FIXME(generic_const_parameter_types): Ideally we remove these errors below when // we have the ability to intermix typeck of anon const const args with the parent // bodies typeck. @@ -2352,14 +2359,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - tcx.feed_anon_const_type( - anon.def_id, - ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)), - ); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type)); } let hir_id = const_arg.hir_id; match const_arg.kind { + hir::ConstArgKind::Tup(span, exprs) => self.lower_const_arg_tup(exprs, feed, span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2464,7 +2469,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .zip(args) .map(|(field_def, arg)| { - self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args)) + self.lower_const_arg(arg, FeedConstTy::with_type_of(tcx, field_def.did, adt_args)) }) .collect::>(); @@ -2480,6 +2485,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_value(tcx, valtree, adt_ty) } + fn lower_const_arg_tup( + &self, + exprs: &'tcx [&'tcx hir::ConstArg<'tcx>], + feed: FeedConstTy<'tcx>, + span: Span, + ) -> Const<'tcx> { + let tcx = self.tcx(); + + let FeedConstTy::WithTy(ty) = feed else { + return Const::new_error_with_message(tcx, span, "unsupported const tuple"); + }; + + let ty::Tuple(tys) = ty.kind() else { + return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type"); + }; + + let exprs = exprs + .iter() + .zip(tys.iter()) + .map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::WithTy(ty))) + .collect::>(); + + let valtree = ty::ValTree::from_branches(tcx, exprs); + ty::Const::new_value(tcx, valtree, ty) + } + fn lower_const_arg_struct( &self, hir_id: HirId, @@ -2558,7 +2589,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return ty::Const::new_error(tcx, e); } - self.lower_const_arg(expr.expr, FeedConstTy::Param(field_def.did, adt_args)) + self.lower_const_arg( + expr.expr, + FeedConstTy::with_type_of(tcx, field_def.did, adt_args), + ) } None => { let e = tcx.dcx().span_err( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 65f6a11e8e9b..7296ba6f964a 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -301,7 +301,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, hir_ct: &hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 932e78958345..d360a18676ff 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1141,6 +1141,16 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { + ConstArgKind::Tup(_, exprs) => { + self.popen(); + self.commasep_cmnt( + Inconsistent, + exprs, + |s, arg| s.print_const_arg(arg), + |arg| arg.span(), + ); + self.pclose(); + } ConstArgKind::Struct(qpath, fields) => self.print_const_struct(qpath, fields), ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 339e77ac6edd..a66ff2a23c25 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy<'_, 'tcx>, + feed: FeedConstTy<'tcx>, ) -> ty::Const<'tcx> { let ct = self.lowerer().lower_const_arg(const_arg, feed); self.register_wf_obligation( @@ -1228,7 +1228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Ambiguous parts of `ConstArg` are handled in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(self.fcx.tcx, param.def_id, preceding_args), ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e81537008bb5..aab4e3985555 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -447,7 +447,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We handle the ambig portions of `ConstArg` in the match arms below .lower_const_arg( ct.as_unambig_ct(), - FeedConstTy::Param(param.def_id, preceding_args), + FeedConstTy::with_type_of(self.cfcx.tcx, param.def_id, preceding_args), ) .into(), (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d79ab9eaf759..d0e8bc50c495 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1442,6 +1442,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ConstArgKind::Error(..) | hir::ConstArgKind::Struct(..) | hir::ConstArgKind::TupleCall(..) + | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f7b85453448c..b392b7747b55 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -419,7 +419,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Avoid overwriting `const_arg_context` as we may want to treat const blocks // as being anon consts if we are inside a const argument. - ExprKind::Struct(_) | ExprKind::Call(..) => return visit::walk_expr(self, expr), + ExprKind::Struct(_) | ExprKind::Call(..) | ExprKind::Tup(..) => { + return visit::walk_expr(self, expr); + } // FIXME(mgca): we may want to handle block labels in some manner ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { // FIXME(mgca): this probably means that mac calls that expand diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0768e6a56b3c..01f5d6f22f91 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -326,6 +326,10 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::TupleCall(..) => { ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() } } + hir::ConstArgKind::Tup(..) => { + // FIXME(mgca): proper printing :3 + ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1809,7 +1813,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T } hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) - | hir::ConstArgKind::TupleCall(..) => { + | hir::ConstArgKind::TupleCall(..) + | hir::ConstArgKind::Tup(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr index 6cf4e881adae..62bebd53b14a 100644 --- a/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr +++ b/tests/ui/const-generics/generic_const_exprs/assoc_const_unification/doesnt_unify_evaluatable.stderr @@ -1,8 +1,8 @@ error: unconstrained generic constant - --> $DIR/doesnt_unify_evaluatable.rs:9:11 + --> $DIR/doesnt_unify_evaluatable.rs:9:13 | LL | bar::<{ T::ASSOC }>(); - | ^^^^^^^^^^^^ + | ^^^^^^^^ | help: try adding a `where` bound | diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs new file mode 100644 index 000000000000..e47052523fa3 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.rs @@ -0,0 +1,20 @@ +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_tuple::<{ (N, T::ASSOC + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + + takes_nested_tuple::<{ (N, (N, N + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block + takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); //~ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr new file mode 100644 index 000000000000..dbc64a1bf59d --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_complex.stderr @@ -0,0 +1,26 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:13:25 + | +LL | takes_tuple::<{ (N, N + 1) }>(); + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:14:25 + | +LL | takes_tuple::<{ (N, T::ASSOC + 1) }>(); + | ^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:16:36 + | +LL | takes_nested_tuple::<{ (N, (N, N + 1)) }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/adt_expr_arg_tuple_expr_complex.rs:17:44 + | +LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); + | ^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs new file mode 100644 index 000000000000..60c4c6e952cf --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N2) }>(); + takes_tuple::<{ (N, T::ASSOC) }>(); + + takes_nested_tuple::<{ (N, (N, N2)) }>(); + takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); +} + +fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index 519e913480ec..f2b9f037ea5f 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,7 +4,6 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` - //~| ERROR cycle detected when computing type of `Foo::N` fn func() {} } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index 0ecb3e74eb57..4024f57af4ff 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,26 +44,6 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `Foo::N` - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:11 - | -LL | trait Foo> { - | ^^^^^^^^^^^^^^^ - | -note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 - | -LL | trait Bar> {} - | ^^^^^^^^^^^^^^^ - = note: ...which again requires computing type of `Foo::N`, completing the cycle -note: cycle used when checking that `Foo` is well-formed - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:1 - | -LL | trait Foo> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0391`. From d572e6d415ab0796ef6d7beb960ff479be3628c2 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 6 Jan 2026 20:23:31 +0800 Subject: [PATCH 192/340] Add span field for ConstArg --- compiler/rustc_ast_lowering/src/index.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 47 ++++++++++++++----- compiler/rustc_ast_lowering/src/pat.rs | 3 +- compiler/rustc_hir/src/hir.rs | 25 +++------- compiler/rustc_hir/src/hir/tests.rs | 12 +++-- compiler/rustc_hir/src/intravisit.rs | 10 ++-- .../src/hir_ty_lowering/errors.rs | 4 +- .../src/hir_ty_lowering/mod.rs | 18 +++---- compiler/rustc_hir_pretty/src/lib.rs | 6 +-- compiler/rustc_hir_typeck/src/expr.rs | 4 +- compiler/rustc_lint/src/pass_by_value.rs | 9 ++-- compiler/rustc_middle/src/hir/map.rs | 2 +- .../src/error_reporting/infer/mod.rs | 2 +- .../clippy_lints/src/large_stack_arrays.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 16 +++++++ .../mgca/adt_expr_erroneuous_inits.stderr | 6 +-- ...inting_valtrees_supports_non_values.stderr | 8 ++-- .../mgca/tuple_ctor_erroneous.stderr | 10 ++-- 20 files changed, 111 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index f6edcaa64dfe..be0a1d490da6 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -312,7 +312,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) { self.insert( - const_arg.as_unambig_ct().span(), + const_arg.as_unambig_ct().span, const_arg.hir_id, Node::ConstArg(const_arg.as_unambig_ct()), ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5c65aa192b7e..a81d2297ef85 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2285,8 +2285,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer` match c.value.peel_parens().kind { ExprKind::Underscore => { - let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ()); - self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind }) + let ct_kind = hir::ConstArgKind::Infer(()); + self.arena.alloc(hir::ConstArg { + hir_id: self.lower_node_id(c.id), + kind: ct_kind, + span: self.lower_span(c.value.span), + }) } _ => self.lower_anon_const_to_const_arg_and_alloc(c), } @@ -2356,7 +2360,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::ConstArgKind::Anon(ct) }; - self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind }) + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: ct_kind, + span: self.lower_span(span), + }) } fn lower_const_item_rhs( @@ -2373,9 +2381,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let const_arg = ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Error( - DUMMY_SP, self.dcx().span_delayed_bug(DUMMY_SP, "no block"), ), + span: DUMMY_SP, }; hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg)) } @@ -2388,13 +2396,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self), ret)] fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { + let span = self.lower_span(expr.span); + 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()) } + ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span } }; match &expr.kind { @@ -2425,6 +2435,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::TupleCall(qpath, lowered_args), + span, } } ExprKind::Tup(exprs) => { @@ -2442,7 +2453,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &*self.arena.alloc(expr) })); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(expr.span, exprs) } + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span } } ExprKind::Path(qself, path) => { let qpath = self.lower_qpath( @@ -2456,7 +2467,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, ); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span } } ExprKind::Struct(se) => { let path = self.lower_qpath( @@ -2497,11 +2508,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) })); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Struct(path, fields), + span, + } } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), - kind: hir::ConstArgKind::Infer(expr.span, ()), + kind: hir::ConstArgKind::Infer(()), + span, }, ExprKind::Block(block, _) => { if let [stmt] = block.stmts.as_slice() @@ -2546,7 +2562,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(lowered_anon), + span: lowered_anon.span, + } } MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), }; @@ -2583,11 +2603,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return ConstArg { hir_id: self.lower_node_id(anon.id), kind: hir::ConstArgKind::Path(qpath), + span: self.lower_span(expr.span), }; } let lowered_anon = self.lower_anon_const_to_anon_const(anon); - ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(lowered_anon), + span: self.lower_span(expr.span), + } } /// See [`hir::ConstArg`] for when to use this function vs diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index f09bbb9c4972..e066bce95158 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -513,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)), + span, }) } @@ -557,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) }); let hir_id = self.next_id(); - self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id }) + self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span }) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5c3f0e5ccd31..dc6790f7a3f1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -423,7 +423,7 @@ impl<'hir> ConstItemRhs<'hir> { pub fn span<'tcx>(&self, tcx: impl crate::intravisit::HirTyCtxt<'tcx>) -> Span { match self { ConstItemRhs::Body(body_id) => tcx.hir_body(*body_id).value.span, - ConstItemRhs::TypeConst(ct_arg) => ct_arg.span(), + ConstItemRhs::TypeConst(ct_arg) => ct_arg.span, } } } @@ -447,6 +447,7 @@ pub struct ConstArg<'hir, Unambig = ()> { #[stable_hasher(ignore)] pub hir_id: HirId, pub kind: ConstArgKind<'hir, Unambig>, + pub span: Span, } impl<'hir> ConstArg<'hir, AmbigArg> { @@ -475,7 +476,7 @@ impl<'hir> ConstArg<'hir> { /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if /// infer consts are relevant to you then care should be taken to handle them separately. pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> { - if let ConstArgKind::Infer(_, ()) = self.kind { + if let ConstArgKind::Infer(()) = self.kind { return None; } @@ -494,25 +495,13 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { _ => None, } } - - pub fn span(&self) -> Span { - match self.kind { - ConstArgKind::Tup(span, ..) => span, - ConstArgKind::Struct(path, _) => path.span(), - ConstArgKind::Path(path) => path.span(), - ConstArgKind::TupleCall(path, _) => path.span(), - ConstArgKind::Anon(anon) => anon.span, - ConstArgKind::Error(span, _) => span, - ConstArgKind::Infer(span, _) => span, - } - } } /// See [`ConstArg`]. #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { - Tup(Span, &'hir [&'hir ConstArg<'hir, Unambig>]), + Tup(&'hir [&'hir ConstArg<'hir, Unambig>]), /// **Note:** Currently this is only used for bare const params /// (`N` where `fn foo(...)`), /// not paths to any const (`N` where `const N: usize = ...`). @@ -525,10 +514,10 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// Tuple constructor variant TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]), /// Error const - Error(Span, ErrorGuaranteed), + Error(ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes /// [`GenericArg::Infer`] is used instead. - Infer(Span, Unambig), + Infer(Unambig), } #[derive(Clone, Copy, Debug, HashStable_Generic)] @@ -574,7 +563,7 @@ impl GenericArg<'_> { match self { GenericArg::Lifetime(l) => l.ident.span, GenericArg::Type(t) => t.span, - GenericArg::Const(c) => c.span(), + GenericArg::Const(c) => c.span, GenericArg::Infer(i) => i.span, } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 4f9609fd360d..2ac33a369cbd 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -24,12 +24,16 @@ define_tests! { cast_ptr TyKind Ptr { 0: MutTy { ty: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, mutbl: Mutability::Not }} cast_array TyKind Array { 0: &Ty { span: DUMMY_SP, hir_id: HirId::INVALID, kind: TyKind::Never }, - 1: &ConstArg { hir_id: HirId::INVALID, kind: ConstArgKind::Anon(&AnonConst { + 1: &ConstArg { hir_id: HirId::INVALID, - def_id: LocalDefId { local_def_index: DefIndex::ZERO }, - body: BodyId { hir_id: HirId::INVALID }, + kind: ConstArgKind::Anon(&AnonConst { + hir_id: HirId::INVALID, + def_id: LocalDefId { local_def_index: DefIndex::ZERO }, + body: BodyId { hir_id: HirId::INVALID }, + span: DUMMY_SP, + }), span: DUMMY_SP, - })} + }, } cast_anon ConstArgKind Anon { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 576f74b8b02b..59db60fdc55c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1068,8 +1068,8 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( match const_arg.try_as_ambig_ct() { Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { - let ConstArg { hir_id, kind: _ } = const_arg; - visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) + let ConstArg { hir_id, kind: _, span } = const_arg; + visitor.visit_infer(*hir_id, *span, InferKind::Const(const_arg)) } } } @@ -1078,10 +1078,10 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { - let ConstArg { hir_id, kind } = const_arg; + let ConstArg { hir_id, kind, span: _ } = const_arg; try_visit!(visitor.visit_id(*hir_id)); match kind { - ConstArgKind::Tup(_, exprs) => { + ConstArgKind::Tup(exprs) => { walk_list!(visitor, visit_const_arg, *exprs); V::Result::output() } @@ -1103,7 +1103,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), - ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important + ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important } } 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 51c664921804..92b77a2042b1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -381,7 +381,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let span = match term { hir::Term::Ty(ty) => ty.span, - hir::Term::Const(ct) => ct.span(), + hir::Term::Const(ct) => ct.span, }; (span, Some(ident.span), assoc_item.as_tag(), assoc_tag) } else { @@ -1466,7 +1466,7 @@ pub fn prohibit_assoc_item_constraint( hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, GenericParamDefKind::Const { .. }, ) => { - suggest_direct_use(&mut err, c.span()); + suggest_direct_use(&mut err, c.span); } (hir::AssocItemConstraintKind::Bound { bounds }, _) => { // Suggest `impl Trait for Foo` when finding diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ad037c195d55..aaa566760013 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2331,7 +2331,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants with lifetimes in their type are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2342,7 +2342,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // variables otherwise we will ICE. if anon_const_type.has_non_region_infer() { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants with inferred types are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2352,7 +2352,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // give the anon const any of the generics from the parent. if anon_const_type.has_non_region_param() { let e = self.dcx().span_err( - const_arg.span(), + const_arg.span, "anonymous constants referencing generics are not yet supported", ); tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); @@ -2364,7 +2364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let hir_id = const_arg.hir_id; match const_arg.kind { - hir::ConstArgKind::Tup(span, exprs) => self.lower_const_arg_tup(exprs, feed, span), + hir::ConstArgKind::Tup(exprs) => self.lower_const_arg_tup(exprs, feed, const_arg.span), hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2378,19 +2378,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_self_ty, segment, hir_id, - const_arg.span(), + const_arg.span, ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } hir::ConstArgKind::Struct(qpath, inits) => { - self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span()) + self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span) } hir::ConstArgKind::TupleCall(qpath, args) => { - self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span()) + self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span) } hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), - hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), - hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), + hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), + hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d360a18676ff..2c160ccef2b6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1141,13 +1141,13 @@ impl<'a> State<'a> { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { - ConstArgKind::Tup(_, exprs) => { + ConstArgKind::Tup(exprs) => { self.popen(); self.commasep_cmnt( Inconsistent, exprs, |s, arg| s.print_const_arg(arg), - |arg| arg.span(), + |arg| arg.span, ); self.pclose(); } @@ -1155,7 +1155,7 @@ impl<'a> State<'a> { ConstArgKind::TupleCall(qpath, args) => self.print_const_ctor(qpath, args), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), - ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), + ConstArgKind::Error(_) => self.word("/*ERROR*/"), ConstArgKind::Infer(..) => self.word("_"), } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index c4fa39c6c2c8..9d7e09b020a7 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1705,7 +1705,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; if let hir::TyKind::Array(_, ct) = ty.peel_refs().kind { - let span = ct.span(); + let span = ct.span; self.dcx().try_steal_modify_and_emit_err( span, StashKey::UnderscoreForArrayLengths, @@ -1746,7 +1746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count_span = count.span(); + let count_span = count.span; let count = self.try_structurally_resolve_const( count_span, self.normalize(count_span, self.lower_const_arg(count, FeedConstTy::No)), diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 29006732aade..f4a506d50a41 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -74,12 +74,9 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { GenericArg::Type(ty) => { cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into()) } - GenericArg::Const(c) => cx - .tcx - .sess - .source_map() - .span_to_snippet(c.span()) - .unwrap_or_else(|_| "_".into()), + GenericArg::Const(c) => { + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into()) + } GenericArg::Infer(_) => String::from("_"), }) .collect::>(); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 8cc66802e435..ca783311586f 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -1003,7 +1003,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, Node::ConstBlock(constant) => self.hir_body(constant.body).value.span, - Node::ConstArg(const_arg) => const_arg.span(), + Node::ConstArg(const_arg) => const_arg.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::ConstArgExprField(field) => field.span, 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 cea69c699628..47810e2578df 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1879,7 +1879,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(length_val) = sz.found.try_to_target_usize(self.tcx) { Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { - span: length_arg.span(), + span: length_arg.span, length: length_val, }) } else { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 620e27fa67c6..261b03abba17 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -126,7 +126,7 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { let ExprKind::Repeat(_, len_ct) = expr.kind else { return false; }; - !expr.span.contains(len_ct.span()) + !expr.span.contains(len_ct.span) } expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr) diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index f515f9987a80..455f76edc904 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -321,6 +321,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index a44cd31dc123..46b87fd5df96 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f1ee534c500d..57c896c97172 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -661,6 +661,10 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { + return false; + } + match (&left.kind, &right.kind) { (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), @@ -679,11 +683,18 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { + args_a + .iter() + .zip(*args_b) + .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) + } // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) + | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Error(..), @@ -1560,6 +1571,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, + ConstArgKind::Tup(args) => { + for arg in *args { + self.hash_const_arg(arg); + } + }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr index 49d3f67003dc..72e0e94ff625 100644 --- a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr +++ b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr @@ -23,7 +23,7 @@ error: struct expression with missing field initialiser for `field` --> $DIR/adt_expr_erroneuous_inits.rs:16:17 | LL | accepts::<{ Foo:: { }}>(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^ error: struct expression with multiple initialisers for `field` --> $DIR/adt_expr_erroneuous_inits.rs:18:49 @@ -35,13 +35,13 @@ error: struct expression with invalid base path --> $DIR/adt_expr_erroneuous_inits.rs:20:17 | LL | accepts::<{ Fooo:: { field: const { 1 } }}>(); - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct expression with invalid base path --> $DIR/adt_expr_erroneuous_inits.rs:23:17 | LL | accepts::<{ NonStruct { }}>(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index b4f03e07b569..bd2162468944 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -2,7 +2,7 @@ error: the constant `Option::::Some(N)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:18:13 | LL | foo::<{ Option::Some:: { 0: N } }>; - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -14,7 +14,7 @@ error: the constant `Option::::Some(::ASSOC)` is not of type `F --> $DIR/printing_valtrees_supports_non_values.rs:23:13 | LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -37,7 +37,7 @@ error: the constant `Option::::Some(_)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:30:12 | LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 @@ -49,7 +49,7 @@ error: the constant `Option::::Some(_)` is not of type `Foo` --> $DIR/printing_valtrees_supports_non_values.rs:36:13 | LL | foo::<{ Option::Some:: { 0: _ } }>(); - | ^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 diff --git a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr index fbcdf35461ec..cc6144b9c88a 100644 --- a/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr +++ b/tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr @@ -13,31 +13,31 @@ error: tuple constructor has 2 arguments but 1 were provided --> $DIR/tuple_ctor_erroneous.rs:23:23 | LL | accepts_point::<{ Point(N) }>(); - | ^^^^^ + | ^^^^^^^^ error: tuple constructor has 2 arguments but 3 were provided --> $DIR/tuple_ctor_erroneous.rs:26:23 | LL | accepts_point::<{ Point(N, N, N) }>(); - | ^^^^^ + | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:29:23 | LL | accepts_point::<{ UnresolvedIdent(N, N) }>(); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:33:23 | LL | accepts_point::<{ non_ctor(N, N) }>(); - | ^^^^^^^^ + | ^^^^^^^^^^^^^^ error: tuple constructor with invalid base path --> $DIR/tuple_ctor_erroneous.rs:36:23 | LL | accepts_point::<{ CONST_ITEM(N, N) }>(); - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: the constant `Point` is not of type `Point` --> $DIR/tuple_ctor_erroneous.rs:39:23 From cb1de296591e7220495c7f37a862678ee55edd71 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 6 Jan 2026 23:07:24 +0800 Subject: [PATCH 193/340] Use parent's identity_args to instantiate the type of const param --- compiler/rustc_hir_analysis/src/collect.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9d4cb6d7684b..bacdf0049806 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1479,24 +1479,27 @@ fn rendered_precise_capturing_args<'tcx>( fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, - def_id: LocalDefId, + local_def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { let hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { default: Some(default_ct), .. }, .. - }) = tcx.hir_node_by_def_id(def_id) + }) = tcx.hir_node_by_def_id(local_def_id) else { span_bug!( - tcx.def_span(def_id), + tcx.def_span(local_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); - let ct = icx.lowerer().lower_const_arg( - default_ct, - FeedConstTy::with_type_of(tcx, def_id.to_def_id(), identity_args), - ); + + let icx = ItemCtxt::new(tcx, local_def_id); + + let def_id = local_def_id.to_def_id(); + let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id)); + + let ct = icx + .lowerer() + .lower_const_arg(default_ct, FeedConstTy::with_type_of(tcx, def_id, identity_args)); ty::EarlyBinder::bind(ct) } From 139d59f7ecbf0146a5c0e475473e71aca47e0b39 Mon Sep 17 00:00:00 2001 From: neo Date: Wed, 7 Jan 2026 09:53:06 +0900 Subject: [PATCH 194/340] Reword the collect() docs to stress that the return type determines the resulting collection --- library/core/src/iter/traits/iterator.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f106900a3983..e418f481ad2a 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1906,9 +1906,12 @@ pub trait Iterator { /// Transforms an iterator into a collection. /// - /// `collect()` can take anything iterable, and turn it into a relevant - /// collection. This is one of the more powerful methods in the standard - /// library, used in a variety of contexts. + /// `collect()` takes ownership of an iterator and produces whichever + /// collection type you request. The iterator itself carries no knowledge of + /// the eventual container; the target collection is chosen entirely by the + /// type you ask `collect()` to return. This makes `collect()` one of the + /// more powerful methods in the standard library, and it shows up in a wide + /// variety of contexts. /// /// The most basic pattern in which `collect()` is used is to turn one /// collection into another. You take a collection, call [`iter`] on it, From 6346d14202ce2c4ac3e92595a6fd1b619803145d Mon Sep 17 00:00:00 2001 From: tison Date: Wed, 7 Jan 2026 09:31:59 +0800 Subject: [PATCH 195/340] Apply suggestion from @tisonkun --- library/alloc/src/task.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 73b732241974..aa1901314e37 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -360,6 +360,7 @@ impl From> for RawWaker { /// waker.wake_by_ref(); // Prints "woken". /// waker.wake(); // Prints "woken". /// ``` +// #[unstable(feature = "local_waker", issue = "118959")] #[unstable(feature = "waker_fn", issue = "149580")] pub fn local_waker_fn(f: F) -> LocalWaker { struct LocalWakeFn { From 6c2dc40666b1564a9621fcccc2f32a70d3e89e38 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Wed, 7 Jan 2026 00:03:32 +0800 Subject: [PATCH 196/340] Bless other tests --- tests/crashes/133965.rs | 9 --- tests/incremental/const-generic-type-cycle.rs | 1 - ...ith-same-name-and-derive-default-133965.rs | 14 ++++ ...same-name-and-derive-default-133965.stderr | 81 +++++++++++++++++++ .../non_scalar_alignment_value.stderr | 8 +- 5 files changed, 99 insertions(+), 14 deletions(-) delete mode 100644 tests/crashes/133965.rs create mode 100644 tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs create mode 100644 tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr diff --git a/tests/crashes/133965.rs b/tests/crashes/133965.rs deleted file mode 100644 index 69f533ccbe98..000000000000 --- a/tests/crashes/133965.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #133965 -//@ needs-rustc-debug-assertions - -struct NonGeneric {} - -#[derive(Default)] -struct NonGeneric<'a, const N: usize> {} - -pub fn main() {} diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs index 40a40ebd13fe..5bcbc1d5dafe 100644 --- a/tests/incremental/const-generic-type-cycle.rs +++ b/tests/incremental/const-generic-type-cycle.rs @@ -14,7 +14,6 @@ trait Bar {} trait Bar {} //[cfail]~^ ERROR cycle detected when computing type of `Bar::N` //[cfail]~| ERROR cycle detected when computing type of `Bar::N` -//[cfail]~| ERROR cycle detected when computing type of `Bar::N` //[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs new file mode 100644 index 000000000000..8e5cd4248f14 --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.rs @@ -0,0 +1,14 @@ +//@ needs-rustc-debug-assertions + +struct NonGeneric {} + +#[derive(Default)] +//~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied +//~^^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied +//~^^^ ERROR struct takes 0 generic arguments but 1 generic argument was supplied +//~^^^^ ERROR struct takes 0 generic arguments but 1 generic argument was supplied +struct NonGeneric<'a, const N: usize> {} +//~^ ERROR lifetime parameter `'a` is never used +//~^^ ERROR the name `NonGeneric` is defined multiple times + +pub fn main() {} diff --git a/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr new file mode 100644 index 000000000000..cf9c0d0ad3be --- /dev/null +++ b/tests/ui/duplicate/multiple-types-with-same-name-and-derive-default-133965.stderr @@ -0,0 +1,81 @@ +error[E0428]: the name `NonGeneric` is defined multiple times + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:10:1 + | +LL | struct NonGeneric {} + | ----------------- previous definition of the type `NonGeneric` here +... +LL | struct NonGeneric<'a, const N: usize> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonGeneric` redefined here + | + = note: `NonGeneric` must be defined only once in the type namespace of this module + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 lifetime arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | -- help: remove the lifetime argument + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 generic arguments + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:10:19 + | +LL | struct NonGeneric<'a, const N: usize> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 lifetime arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | -- help: remove the lifetime argument + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:5:10 + | +LL | #[derive(Default)] + | ^^^^^^^ expected 0 generic arguments +... +LL | struct NonGeneric<'a, const N: usize> {} + | - help: remove the unnecessary generic argument + | +note: struct defined here, with 0 generic parameters + --> $DIR/multiple-types-with-same-name-and-derive-default-133965.rs:3:8 + | +LL | struct NonGeneric {} + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0107, E0392, E0428. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/transmutability/non_scalar_alignment_value.stderr b/tests/ui/transmutability/non_scalar_alignment_value.stderr index 06487dea82e0..d22c6d0b27e8 100644 --- a/tests/ui/transmutability/non_scalar_alignment_value.stderr +++ b/tests/ui/transmutability/non_scalar_alignment_value.stderr @@ -11,25 +11,25 @@ error: struct expression with missing field initialiser for `alignment` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `lifetimes` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `safety` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: struct expression with missing field initialiser for `validity` --> $DIR/non_scalar_alignment_value.rs:15:32 | LL | alignment: Assume {}, - | ^^^^^^ + | ^^^^^^^^^ error: aborting due to 4 previous errors; 1 warning emitted From d848437814ac8796a540b762dcb446f20384969e Mon Sep 17 00:00:00 2001 From: andjsrk Date: Wed, 7 Jan 2026 12:09:07 +0900 Subject: [PATCH 197/340] add more information in comment --- .../ui/repeat-expr/can-have-side-effects-consider-element.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs index d0b5d12455dc..274942f9379f 100644 --- a/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs +++ b/tests/ui/repeat-expr/can-have-side-effects-consider-element.rs @@ -5,8 +5,8 @@ // Test if `Expr::can_have_side_effects` considers element of repeat expressions. fn drop_repeat_in_arm_body() { - // Built-in lint `dropping_copy_types` relies on - // `Expr::can_have_side_effects` (See rust-clippy#9482) + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` + // (See rust-clippy#9482 and rust#113231) match () { () => drop([0; 1]), // No side effects From 11324546168855ddb221b019e0fa004e9de78881 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 7 Jan 2026 06:03:51 +0100 Subject: [PATCH 198/340] tests/ui/runtime/on-broken-pipe/with-rustc_main.rs: Not needed so remove It was added in ddee45e1d7fd when SIGPIPE was controlled with an attribute on `fn main()` which meant it could also be combined with `#[rustc_main]`: #[unix_sigpipe = "sig_dfl"] #[rustc_main] fn rustc_main() { It stopped being needed cde0cde151f3 when `#[unix_sigpipe = "..."]` was replaced by `-Zon-broken-pipe=...`. And it will not be needed when `-Zon-broken-pipe=...` is replaced by an Externally Implementable Item. Let's remove this test. --- .../ui/runtime/on-broken-pipe/with-rustc_main.rs | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 tests/ui/runtime/on-broken-pipe/with-rustc_main.rs diff --git a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs deleted file mode 100644 index c40590ad87f4..000000000000 --- a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -//@ aux-build:sigpipe-utils.rs -//@ compile-flags: -Zon-broken-pipe=kill -//@ only-unix because SIGPIPE is a unix thing - -#![feature(rustc_attrs)] - -#[rustc_main] -fn rustc_main() { - extern crate sigpipe_utils; - - // `-Zon-broken-pipe=kill` is active, so SIGPIPE handler shall be - // SIG_DFL. Note that we have a #[rustc_main], but it should still work. - sigpipe_utils::assert_sigpipe_handler(sigpipe_utils::SignalHandler::Default); -} From f02ed7b565e6d9ba3b7b13abe86ea3a2dec3bf3c Mon Sep 17 00:00:00 2001 From: Spxg Date: Wed, 7 Jan 2026 17:10:56 +0800 Subject: [PATCH 199/340] Fix `alloc_error_handler` signature mismatch --- compiler/rustc_codegen_ssa/src/base.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8ab0b367f08a..c8aa7c04585c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,7 +6,8 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast::expand::allocator::{ - ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorTy, + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorMethodInput, + AllocatorTy, }; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; @@ -671,7 +672,7 @@ pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec Date: Wed, 7 Jan 2026 10:03:04 +0100 Subject: [PATCH 200/340] Do not warn about large stack arrays without having a valid span The libtest harness generates an array with all the tests on the stack. However, it is generated with no location information, so we cannot tell the user anything useful. This commit is not accompanied by a test, as it would require running Clippy on the result of libtest harness with a lot of tests, which would take a very long time. A note has been added to the source to indicate not to remove the check. --- clippy_lints/src/large_stack_arrays.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 620e27fa67c6..7bb7bc91f0c9 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -94,6 +94,15 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { }) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) { + // libtest might generate a large array containing the test cases, and no span will be associated + // to it. In this case it is better not to complain. + // + // Note that this condition is not checked explicitly by a unit test. Do not remove it without + // ensuring that stays fixed. + if expr.span.is_dummy() { + return; + } + span_lint_and_then( cx, LARGE_STACK_ARRAYS, From 6f7313e8adaec57196cec3d368cac8dd5fbf3d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 12:55:38 +0100 Subject: [PATCH 201/340] Make verify-channel.sh script compatible with new bors --- src/ci/scripts/verify-channel.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/verify-channel.sh b/src/ci/scripts/verify-channel.sh index 9a9e713243d7..cac8ba332ed1 100755 --- a/src/ci/scripts/verify-channel.sh +++ b/src/ci/scripts/verify-channel.sh @@ -8,7 +8,8 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isCiBranch auto || isCiBranch try || isCiBranch try-perf || isCiBranch automation/bors/try; then +if isCiBranch auto || isCiBranch try || isCiBranch try-perf || \ + isCiBranch automation/bors/try || isCiBranch automation/bors/auto; then echo "channel verification is only executed on PR builds" exit fi From 43e1604defa289b21cacf5f8e3c7d1ae741ecdca Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 7 Jan 2026 14:51:18 +0200 Subject: [PATCH 202/340] rustc book: fix grammar --- src/doc/rustc/src/remap-source-paths.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md index ebe92d71158a..a499f9d3c77e 100644 --- a/src/doc/rustc/src/remap-source-paths.md +++ b/src/doc/rustc/src/remap-source-paths.md @@ -41,7 +41,7 @@ This example replaces all occurrences of `/home/user/project` in emitted paths w ## Caveats and Limitations -### Linkers generated paths +### Paths generated by linkers On some platforms like `x86_64-pc-windows-msvc`, the linker may embed absolute host paths and compiler arguments into debug info files (like `.pdb`) independently of `rustc`. From 5b4dbe02131e184a21cffea58f4550b1787edf9b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 7 Jan 2026 14:53:21 +0200 Subject: [PATCH 203/340] add missing commas --- src/doc/rustc/src/remap-source-paths.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md index a499f9d3c77e..dc00278fac67 100644 --- a/src/doc/rustc/src/remap-source-paths.md +++ b/src/doc/rustc/src/remap-source-paths.md @@ -3,7 +3,7 @@ `rustc` supports remapping source paths prefixes **as a best effort** in all compiler generated output, including compiler diagnostics, debugging information, macro expansions, etc. -This is useful for normalizing build products, for example by removing the current directory +This is useful for normalizing build products, for example, by removing the current directory out of the paths emitted into object files. The remapping is done via the `--remap-path-prefix` option. @@ -54,7 +54,7 @@ The `--remap-path-prefix` option does not affect these linker-generated paths. ### Textual replacement only The remapping is strictly textual and does not account for different path separator conventions across -platforms. Care must be taken when specifying prefixes, especially on Windows where both `/` and `\` may +platforms. Care must be taken when specifying prefixes, especially on Windows, where both `/` and `\` may appear in paths. ### External tools From ea7ada90c61c4edc748c7a1a3c89c77ec5648b99 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jan 2026 13:55:53 +0100 Subject: [PATCH 204/340] Update browser-ui-test version to `0.23.1` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef74853b77a5..0cba589d23f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.23.0", + "browser-ui-test": "^0.23.1", "es-check": "^9.4.4", "eslint": "^8.57.1", "typescript": "^5.8.3" From a928f3352d43ce4034e664aa310982657dc55c26 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Jan 2026 13:06:54 +0100 Subject: [PATCH 205/340] Rename `tests/rustdoc` into `tests/rustdoc-html` --- rustfmt.toml | 2 +- src/bootstrap/src/core/build_steps/test.rs | 14 +++++++------- .../src/core/build_steps/test/compiletest.rs | 4 ++-- src/bootstrap/src/core/builder/cli_paths.rs | 2 +- .../builder/cli_paths/snapshots/x_test.snap | 5 ++--- .../snapshots/x_test_librustdoc_rustdoc.snap | 3 --- .../x_test_librustdoc_rustdoc_html.snap | 10 ++++++++++ .../cli_paths/snapshots/x_test_rustdoc.snap | 3 --- .../snapshots/x_test_rustdoc_html.snap | 7 +++++++ .../snapshots/x_test_skip_coverage.snap | 5 ++--- .../cli_paths/snapshots/x_test_tests.snap | 6 +++--- .../snapshots/x_test_tests_skip_coverage.snap | 6 +++--- .../src/core/builder/cli_paths/tests.rs | 2 ++ src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 19 ++++++++----------- src/ci/citool/tests/test-jobs.yml | 2 +- .../host-x86_64/x86_64-gnu-gcc/Dockerfile | 2 +- src/librustdoc/html/render/write_shared.rs | 3 ++- src/tools/compiletest/src/common.rs | 4 ++-- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/directives/tests.rs | 2 +- src/tools/compiletest/src/lib.rs | 6 +++--- src/tools/compiletest/src/runtest.rs | 4 ++-- src/tools/compiletest/src/runtest/rustdoc.rs | 2 +- src/tools/compiletest/src/rustdoc_gui_test.rs | 2 +- src/tools/opt-dist/src/tests.rs | 2 +- src/tools/tidy/src/features.rs | 2 +- tests/{rustdoc => rustdoc-html}/all.rs | 0 .../anchor-id-duplicate-method-name-25001.rs | 0 .../anchors/anchor-id-trait-method-15169.rs | 0 .../anchors/anchor-id-trait-tymethod-28478.rs | 0 .../anchors/anchors.no_const_anchor.html | 0 .../anchors/anchors.no_const_anchor2.html | 0 .../anchors/anchors.no_method_anchor.html | 0 .../anchors.no_trait_method_anchor.html | 0 .../anchors/anchors.no_tymethod_anchor.html | 0 .../anchors/anchors.no_type_anchor.html | 0 .../anchors/anchors.no_type_anchor2.html | 0 .../anchors/anchors.rs | 0 .../anchors/auxiliary/issue-86620-1.rs | 0 .../anchors/disambiguate-anchors-32890.rs | 0 .../disambiguate-anchors-header-29449.rs | 0 .../method-anchor-in-blanket-impl-86620.rs | 0 .../trait-impl-items-links-and-anchors.rs | 0 .../anon-fn-params.rs | 0 .../anonymous-lifetime.rs | 0 .../array-links.link_box_generic.html | 0 .../array-links.link_box_u32.html | 0 .../array-links.link_slice_generic.html | 0 .../array-links.link_slice_u32.html | 0 .../{rustdoc => rustdoc-html}/array-links.rs | 0 .../{rustdoc => rustdoc-html}/asm-foreign.rs | 0 .../{rustdoc => rustdoc-html}/asm-foreign2.rs | 0 .../asref-for-and-of-local-82465.rs | 0 .../assoc/assoc-fns.rs | 0 .../assoc/assoc-item-cast.rs | 0 .../assoc/assoc-type-bindings-20646.rs | 0 .../assoc/assoc-types.rs | 0 .../cross-crate-hidden-assoc-trait-items.rs | 0 .../assoc/auxiliary/issue-20646.rs | 0 .../assoc/auxiliary/issue-20727.rs | 0 .../assoc/auxiliary/normalize-assoc-item.rs | 0 .../cross-crate-hidden-assoc-trait-items.rs | 0 .../assoc/doc-assoc-item.rs | 0 .../assoc/inline-assoc-type-20727-bindings.rs | 0 .../inline-assoc-type-20727-bounds-deref.rs | 0 .../inline-assoc-type-20727-bounds-index.rs | 0 .../assoc/inline-assoc-type-20727-bounds.rs | 0 .../assoc/normalize-assoc-item.rs | 0 .../async/async-fn-opaque-item.rs | 0 .../async/async-fn.rs | 0 .../async/async-move-doctest.rs | 0 .../async/async-trait-sig.rs | 0 .../async/async-trait.rs | 0 .../async/auxiliary/async-trait-dep.rs | 0 .../attributes-2021-edition.rs | 0 .../attributes-inlining-108281.rs | 0 .../attributes-re-export-2021-edition.rs | 0 .../attributes-re-export.rs | 0 tests/{rustdoc => rustdoc-html}/attributes.rs | 0 .../auto/auto-impl-for-trait.rs | 0 .../auto/auto-impl-primitive.rs | 0 ...o-trait-bounds-by-associated-type-50159.rs | 0 ...-trait-bounds-inference-variables-54705.rs | 0 .../auto/auto-trait-bounds-where-51236.rs | 0 .../auto/auto-trait-negative-impl-55321.rs | 0 .../auto/auto-trait-not-send.rs | 0 .../auto/auto-traits.rs | 0 .../auto/auto_aliases.rs | 0 .../auto/auxiliary/auto-traits.rs | 0 .../auxiliary/all-item-types.rs | 0 .../auxiliary/cross_crate_generic_typedef.rs | 0 .../auxiliary/elided-lifetime.rs | 0 .../auxiliary/empty.rs | 0 .../auxiliary/enum-primitive.rs | 0 .../auxiliary/ext-anon-fn-params.rs | 0 .../auxiliary/ext-repr.rs | 0 .../auxiliary/ext-trait-aliases.rs | 0 .../auxiliary/inline-default-methods.rs | 0 .../auxiliary/issue-106421-force-unstable.rs | 0 .../auxiliary/issue-13698.rs | 0 .../auxiliary/issue-19190-3.rs | 0 .../auxiliary/issue-61592.rs | 0 .../auxiliary/issue-99221-aux.rs | 0 .../auxiliary/issue-99734-aux.rs | 0 .../jump-to-def-res-err-handling-aux.rs | 0 .../auxiliary/masked.rs | 0 .../auxiliary/mod-stackoverflow.rs | 0 .../auxiliary/reexp-stripped.rs | 0 .../auxiliary/remapped-paths.rs | 0 .../auxiliary/rustdoc-ffi.rs | 0 .../auxiliary/trait-visibility.rs | 0 .../auxiliary/unit-return.rs | 0 .../auxiliary/unsafe-binder-dep.rs | 0 .../auxiliary/unstable-trait.rs | 0 .../bad-codeblock-syntax.rs | 0 .../blank-line-in-doc-block-47197.rs | 0 .../bold-tag-101743.rs | 0 tests/{rustdoc => rustdoc-html}/bounds.rs | 0 tests/{rustdoc => rustdoc-html}/cap-lints.rs | 0 tests/{rustdoc => rustdoc-html}/cfg-bool.rs | 0 .../{rustdoc => rustdoc-html}/cfg-doctest.rs | 0 .../check-styled-link.rs | 0 tests/{rustdoc => rustdoc-html}/check.rs | 0 .../codeblock-title.rs | 0 .../comment-in-doctest.rs | 0 .../const-fn-76501.rs | 0 .../const-fn-effects.rs | 0 tests/{rustdoc => rustdoc-html}/const-fn.rs | 0 .../const-generics/add-impl.rs | 0 .../const-generics/auxiliary/extern_crate.rs | 0 .../const-generics/const-generic-defaults.rs | 0 .../const-generics/const-generic-slice.rs | 0 .../const-generics/const-generics-docs.rs | 0 .../const-generics/const-impl.rs | 0 .../const-param-type-references-generics.rs | 0 .../const-generics/generic_const_exprs.rs | 0 .../const-equate-pred.rs | 0 .../const-generics/type-alias.rs | 0 .../const-intrinsic.rs | 0 .../constant/assoc-consts-underscore.rs | 0 .../constant/assoc-consts-version.rs | 0 .../constant/assoc-consts.rs | 0 .../constant/associated-consts.rs | 0 .../constant/const-display.rs | 0 .../constant/const-doc.rs | 0 .../constant/const-effect-param.rs | 0 .../constant/const-trait-and-impl-methods.rs | 0 .../constant/const-underscore.rs | 0 .../constant/const-value-display.rs | 0 .../constant/const.rs | 0 ...m-with-associated-const-in-where-clause.rs | 0 .../constant/generic-const-items.rs | 0 .../constant/generic_const_exprs.rs | 0 .../constant/glob-shadowing-const.rs | 0 ...ide-complex-unevaluated-const-arguments.rs | 0 .../hide-complex-unevaluated-consts.rs | 0 .../ice-associated-const-equality-105952.rs | 0 .../constant/legacy-const-generic.rs | 0 .../constant/link-assoc-const.rs | 0 .../constant/redirect-const.rs | 0 .../constant/rfc-2632-const-trait-impl.rs | 0 .../constant/show-const-contents.rs | 0 .../constructor-imports.rs | 0 .../crate-doc-hidden-109695.rs | 0 .../crate-version-escape.rs | 0 .../crate-version-extra.rs | 0 .../crate-version.rs | 0 .../cargo-transitive-no-index/auxiliary/q.rs | 0 .../cargo-transitive-no-index/auxiliary/t.rs | 0 .../cargo-transitive-no-index/s.rs | 0 .../cargo-transitive/auxiliary/q.rs | 0 .../cargo-transitive/auxiliary/t.rs | 0 .../cross-crate-info/cargo-transitive/s.rs | 0 .../cargo-two-no-index/auxiliary/f.rs | 0 .../cross-crate-info/cargo-two-no-index/e.rs | 0 .../cross-crate-info/cargo-two/auxiliary/f.rs | 0 .../cross-crate-info/cargo-two/e.rs | 0 .../index-on-last/auxiliary/f.rs | 0 .../cross-crate-info/index-on-last/e.rs | 0 .../kitchen-sink/auxiliary/q.rs | 0 .../kitchen-sink/auxiliary/r.rs | 0 .../kitchen-sink/auxiliary/s.rs | 0 .../kitchen-sink/auxiliary/t.rs | 0 .../cross-crate-info/kitchen-sink/i.rs | 0 .../single-crate-baseline/q.rs | 0 .../single-crate-no-index/q.rs | 0 .../transitive/auxiliary/q.rs | 0 .../transitive/auxiliary/t.rs | 0 .../cross-crate-info/transitive/s.rs | 0 .../cross-crate-info/two/auxiliary/f.rs | 0 .../cross-crate-info/two/e.rs | 0 .../working-dir-examples/q.rs | 0 .../write-docs-somewhere-else/auxiliary/f.rs | 0 .../write-docs-somewhere-else/e.rs | 0 .../cross-crate-links.rs | 0 .../custom_code_classes.rs | 0 ...ecl-line-wrapping-empty-arg-list.decl.html | 0 .../decl-line-wrapping-empty-arg-list.rs | 0 .../decl-trailing-whitespace.declaration.html | 0 .../decl-trailing-whitespace.rs | 0 .../deep-structures.rs | 0 .../default-theme.rs | 0 .../default-trait-method-link.rs | 0 .../default-trait-method.rs | 0 .../demo-allocator-54478.rs | 0 .../deprecated-future-staged-api.rs | 0 .../deprecated-future.rs | 0 tests/{rustdoc => rustdoc-html}/deprecated.rs | 0 .../deref-methods-19190-foreign-type.rs | 0 .../deref-methods-19190-inline.rs | 0 .../deref-methods-19190.rs | 0 .../deref-mut-35169-2.rs | 0 .../deref-mut-35169.rs | 0 .../deref/deref-const-fn.rs | 0 .../deref/deref-methods-24686-target.rs | 0 .../deref/deref-multiple-impl-blocks.rs | 0 .../deref/deref-mut-methods.rs | 0 .../deref/deref-recursive-pathbuf.rs | 0 .../deref/deref-recursive.rs | 0 .../deref/deref-slice-core.rs | 0 .../deref/deref-to-primitive.rs | 0 .../deref/deref-typedef.rs | 0 .../deref/escape-deref-methods.rs | 0 .../deref/recursive-deref-sidebar.rs | 0 .../deref/recursive-deref.rs | 0 .../deref/sidebar-links-deref-100679.rs | 0 .../{rustdoc => rustdoc-html}/description.rs | 0 .../description_default.rs | 0 .../display-hidden-items.rs | 0 .../doc-attr-comment-mix-42760.rs | 0 .../doc-attribute.rs | 0 .../doc-auto-cfg-public-in-private.rs | 0 .../{rustdoc => rustdoc-html}/doc-auto-cfg.rs | 0 .../doc-cfg/doc-cfg-hide.rs | 0 .../doc-cfg/doc-cfg-implicit-gate.rs | 0 .../doc-cfg/doc-cfg-implicit.rs | 0 .../doc-cfg-inherit-from-module-79201.rs | 0 .../doc-cfg/doc-cfg-simplification.rs | 0 .../doc-cfg/doc-cfg-target-feature.rs | 0 .../doc-cfg/doc-cfg-traits.rs | 0 .../doc-cfg/doc-cfg.rs | 0 .../doc-cfg/duplicate-cfg.rs | 0 .../doc-hidden-crate.rs | 0 .../doc-hidden-method-13698.rs | 0 .../doc-on-keyword.rs | 0 .../doc-test-attr-18199.rs | 0 .../{rustdoc => rustdoc-html}/doc_auto_cfg.rs | 0 .../doc_auto_cfg_reexports.rs | 0 .../doctest/auxiliary/doctest-runtool.rs | 0 .../doctest/auxiliary/empty.rs | 0 .../doctest/doctest-cfg-feature-30252.rs | 0 .../doctest/doctest-crate-attributes-38129.rs | 0 ...doctest-escape-boring-41783.codeblock.html | 0 .../doctest/doctest-escape-boring-41783.rs | 0 .../doctest/doctest-hide-empty-line-23106.rs | 0 .../doctest/doctest-ignore-32556.rs | 0 .../doctest/doctest-include-43153.rs | 0 .../doctest/doctest-macro-38219.rs | 0 .../doctest/doctest-manual-crate-name.rs | 0 .../doctest-markdown-inline-parse-23744.rs | 0 ...octest-markdown-trailing-docblock-48377.rs | 0 ...doctest-multi-line-string-literal-25944.rs | 0 .../doctest/doctest-runtool.rs | 0 .../doctest/ignore-sometimes.rs | 0 .../document-hidden-items-15347.rs | 0 .../double-hyphen-to-dash.rs | 0 .../double-quote-escape.rs | 0 .../duplicate-flags.rs | 0 .../duplicate_impls/impls.rs | 0 .../sidebar-links-duplicate-impls-33054.rs | 0 .../dyn-compatibility.rs | 0 .../early-unindent.rs | 0 .../edition-doctest.rs | 0 .../{rustdoc => rustdoc-html}/edition-flag.rs | 0 .../elided-lifetime.rs | 0 .../empty-doc-comment.rs | 0 .../empty-mod-public.rs | 0 .../empty-section.rs | 0 .../empty-tuple-struct-118180.rs | 0 .../ensure-src-link.rs | 0 .../enum/auxiliary/enum-variant.rs | 0 .../enum/auxiliary/variant-struct.rs | 0 .../enum/enum-headings.rs | 0 .../enum/enum-non-exhaustive-108925.rs | 0 .../enum-variant-doc-hidden-field-88600.rs | 0 .../enum/enum-variant-fields-heading.rs | 0 .../enum-variant-fields-heading.variants.html | 0 .../enum/enum-variant-non_exhaustive.rs | 0 ...ariant-non_exhaustive.type-alias-code.html | 0 ...enum-variant-non_exhaustive.type-code.html | 0 .../enum/enum-variant-value.rs | 0 .../render-enum-variant-structlike-32395.rs | 0 .../enum/strip-enum-variant.no-not-shown.html | 0 .../enum/strip-enum-variant.rs | 0 .../extern/auxiliary/empty.rs | 0 .../extern/auxiliary/extern-links.rs | 0 .../extern/auxiliary/external-cross-doc.md | 0 .../extern/auxiliary/external-cross.rs | 0 .../extern/auxiliary/external-doc.md | 0 .../extern/auxiliary/html_root.rs | 0 .../extern/auxiliary/issue-30109-1.rs | 0 .../extern/auxiliary/no_html_root.rs | 0 .../extern/auxiliary/panic-item.rs | 0 .../extern/auxiliary/pub-extern-crate.rs | 0 .../rustdoc-extern-default-method.rs | 0 .../extern/auxiliary/rustdoc-extern-method.rs | 0 .../extern/auxiliary/variant-struct.rs | 0 .../duplicate-reexports-section-150211.rs | 0 ...tern-default-method.no_href_on_anchor.html | 0 .../extern/extern-default-method.rs | 0 .../extern/extern-fn-22038.rs | 0 .../extern/extern-html-alias.rs | 0 .../extern/extern-html-fallback.rs | 0 .../extern/extern-html-root-url-precedence.rs | 0 .../extern/extern-html-root-url.rs | 0 .../extern/extern-links.rs | 0 .../extern/extern-method.rs | 0 .../extern/external-cross.rs | 0 .../extern/external-doc.rs | 0 .../extern/hidden-extern-34025.rs | 0 .../extern/link-extern-crate-33178.rs | 0 .../extern/link-extern-crate-item-30109.rs | 0 .../extern/link-extern-crate-title-33178.rs | 0 .../extern/pub-extern-crate-150176.rs | 0 .../extern/pub-extern-crate.rs | 0 .../extern/unsafe-extern-blocks.rs | 0 .../extern/unused-extern-crate.rs | 0 ...long_typename.extremely_long_typename.html | 0 .../extremely_long_typename.rs | 0 .../feature-gate-doc_auto_cfg.rs | 0 tests/{rustdoc => rustdoc-html}/ffi.rs | 0 .../file-creation-111249.rs | 0 .../files-creation-hidden.rs | 0 tests/{rustdoc => rustdoc-html}/fn-bound.rs | 0 .../fn-pointer-arg-name.rs | 0 tests/{rustdoc => rustdoc-html}/fn-sidebar.rs | 0 tests/{rustdoc => rustdoc-html}/fn-type.rs | 0 ...te-definition-without-blank-line-100638.rs | 0 .../{rustdoc => rustdoc-html}/footnote-ids.rs | 0 .../footnote-in-summary.rs | 0 .../footnote-reference-ids.rs | 0 .../footnote-reference-in-footnote-def.rs | 0 .../force-target-feature.rs | 0 ...nstable-if-unmarked-106421-not-internal.rs | 0 .../force-unstable-if-unmarked-106421.rs | 0 .../{rustdoc => rustdoc-html}/foreigntype.rs | 0 .../gat-elided-lifetime-94683.rs | 0 .../gat-linkification-109488.rs | 0 .../generic-associated-types/gats.rs | 0 .../glob-shadowing.rs | 0 .../heading-levels-89309.rs | 0 .../heterogeneous-concat.rs | 0 .../{rustdoc => rustdoc-html}/hidden-line.rs | 0 .../hidden-methods.rs | 0 ...rait-methods-with-document-hidden-items.rs | 0 .../hidden-trait-methods.rs | 0 .../hide-unstable-trait.rs | 0 .../higher-ranked-trait-bounds.rs | 0 .../highlight-invalid-rust-12834.rs | 0 .../ice-type-error-19181.rs | 0 .../cross-crate-hidden-impl-parameter.rs | 0 .../impl/auxiliary/extern-impl-trait.rs | 0 .../impl/auxiliary/incoherent-impl-types.rs | 0 .../impl/auxiliary/issue-100204-aux.rs | 0 .../impl/auxiliary/issue-17476.rs | 0 .../impl/auxiliary/issue-21092.rs | 0 .../impl/auxiliary/issue-22025.rs | 0 .../impl/auxiliary/issue-53689.rs | 0 .../impl/auxiliary/precise-capturing.rs | 0 .../impl/auxiliary/real_gimli.rs | 0 .../impl/auxiliary/realcore.rs | 0 .../impl/auxiliary/rustdoc-default-impl.rs | 0 .../rustdoc-impl-parts-crosscrate.rs | 0 .../impl/blanket-impl-29503.rs | 0 .../impl/blanket-impl-78673.rs | 0 .../impl/cross-crate-hidden-impl-parameter.rs | 0 .../deduplicate-glob-import-impl-21474.rs | 0 .../impl/deduplicate-trait-impl-22025.rs | 0 .../impl/default-impl.rs | 0 .../impl/deprecated-impls.rs | 0 .../doc-hidden-trait-implementors-33069.rs | 0 .../impl/doc_auto_cfg_nested_impl.rs | 0 .../impl/duplicated_impl.rs | 0 .../impl/empty-impl-block.rs | 0 .../impl/empty-impls.rs | 0 .../impl/extern-impl-trait.rs | 0 .../impl/extern-impl.rs | 0 .../impl/foreign-implementors-js-43701.rs | 0 .../impl/generic-impl.rs | 0 .../impl/hidden-implementors-90781.rs | 0 .../impl/hidden-impls.rs | 0 .../impl/hidden-trait-struct-impls.rs | 0 ...e-mut-methods-if-no-derefmut-impl-74083.rs | 0 .../impl/impl-alias-substituted.rs | 0 .../impl/impl-assoc-type-21092.rs | 0 .../impl/impl-associated-items-order.rs | 0 .../impl/impl-associated-items-sidebar.rs | 0 .../impl/impl-blanket-53689.rs | 0 .../impl/impl-box.rs | 0 .../impl/impl-disambiguation.rs | 0 .../impl/impl-everywhere.rs | 0 .../impl/impl-in-const-block.rs | 0 .../impl/impl-on-ty-alias-issue-119015.rs | 0 .../impl/impl-parts-crosscrate.rs | 0 .../impl/impl-parts.rs | 0 .../impl/impl-ref-20175.rs | 0 .../impl/impl-trait-43869.rs | 0 .../impl/impl-trait-alias.rs | 0 .../impl/impl-trait-precise-capturing.rs | 0 .../impl/impl-type-parameter-33592.rs | 0 .../impl/implementor-stable-version.rs | 0 .../impl/implementors-unstable-75588.rs | 0 .../inline-impl-through-glob-import-100204.rs | 0 .../impl/manual_impl.rs | 0 .../method-link-foreign-trait-impl-17476.rs | 0 .../impl/module-impls.rs | 0 .../impl/must_implement_one_of.rs | 0 .../impl/negative-impl-no-items.rs | 0 .../impl/negative-impl-sidebar.rs | 0 .../impl/negative-impl.rs | 0 .../impl/return-impl-trait.rs | 0 .../impl/rustc-incoherent-impls.rs | 0 .../impl/same-crate-hidden-impl-parameter.rs | 0 .../sidebar-trait-impl-disambiguate-78701.rs | 0 .../impl/struct-implementations-title.rs | 0 .../impl/trait-impl.rs | 0 ...it-implementations-duplicate-self-45584.rs | 0 .../underscore-type-in-trait-impl-96381.rs | 0 .../impl/universal-impl-trait.rs | 0 .../unneeded-trait-implementations-title.rs | 0 .../import-remapped-paths.rs | 0 .../impossible-default.rs | 0 .../include_str_cut.rs | 0 tests/{rustdoc => rustdoc-html}/index-page.rs | 0 .../infinite-redirection-16265-1.rs | 0 .../infinite-redirection-16265-2.rs | 0 .../infinite-redirection.rs | 0 .../inherent-projections.rs | 0 .../inline-default-methods.rs | 0 .../inline-rename-34473.rs | 0 .../inline_cross/add-docs.rs | 0 .../inline_cross/assoc-const-equality.rs | 0 .../inline_cross/assoc-items.rs | 0 .../assoc_item_trait_bounds.out0.html | 0 .../assoc_item_trait_bounds.out2.html | 0 .../assoc_item_trait_bounds.out9.html | 0 .../inline_cross/assoc_item_trait_bounds.rs | 0 .../inline_cross/async-fn.rs | 0 .../inline_cross/attributes.rs | 0 .../inline_cross/auxiliary/add-docs.rs | 0 .../auxiliary/assoc-const-equality.rs | 0 .../inline_cross/auxiliary/assoc-items.rs | 0 .../auxiliary/assoc_item_trait_bounds.rs | 0 .../inline_cross/auxiliary/async-fn.rs | 0 .../inline_cross/auxiliary/attributes.rs | 0 .../auxiliary/const-effect-param.rs | 0 .../inline_cross/auxiliary/cross-glob.rs | 0 .../auxiliary/default-generic-args.rs | 0 .../auxiliary/default-trait-method.rs | 0 .../inline_cross/auxiliary/doc-auto-cfg.rs | 0 .../inline_cross/auxiliary/dyn_trait.rs | 0 .../early-late-bound-lifetime-params.rs | 0 .../inline_cross/auxiliary/fn-ptr-ty.rs | 0 .../auxiliary/generic-const-items.rs | 0 .../auxiliary/impl-inline-without-trait.rs | 0 .../inline_cross/auxiliary/impl-sized.rs | 0 .../inline_cross/auxiliary/impl_trait_aux.rs | 0 .../auxiliary/implementors_inline.rs | 0 .../inline_cross/auxiliary/issue-21801.rs | 0 .../inline_cross/auxiliary/issue-23207-1.rs | 0 .../inline_cross/auxiliary/issue-23207-2.rs | 0 .../inline_cross/auxiliary/issue-24183.rs | 0 .../inline_cross/auxiliary/issue-27362-aux.rs | 0 .../inline_cross/auxiliary/issue-29584.rs | 0 .../inline_cross/auxiliary/issue-33113.rs | 0 .../inline_cross/auxiliary/issue-46727.rs | 0 .../inline_cross/auxiliary/issue-57180.rs | 0 .../inline_cross/auxiliary/issue-76736-1.rs | 0 .../inline_cross/auxiliary/issue-76736-2.rs | 0 .../inline_cross/auxiliary/issue-85454.rs | 0 .../inline_cross/auxiliary/macro-vis.rs | 0 .../inline_cross/auxiliary/macros.rs | 0 .../auxiliary/non_lifetime_binders.rs | 0 .../inline_cross/auxiliary/proc_macro.rs | 0 .../reexport-with-anonymous-lifetime-98697.rs | 0 .../auxiliary/renamed-via-module.rs | 0 .../auxiliary/ret-pos-impl-trait-in-trait.rs | 0 .../auxiliary/rustdoc-hidden-sig.rs | 0 .../inline_cross/auxiliary/rustdoc-hidden.rs | 0 .../auxiliary/rustdoc-nonreachable-impls.rs | 0 .../auxiliary/rustdoc-trait-object-impl.rs | 0 .../inline_cross/auxiliary/trait-vis.rs | 0 .../inline_cross/auxiliary/use_crate.rs | 0 .../inline_cross/auxiliary/use_crate_2.rs | 0 .../inline_cross/const-effect-param.rs | 0 .../inline_cross/const-eval-46727.rs | 0 .../inline_cross/const-fn-27362.rs | 0 .../inline_cross/cross-glob.rs | 0 .../deduplicate-inlined-items-23207.rs | 0 .../inline_cross/default-generic-args.rs | 0 .../inline_cross/default-trait-method.rs | 0 .../inline_cross/doc-auto-cfg.rs | 0 .../doc-hidden-broken-link-28480.rs | 0 .../doc-hidden-extern-trait-impl-29584.rs | 0 .../doc-reachability-impl-31948-1.rs | 0 .../doc-reachability-impl-31948-2.rs | 0 .../doc-reachability-impl-31948.rs | 0 .../inline_cross/dyn_trait.rs | 0 .../early-late-bound-lifetime-params.rs | 0 .../inline_cross/fn-ptr-ty.rs | 0 .../inline_cross/generic-const-items.rs | 0 .../inline_cross/hidden-use.rs | 0 .../inline_cross/ice-import-crate-57180.rs | 0 .../inline_cross/impl-dyn-trait-32881.rs | 0 .../inline_cross/impl-inline-without-trait.rs | 0 .../inline_cross/impl-ref-33113.rs | 0 .../inline_cross/impl-sized.rs | 0 .../inline_cross/impl_trait.rs | 0 .../inline_cross/implementors-js.rs | 0 .../inline_cross/inline_hidden.rs | 0 .../inline_cross/macro-vis.rs | 0 .../inline_cross/macros.rs | 0 .../inline_cross/non_lifetime_binders.rs | 0 .../inline_cross/proc_macro.rs | 0 .../inline_cross/qpath-self-85454.rs | 0 .../reexport-with-anonymous-lifetime-98697.rs | 0 .../inline_cross/renamed-via-module.rs | 0 .../ret-pos-impl-trait-in-trait.rs | 0 .../inline_cross/rustc-private-76736-1.rs | 0 .../inline_cross/rustc-private-76736-2.rs | 0 .../inline_cross/rustc-private-76736-3.rs | 0 .../inline_cross/rustc-private-76736-4.rs | 0 ...unds-24183.method_no_where_self_sized.html | 0 .../inline_cross/self-sized-bounds-24183.rs | 0 .../inline_cross/sugar-closure-crate-21801.rs | 0 .../inline_cross/trait-vis.rs | 0 .../inline_cross/use_crate.rs | 0 .../blanket-impl-reexported-trait-94183.rs | 0 .../inline_local/doc-no-inline-32343.rs | 0 .../enum-variant-reexport-46766.rs | 0 .../fully-stable-path-is-better.rs | 0 .../glob-extern-document-private-items.rs | 0 .../inline_local/glob-extern.rs | 0 .../glob-private-document-private-items.rs | 0 .../inline_local/glob-private.rs | 0 .../inline_local/hidden-use.rs | 0 .../inline_local/macro_by_example.rs | 0 .../inline_local/parent-path-is-better.rs | 0 .../inline_local/please_inline.rs | 0 .../private-reexport-in-public-api-81141-2.rs | 0 .../private-reexport-in-public-api-81141.rs | 0 ...e-reexport-in-public-api-generics-81141.rs | 0 ...ate-reexport-in-public-api-hidden-81141.rs | 0 ...te-reexport-in-public-api-private-81141.rs | 0 .../inline_local/pub-re-export-28537.rs | 0 ...ed-macro-and-macro-export-sidebar-89852.rs | 0 .../inline_local/staged-inline.rs | 0 .../inline_local/trait-vis.rs | 0 tests/{rustdoc => rustdoc-html}/internal.rs | 0 .../intra-doc-crate/auxiliary/self.rs | 0 .../intra-doc-crate/self.rs | 0 .../intra-doc/anchors.rs | 0 .../intra-doc/assoc-reexport-super.rs | 0 .../intra-doc/associated-defaults.rs | 0 .../intra-doc/associated-items.rs | 0 .../intra-doc/auxiliary/empty.rs | 0 .../intra-doc/auxiliary/empty2.rs | 0 .../auxiliary/extern-builtin-type-impl-dep.rs | 0 .../auxiliary/extern-inherent-impl-dep.rs | 0 .../auxiliary/intra-link-extern-crate.rs | 0 .../intra-doc/auxiliary/intra-link-pub-use.rs | 0 .../intra-link-reexport-additional-docs.rs | 0 .../auxiliary/intra-links-external-traits.rs | 0 .../intra-doc/auxiliary/issue-66159-1.rs | 0 .../intra-doc/auxiliary/my-core.rs | 0 .../intra-doc/auxiliary/proc-macro-macro.rs | 0 .../intra-doc/auxiliary/pub-struct.rs | 0 .../intra-doc/basic.rs | 0 .../intra-doc/builtin-macros.rs | 0 .../intra-doc/crate-relative-assoc.rs | 0 .../intra-doc/crate-relative.rs | 0 .../intra-doc/cross-crate/additional_doc.rs | 0 .../cross-crate/auxiliary/additional_doc.rs | 0 .../intra-doc/cross-crate/auxiliary/hidden.rs | 0 .../cross-crate/auxiliary/intra-doc-basic.rs | 0 .../auxiliary/intra-link-cross-crate-crate.rs | 0 .../cross-crate/auxiliary/macro_inner.rs | 0 .../intra-doc/cross-crate/auxiliary/module.rs | 0 .../cross-crate/auxiliary/proc_macro.rs | 0 .../cross-crate/auxiliary/submodule-inner.rs | 0 .../cross-crate/auxiliary/submodule-outer.rs | 0 .../intra-doc/cross-crate/auxiliary/traits.rs | 0 .../intra-doc/cross-crate/basic.rs | 0 .../intra-doc/cross-crate/crate.rs | 0 .../intra-doc/cross-crate/hidden.rs | 0 .../intra-doc/cross-crate/macro.rs | 0 .../intra-doc/cross-crate/module.rs | 0 .../intra-doc/cross-crate/submodule-inner.rs | 0 .../intra-doc/cross-crate/submodule-outer.rs | 0 .../intra-doc/cross-crate/traits.rs | 0 .../intra-doc/deps.rs | 0 .../intra-doc/disambiguators-removed.rs | 0 .../intra-doc/email-address.rs | 0 .../intra-doc/enum-self-82209.rs | 0 .../intra-doc/enum-struct-field.rs | 0 .../intra-doc/extern-builtin-type-impl.rs | 0 .../extern-crate-only-used-in-link.rs | 0 .../intra-doc/extern-crate.rs | 0 .../intra-doc/extern-inherent-impl.rs | 0 .../intra-doc/extern-reference-link.rs | 0 .../intra-doc/extern-type.rs | 0 .../intra-doc/external-traits.rs | 0 .../intra-doc/field.rs | 0 .../intra-doc/filter-out-private.rs | 0 .../intra-doc/generic-params.rs | 0 .../intra-doc/generic-trait-impl.rs | 0 .../intra-doc/ice-intra-doc-links-107995.rs | 0 .../intra-doc/in-bodies.rs | 0 .../intra-doc/inherent-associated-types.rs | 0 .../intra-doc-link-method-trait-impl-72340.rs | 0 .../intra-doc/libstd-re-export.rs | 0 .../intra-doc/link-in-footnotes-132208.rs | 0 ...ame-name-different-disambiguator-108459.rs | 0 .../intra-doc/link-to-proc-macro.rs | 0 .../intra-doc/macro-caching-144965.rs | 0 .../intra-doc/macros-disambiguators.rs | 0 .../intra-doc/mod-ambiguity.rs | 0 .../intra-doc/mod-relative.rs | 0 .../module-scope-name-resolution-55364.rs | 0 .../intra-doc/nested-use.rs | 0 .../intra-doc/no-doc-primitive.rs | 0 .../intra-doc/non-path-primitives.rs | 0 .../intra-doc/prim-assoc.rs | 0 .../intra-doc/prim-associated-traits.rs | 0 .../intra-doc/prim-methods-external-core.rs | 0 .../intra-doc/prim-methods-local.rs | 0 .../intra-doc/prim-methods.rs | 0 .../intra-doc/prim-precedence.rs | 0 .../intra-doc/prim-self.rs | 0 .../intra-doc/primitive-disambiguators.rs | 0 .../intra-doc/primitive-non-default-impl.rs | 0 .../intra-doc/private-failures-ignored.rs | 0 .../intra-doc/private.rs | 0 .../intra-doc/proc-macro.rs | 0 .../intra-doc/pub-use.rs | 0 .../intra-doc/raw-ident-self.rs | 0 .../intra-doc/reexport-additional-docs.rs | 0 .../same-name-different-crates-66159.rs | 0 .../intra-doc/self-cache.rs | 0 .../intra-doc/self.rs | 0 .../intra-doc/trait-impl.rs | 0 .../intra-doc/trait-item.rs | 0 .../intra-doc/true-false.rs | 0 .../intra-doc/type-alias-primitive.rs | 0 .../intra-doc/type-alias.rs | 0 .../invalid$crate$name.rs | 0 .../item-desc-list-at-start.item-table.html | 0 .../item-desc-list-at-start.rs | 0 .../jump-to-def/assoc-items.rs | 0 .../jump-to-def/assoc-types.rs | 0 .../jump-to-def/auxiliary/symbols.rs | 0 .../jump-to-def/derive-macro.rs | 0 .../jump-to-def/doc-links-calls.rs | 0 .../jump-to-def/doc-links.rs | 0 .../jump-to-def/macro.rs | 0 .../jump-to-def/no-body-items.rs | 0 .../jump-to-def/non-local-method.rs | 0 .../jump-to-def/patterns.rs | 0 .../jump-to-def/prelude-types.rs | 0 .../jump-to-def/shebang.rs | 0 tests/{rustdoc => rustdoc-html}/keyword.rs | 0 .../lifetime-name.rs | 0 .../{rustdoc => rustdoc-html}/line-breaks.rs | 0 .../link-on-path-with-generics.rs | 0 .../link-title-escape.rs | 0 .../links-in-headings.rs | 0 .../logo-class-default.rs | 0 .../logo-class-rust.rs | 0 tests/{rustdoc => rustdoc-html}/logo-class.rs | 0 .../field-followed-by-exclamation.rs | 0 .../macro-expansion/type-macro-expansion.rs | 0 .../macro/auxiliary/external-macro-src.rs | 0 .../macro/auxiliary/issue-99221-aux.rs | 0 .../macro/auxiliary/macro_pub_in_module.rs | 0 .../macro/auxiliary/one-line-expand.rs | 0 .../macro/auxiliary/pub-use-extern-macros.rs | 0 .../macro/compiler-derive-proc-macro.rs | 0 .../macro/const-rendering-macros-33302.rs | 0 .../macro/decl_macro.rs | 0 .../macro/decl_macro_priv.rs | 0 .../macro/doc-proc-macro.rs | 0 .../macro/external-macro-src.rs | 0 .../macro/macro-const-display-115295.rs | 0 .../macro/macro-doc-comment-23812.rs | 0 .../macro/macro-export-crate-root-108231.rs | 0 ...o-generated-macro.macro_linebreak_pre.html | 0 ...o-generated-macro.macro_morestuff_pre.html | 0 .../macro/macro-generated-macro.rs | 0 .../macro/macro-higher-kinded-function.rs | 0 .../macro/macro-ice-16019.rs | 0 .../macro/macro-in-async-block.rs | 0 .../macro/macro-in-closure.rs | 0 .../macro/macro-indirect-use.rs | 0 .../macro/macro_expansion.rs | 0 .../macro/macro_pub_in_module.rs | 0 .../macro/macro_rules-matchers.rs | 0 .../{rustdoc => rustdoc-html}/macro/macros.rs | 0 .../multiple-macro-rules-w-same-name-99221.rs | 0 ...macro-rules-w-same-name-submodule-99221.rs | 0 .../macro/one-line-expand.rs | 0 .../macro/proc-macro.rs | 0 .../macro/pub-use-extern-macros.rs | 0 .../macro/rustc-macro-crate.rs | 0 .../markdown-60482.rs | 0 .../markdown-table-escape-pipe-27862.rs | 0 tests/{rustdoc => rustdoc-html}/masked.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/tango.rs | 0 .../cargo-transitive-read-write/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/romeo.rs | 0 .../auxiliary/sierra.rs | 0 .../auxiliary/tango.rs | 0 .../kitchen-sink-separate-dirs/indigo.rs | 0 .../no-merge-separate/auxiliary/quebec.rs | 0 .../no-merge-separate/auxiliary/tango.rs | 0 .../no-merge-separate/sierra.rs | 0 .../no-merge-write-anyway/auxiliary/quebec.rs | 0 .../no-merge-write-anyway/auxiliary/tango.rs | 0 .../no-merge-write-anyway/sierra.rs | 0 .../overwrite-but-include/auxiliary/quebec.rs | 0 .../overwrite-but-include/auxiliary/tango.rs | 0 .../overwrite-but-include/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../overwrite-but-separate/auxiliary/tango.rs | 0 .../overwrite-but-separate/sierra.rs | 0 .../overwrite/auxiliary/quebec.rs | 0 .../overwrite/auxiliary/tango.rs | 0 .../overwrite/sierra.rs | 0 .../single-crate-finalize/quebec.rs | 0 .../single-crate-read-write/quebec.rs | 0 .../single-crate-write-anyway/quebec.rs | 0 .../single-merge-none-useless-write/quebec.rs | 0 .../transitive-finalize/auxiliary/quebec.rs | 0 .../transitive-finalize/auxiliary/tango.rs | 0 .../transitive-finalize/sierra.rs | 0 .../transitive-merge-none/auxiliary/quebec.rs | 0 .../transitive-merge-none/auxiliary/tango.rs | 0 .../transitive-merge-none/sierra.rs | 0 .../auxiliary/quebec.rs | 0 .../auxiliary/tango.rs | 0 .../transitive-merge-read-write/sierra.rs | 0 .../transitive-no-info/auxiliary/quebec.rs | 0 .../transitive-no-info/auxiliary/tango.rs | 0 .../transitive-no-info/sierra.rs | 0 .../two-separate-out-dir/auxiliary/foxtrot.rs | 0 .../two-separate-out-dir/echo.rs | 0 .../{rustdoc => rustdoc-html}/method-list.rs | 0 ...ing-doc-comments-and-attrs.S1_top-doc.html | 0 ...ing-doc-comments-and-attrs.S2_top-doc.html | 0 ...ing-doc-comments-and-attrs.S3_top-doc.html | 0 .../mixing-doc-comments-and-attrs.rs | 0 .../mod-stackoverflow.rs | 0 .../multiple-foreigns-w-same-name-99734.rs | 0 .../multiple-import-levels.rs | 0 .../multiple-mods-w-same-name-99734.rs | 0 ...tiple-mods-w-same-name-doc-inline-83375.rs | 0 ...-w-same-name-doc-inline-last-item-83375.rs | 0 .../multiple-structs-w-same-name-99221.rs | 0 tests/{rustdoc => rustdoc-html}/mut-params.rs | 0 tests/{rustdoc => rustdoc-html}/namespaces.rs | 0 .../nested-items-issue-111415.rs | 0 .../nested-modules.rs | 0 .../no-run-still-checks-lints.rs | 0 .../no-stack-overflow-25295.rs | 0 .../no-unit-struct-field.rs | 0 .../non_lifetime_binders.rs | 0 ...-notable_trait-mut_t_is_not_an_iterator.rs | 0 .../doc-notable_trait-mut_t_is_not_ref_t.rs | 0 .../doc-notable_trait-negative.negative.html | 0 .../doc-notable_trait-negative.positive.html | 0 .../doc-notable_trait-negative.rs | 0 ...c-notable_trait-slice.bare_fn_matches.html | 0 .../notable-trait/doc-notable_trait-slice.rs | 0 .../doc-notable_trait.bare-fn.html | 0 .../notable-trait/doc-notable_trait.rs | 0 .../doc-notable_trait.some-struct-new.html | 0 .../doc-notable_trait.wrap-me.html | 0 ...oc-notable_trait_box_is_not_an_iterator.rs | 0 .../notable-trait/notable-trait-generics.rs | 0 .../spotlight-from-dependency.odd.html | 0 .../spotlight-from-dependency.rs | 0 tests/{rustdoc => rustdoc-html}/nul-error.rs | 0 .../playground-arg.rs | 0 .../playground-empty.rs | 0 .../playground-none.rs | 0 .../playground-syntax-error.rs | 0 tests/{rustdoc => rustdoc-html}/playground.rs | 0 .../primitive/auxiliary/issue-15318.rs | 0 .../primitive/auxiliary/primitive-doc.rs | 0 .../primitive/cross-crate-primitive-doc.rs | 0 .../primitive/no_std-primitive.rs | 0 .../primitive/no_std.rs | 0 .../primitive/primitive-generic-impl.rs | 0 .../primitive/primitive-link.rs | 0 .../primitive-raw-pointer-dox-15318-3.rs | 0 .../primitive-raw-pointer-link-15318.rs | 0 ...ive-raw-pointer-link-no-inlined-15318-2.rs | 0 .../primitive/primitive-reference.rs | 0 .../primitive/primitive-slice-auto-trait.rs | 0 .../primitive/primitive-tuple-auto-trait.rs | 0 .../primitive/primitive-tuple-variadic.rs | 0 .../primitive/primitive-unit-auto-trait.rs | 0 .../primitive/primitive.rs | 0 ...h-index-primitive-inherent-method-23511.rs | 0 .../private/doc-hidden-private-67851-both.rs | 0 .../doc-hidden-private-67851-hidden.rs | 0 .../doc-hidden-private-67851-neither.rs | 0 .../doc-hidden-private-67851-private.rs | 0 .../empty-impl-block-private-with-doc.rs | 0 .../private/empty-impl-block-private.rs | 0 .../private/empty-mod-private.rs | 0 .../private/enum-variant-private-46767.rs | 0 .../private/files-creation-private.rs | 0 .../private/hidden-private.rs | 0 ...ne-private-with-intermediate-doc-hidden.rs | 0 .../private/inner-private-110422.rs | 0 .../macro-document-private-duplicate.rs | 0 .../private/macro-document-private.rs | 0 .../private/macro-private-not-documented.rs | 0 .../missing-private-inlining-109258.rs | 0 .../private/private-fields-tuple-struct.rs | 0 .../private/private-non-local-fields-2.rs | 0 .../private/private-non-local-fields.rs | 0 .../private/private-type-alias.rs | 0 .../private/private-type-cycle-110629.rs | 0 .../private/private-use-decl-macro-47038.rs | 0 .../private/private-use.rs | 0 ...ic-impl-mention-private-generic-46380-2.rs | 0 .../private/traits-in-bodies-private.rs | 0 .../process-termination.rs | 0 tests/{rustdoc => rustdoc-html}/pub-method.rs | 0 .../pub-use-loop-107350.rs | 0 .../pub-use-root-path-95873.rs | 0 .../range-arg-pattern.rs | 0 .../raw-ident-eliminate-r-hashtag.rs | 0 .../read-more-unneeded.rs | 0 tests/{rustdoc => rustdoc-html}/recursion1.rs | 0 tests/{rustdoc => rustdoc-html}/recursion2.rs | 0 tests/{rustdoc => rustdoc-html}/recursion3.rs | 0 .../redirect-map-empty.rs | 0 .../{rustdoc => rustdoc-html}/redirect-map.rs | 0 .../redirect-rename.rs | 0 tests/{rustdoc => rustdoc-html}/redirect.rs | 0 .../reexport/alias-reexport.rs | 0 .../reexport/alias-reexport2.rs | 0 .../reexport/anonymous-reexport-108931.rs | 0 .../reexport/anonymous-reexport.rs | 0 .../reexport/auxiliary/alias-reexport.rs | 0 .../reexport/auxiliary/alias-reexport2.rs | 0 .../reexport/auxiliary/all-item-types.rs | 0 .../reexport/auxiliary/issue-28927-1.rs | 0 .../reexport/auxiliary/issue-28927-2.rs | 0 .../reexport/auxiliary/primitive-reexport.rs | 0 .../reexport/auxiliary/reexport-check.rs | 0 .../reexport/auxiliary/reexport-doc-aux.rs | 0 .../reexport/auxiliary/reexports.rs | 0 .../reexport/auxiliary/wrap-unnamable-type.rs | 0 .../reexport/blanket-reexport-item.rs | 0 .../reexport/cfg_doc_reexport.rs | 0 .../reexport/doc-hidden-reexports-109449.rs | 0 .../duplicated-glob-reexport-60522.rs | 0 .../reexport/enum-variant-reexport-35488.rs | 0 .../reexport/enum-variant.rs | 0 .../reexport/extern-135092.rs | 0 .../reexport/foreigntype-reexport.rs | 0 .../glob-reexport-attribute-merge-120487.rs | 0 ...b-reexport-attribute-merge-doc-auto-cfg.rs | 0 .../reexport/ice-reexport-crate-root-28927.rs | 0 .../import_trait_associated_functions.rs | 0 .../reexport/local-reexport-doc.rs | 0 .../reexport/merge-glob-and-non-glob.rs | 0 .../reexport/no-compiler-reexport.rs | 0 .../reexport/overlapping-reexport-105735-2.rs | 0 .../reexport/overlapping-reexport-105735.rs | 0 .../reexport/primitive-reexport.rs | 0 .../reexport/private-mod-override-reexport.rs | 0 .../pub-reexport-of-pub-reexport-46506.rs | 0 .../reexport/reexport-attr-merge.rs | 0 .../reexport/reexport-cfg.rs | 0 .../reexport/reexport-check.rs | 0 .../reexport/reexport-dep-foreign-fn.rs | 0 .../reexport-doc-hidden-inside-private.rs | 0 .../reexport/reexport-doc-hidden.rs | 0 .../reexport/reexport-doc.rs | 0 .../reexport/reexport-hidden-macro.rs | 0 .../reexport/reexport-macro.rs | 0 .../reexport/reexport-of-doc-hidden.rs | 0 .../reexport/reexport-of-reexport-108679.rs | 0 ...ability-tags-deprecated-and-portability.rs | 0 ...stability-tags-unstable-and-portability.rs | 0 .../reexport-trait-from-hidden-111064-2.rs | 0 .../reexport-trait-from-hidden-111064.rs | 0 .../reexport/reexports-of-same-name.rs | 0 .../reexport/reexports-priv.rs | 0 .../reexport/reexports.rs | 0 .../reexport/wrapped-unnamble-type-143222.rs | 0 .../remove-duplicates.rs | 0 .../remove-url-from-headings.rs | 0 tests/{rustdoc => rustdoc-html}/repr.rs | 0 .../resolve-ice-124363.rs | 0 .../return-type-notation.rs | 0 .../safe-intrinsic.rs | 0 .../sanitizer-option.rs | 0 .../search-index-summaries.rs | 0 .../{rustdoc => rustdoc-html}/search-index.rs | 0 .../short-docblock-codeblock.rs | 0 .../short-docblock.rs | 0 tests/{rustdoc => rustdoc-html}/short-line.md | 0 .../sidebar/module.rs | 0 .../sidebar/sidebar-all-page.rs | 0 .../sidebar/sidebar-items.rs | 0 .../sidebar/sidebar-link-generation.rs | 0 .../sidebar/sidebar-links-to-foreign-impl.rs | 0 .../sidebar/top-toc-html.rs | 0 .../sidebar/top-toc-idmap.rs | 0 .../sidebar/top-toc-nil.rs | 0 .../{rustdoc => rustdoc-html}/sized_trait.rs | 0 .../slice-links.link_box_generic.html | 0 .../slice-links.link_box_u32.html | 0 .../slice-links.link_slice_generic.html | 0 .../slice-links.link_slice_u32.html | 0 .../{rustdoc => rustdoc-html}/slice-links.rs | 0 .../{rustdoc => rustdoc-html}/smart-punct.rs | 0 tests/{rustdoc => rustdoc-html}/smoke.rs | 0 tests/{rustdoc => rustdoc-html}/sort-53812.rs | 0 .../sort-modules-by-appearance.rs | 0 .../assoc-type-source-link.rs | 0 .../auxiliary/issue-26606-macro.rs | 0 .../auxiliary/issue-34274.rs | 0 .../auxiliary/source-code-bar.rs | 0 .../auxiliary/source_code.rs | 0 .../auxiliary/src-links-external.rs | 0 .../check-source-code-urls-to-def-std.rs | 0 .../check-source-code-urls-to-def.rs | 0 .../source-code-pages/doc-hidden-source.rs | 0 .../failing-expansion-on-wrong-macro.rs | 0 .../source-code-pages/frontmatter.rs | 0 .../source-code-pages/html-no-source.rs | 0 .../source-code-pages/keyword-macros.rs | 0 .../source-code-pages/shebang.rs | 0 .../source-code-highlight.rs | 0 .../source-code-pages/source-file.rs | 0 .../source-code-pages/source-line-numbers.rs | 0 .../source-version-separator.rs | 0 .../src-link-external-macro-26606.rs | 0 .../source-code-pages/src-links-auto-impls.rs | 0 .../source-code-pages/src-links-external.rs | 0 .../src-links-implementor-43893.rs | 0 .../src-links-inlined-34274.rs | 0 .../source-code-pages/src-links.rs | 0 .../src-links/compiletest-ignore-dir | 0 .../source-code-pages/src-links/fizz.rs | 0 .../source-code-pages/src-links/mod.rs | 0 .../src-mod-path-absolute-26995.rs | 0 .../version-separator-without-source.rs | 0 tests/{rustdoc => rustdoc-html}/stability.rs | 0 .../staged-api-deprecated-unstable-32374.rs | 0 .../staged-api-feature-issue-27759.rs | 0 .../static-root-path.rs | 0 tests/{rustdoc => rustdoc-html}/static.rs | 0 ...rip-block-doc-comments-stars.docblock.html | 0 .../strip-block-doc-comments-stars.rs | 0 .../strip-priv-imports-pass-27104.rs | 0 .../struct-arg-pattern.rs | 0 .../{rustdoc => rustdoc-html}/struct-field.rs | 0 .../{rustdoc => rustdoc-html}/structfields.rs | 0 .../summary-codeblock-31899.rs | 0 .../summary-header-46377.rs | 0 .../summary-reference-link-30366.rs | 0 .../auto-trait-lifetimes-56822.rs | 0 .../synthetic_auto/basic.rs | 0 .../synthetic_auto/bounds.rs | 0 .../synthetic_auto/complex.rs | 0 .../synthetic_auto/crate-local.rs | 0 .../issue-72213-projection-lifetime.rs | 0 .../synthetic_auto/lifetimes.rs | 0 .../synthetic_auto/manual.rs | 0 .../synthetic_auto/negative.rs | 0 .../synthetic_auto/nested.rs | 0 .../synthetic_auto/no-redundancy.rs | 0 .../normalize-auto-trait-80233.rs | 0 .../synthetic_auto/overflow.rs | 0 .../synthetic_auto/project.rs | 0 .../synthetic_auto/self-referential.rs | 0 .../send-impl-conditional-60726.rs | 0 .../synthetic_auto/static-region.rs | 0 .../synthetic_auto/supertrait-bounds.rs | 0 tests/{rustdoc => rustdoc-html}/tab_title.rs | 0 .../table-in-docblock.rs | 0 .../target-feature.rs | 0 tests/{rustdoc => rustdoc-html}/task-lists.rs | 0 tests/{rustdoc => rustdoc-html}/test-lists.rs | 0 .../{rustdoc => rustdoc-html}/test-parens.rs | 0 .../test-strikethrough.rs | 0 .../test_option_check/bar.rs | 0 .../test_option_check/test.rs | 0 .../thread-local-src.rs | 0 tests/{rustdoc => rustdoc-html}/titles.rs | 0 .../toggle-item-contents.rs | 0 .../toggle-method.rs | 0 .../toggle-trait-fn.rs | 0 .../trait-aliases.rs | 0 .../trait-item-info.rs | 0 .../trait-self-link.rs | 0 .../trait-src-link.rs | 0 .../trait-visibility.rs | 0 .../traits-in-bodies.rs | 0 .../tuple-struct-fields-doc.rs | 0 .../tuple-struct-where-clause-34928.rs | 0 .../tuples.link1_i32.html | 0 .../tuples.link1_t.html | 0 .../tuples.link2_i32.html | 0 .../tuples.link2_t.html | 0 .../tuples.link2_tu.html | 0 .../tuples.link_unit.html | 0 tests/{rustdoc => rustdoc-html}/tuples.rs | 0 .../auxiliary/parent-crate-115718.rs | 0 .../type-alias/cross-crate-115718.rs | 0 .../type-alias/deeply-nested-112515.rs | 0 .../type-alias/deref-32077.rs | 0 .../type-alias/impl_trait_in_assoc_type.rs | 0 .../type-alias/primitive-local-link-121106.rs | 0 .../type-alias/repr.rs | 0 .../type-alias/same-crate-115718.rs | 0 .../type-layout-flag-required.rs | 0 .../{rustdoc => rustdoc-html}/type-layout.rs | 0 .../typedef-inner-variants-lazy_type_alias.rs | 0 .../typedef-inner-variants.rs | 0 tests/{rustdoc => rustdoc-html}/typedef.rs | 0 .../underscore-import-61592.rs | 0 tests/{rustdoc => rustdoc-html}/unindent.md | 0 tests/{rustdoc => rustdoc-html}/unindent.rs | 0 .../union-fields-html.rs | 0 tests/{rustdoc => rustdoc-html}/union.rs | 0 .../{rustdoc => rustdoc-html}/unit-return.rs | 0 .../unsafe-binder.rs | 0 tests/{rustdoc => rustdoc-html}/use-attr.rs | 0 .../useless_lifetime_bound.rs | 0 tests/{rustdoc => rustdoc-html}/variadic.rs | 0 .../viewpath-rename.rs | 0 .../viewpath-self.rs | 0 tests/{rustdoc => rustdoc-html}/visibility.rs | 0 .../where-clause-order.rs | 0 .../{rustdoc => rustdoc-html}/where-sized.rs | 0 .../where.SWhere_Echo_impl.html | 0 .../where.SWhere_Simd_item-decl.html | 0 .../where.SWhere_TraitWhere_item-decl.html | 0 .../where.alpha_trait_decl.html | 0 .../where.bravo_trait_decl.html | 0 .../where.charlie_fn_decl.html | 0 .../where.golf_type_alias_decl.html | 0 tests/{rustdoc => rustdoc-html}/where.rs | 0 .../whitespace-after-where-clause.enum.html | 0 .../whitespace-after-where-clause.enum2.html | 0 .../whitespace-after-where-clause.rs | 0 .../whitespace-after-where-clause.struct.html | 0 ...whitespace-after-where-clause.struct2.html | 0 .../whitespace-after-where-clause.trait.html | 0 .../whitespace-after-where-clause.trait2.html | 0 .../whitespace-after-where-clause.union.html | 0 .../whitespace-after-where-clause.union2.html | 0 .../without-redirect.rs | 0 tests/{rustdoc => rustdoc-html}/wrapping.rs | 0 triagebot.toml | 6 +++--- 1076 files changed, 69 insertions(+), 60 deletions(-) create mode 100644 src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap create mode 100644 src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap rename tests/{rustdoc => rustdoc-html}/all.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-duplicate-method-name-25001.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-trait-method-15169.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchor-id-trait-tymethod-28478.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_const_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_const_anchor2.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_method_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_trait_method_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_tymethod_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_type_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.no_type_anchor2.html (100%) rename tests/{rustdoc => rustdoc-html}/anchors/anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/auxiliary/issue-86620-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/disambiguate-anchors-32890.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/disambiguate-anchors-header-29449.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/method-anchor-in-blanket-impl-86620.rs (100%) rename tests/{rustdoc => rustdoc-html}/anchors/trait-impl-items-links-and-anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/anon-fn-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/anonymous-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_box_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_box_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_slice_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.link_slice_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/array-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/asm-foreign.rs (100%) rename tests/{rustdoc => rustdoc-html}/asm-foreign2.rs (100%) rename tests/{rustdoc => rustdoc-html}/asref-for-and-of-local-82465.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-fns.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-item-cast.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-type-bindings-20646.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/assoc-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/issue-20646.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/issue-20727.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/auxiliary/normalize-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/cross-crate-hidden-assoc-trait-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/doc-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bindings.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds-deref.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds-index.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/inline-assoc-type-20727-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/assoc/normalize-assoc-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-fn-opaque-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-move-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-trait-sig.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/async-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/async/auxiliary/async-trait-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-2021-edition.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-inlining-108281.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-re-export-2021-edition.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes-re-export.rs (100%) rename tests/{rustdoc => rustdoc-html}/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-impl-for-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-impl-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-by-associated-type-50159.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-inference-variables-54705.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-bounds-where-51236.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-negative-impl-55321.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-trait-not-send.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auto_aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/auto/auxiliary/auto-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/all-item-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/cross_crate_generic_typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/elided-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/enum-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-anon-fn-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/ext-trait-aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/inline-default-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-106421-force-unstable.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-13698.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-19190-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-61592.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-99221-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/issue-99734-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/jump-to-def-res-err-handling-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/masked.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/mod-stackoverflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/reexp-stripped.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/remapped-paths.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/rustdoc-ffi.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/trait-visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unit-return.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unsafe-binder-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/auxiliary/unstable-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/bad-codeblock-syntax.rs (100%) rename tests/{rustdoc => rustdoc-html}/blank-line-in-doc-block-47197.rs (100%) rename tests/{rustdoc => rustdoc-html}/bold-tag-101743.rs (100%) rename tests/{rustdoc => rustdoc-html}/bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/cap-lints.rs (100%) rename tests/{rustdoc => rustdoc-html}/cfg-bool.rs (100%) rename tests/{rustdoc => rustdoc-html}/cfg-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/check-styled-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/check.rs (100%) rename tests/{rustdoc => rustdoc-html}/codeblock-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/comment-in-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn-76501.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn-effects.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/add-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/auxiliary/extern_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generic-defaults.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generic-slice.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-generics-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/const-param-type-references-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/generic_const_exprs.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/lazy_normalization_consts/const-equate-pred.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-generics/type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/const-intrinsic.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts-underscore.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/assoc-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/associated-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-display.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-trait-and-impl-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-underscore.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const-value-display.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/document-item-with-associated-const-in-where-clause.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/generic_const_exprs.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/glob-shadowing-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/hide-complex-unevaluated-const-arguments.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/hide-complex-unevaluated-consts.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/ice-associated-const-equality-105952.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/legacy-const-generic.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/link-assoc-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/redirect-const.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/rfc-2632-const-trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/constant/show-const-contents.rs (100%) rename tests/{rustdoc => rustdoc-html}/constructor-imports.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-doc-hidden-109695.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version-extra.rs (100%) rename tests/{rustdoc => rustdoc-html}/crate-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive-no-index/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-transitive/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two-no-index/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two-no-index/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/cargo-two/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/index-on-last/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/index-on-last/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/r.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/kitchen-sink/i.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/single-crate-baseline/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/single-crate-no-index/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/auxiliary/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/auxiliary/t.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/transitive/s.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/two/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/two/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/working-dir-examples/q.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-info/write-docs-somewhere-else/e.rs (100%) rename tests/{rustdoc => rustdoc-html}/cross-crate-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/custom_code_classes.rs (100%) rename tests/{rustdoc => rustdoc-html}/decl-line-wrapping-empty-arg-list.decl.html (100%) rename tests/{rustdoc => rustdoc-html}/decl-line-wrapping-empty-arg-list.rs (100%) rename tests/{rustdoc => rustdoc-html}/decl-trailing-whitespace.declaration.html (100%) rename tests/{rustdoc => rustdoc-html}/decl-trailing-whitespace.rs (100%) rename tests/{rustdoc => rustdoc-html}/deep-structures.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-theme.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-trait-method-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/demo-allocator-54478.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated-future-staged-api.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated-future.rs (100%) rename tests/{rustdoc => rustdoc-html}/deprecated.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190-foreign-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190-inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-methods-19190.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-mut-35169-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref-mut-35169.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-const-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-methods-24686-target.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-multiple-impl-blocks.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-mut-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-recursive-pathbuf.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-recursive.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-slice-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-to-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/deref-typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/escape-deref-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/recursive-deref-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/recursive-deref.rs (100%) rename tests/{rustdoc => rustdoc-html}/deref/sidebar-links-deref-100679.rs (100%) rename tests/{rustdoc => rustdoc-html}/description.rs (100%) rename tests/{rustdoc => rustdoc-html}/description_default.rs (100%) rename tests/{rustdoc => rustdoc-html}/display-hidden-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-attr-comment-mix-42760.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-attribute.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-auto-cfg-public-in-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-hide.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-implicit-gate.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-implicit.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-inherit-from-module-79201.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-simplification.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/doc-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-cfg/duplicate-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-hidden-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-hidden-method-13698.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-on-keyword.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc-test-attr-18199.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc_auto_cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/doc_auto_cfg_reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/auxiliary/doctest-runtool.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-cfg-feature-30252.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-crate-attributes-38129.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-escape-boring-41783.codeblock.html (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-escape-boring-41783.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-hide-empty-line-23106.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-ignore-32556.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-include-43153.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-macro-38219.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-manual-crate-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-markdown-inline-parse-23744.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-markdown-trailing-docblock-48377.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-multi-line-string-literal-25944.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/doctest-runtool.rs (100%) rename tests/{rustdoc => rustdoc-html}/doctest/ignore-sometimes.rs (100%) rename tests/{rustdoc => rustdoc-html}/document-hidden-items-15347.rs (100%) rename tests/{rustdoc => rustdoc-html}/double-hyphen-to-dash.rs (100%) rename tests/{rustdoc => rustdoc-html}/double-quote-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate-flags.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate_impls/impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/duplicate_impls/sidebar-links-duplicate-impls-33054.rs (100%) rename tests/{rustdoc => rustdoc-html}/dyn-compatibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/early-unindent.rs (100%) rename tests/{rustdoc => rustdoc-html}/edition-doctest.rs (100%) rename tests/{rustdoc => rustdoc-html}/edition-flag.rs (100%) rename tests/{rustdoc => rustdoc-html}/elided-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-doc-comment.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-mod-public.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-section.rs (100%) rename tests/{rustdoc => rustdoc-html}/empty-tuple-struct-118180.rs (100%) rename tests/{rustdoc => rustdoc-html}/ensure-src-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/auxiliary/enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/auxiliary/variant-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-non-exhaustive-108925.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-doc-hidden-field-88600.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-fields-heading.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-fields-heading.variants.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.type-alias-code.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-non_exhaustive.type-code.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/enum-variant-value.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/render-enum-variant-structlike-32395.rs (100%) rename tests/{rustdoc => rustdoc-html}/enum/strip-enum-variant.no-not-shown.html (100%) rename tests/{rustdoc => rustdoc-html}/enum/strip-enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/extern-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-cross-doc.md (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-cross.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/external-doc.md (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/html_root.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/issue-30109-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/no_html_root.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/panic-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/pub-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/rustdoc-extern-default-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/rustdoc-extern-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/auxiliary/variant-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/duplicate-reexports-section-150211.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-default-method.no_href_on_anchor.html (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-default-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-fn-22038.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-fallback.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-root-url-precedence.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-html-root-url.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/extern-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/external-cross.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/external-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/hidden-extern-34025.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-33178.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-item-30109.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/link-extern-crate-title-33178.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/pub-extern-crate-150176.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/pub-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/unsafe-extern-blocks.rs (100%) rename tests/{rustdoc => rustdoc-html}/extern/unused-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/extremely_long_typename.extremely_long_typename.html (100%) rename tests/{rustdoc => rustdoc-html}/extremely_long_typename.rs (100%) rename tests/{rustdoc => rustdoc-html}/feature-gate-doc_auto_cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/ffi.rs (100%) rename tests/{rustdoc => rustdoc-html}/file-creation-111249.rs (100%) rename tests/{rustdoc => rustdoc-html}/files-creation-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-bound.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-pointer-arg-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/fn-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-definition-without-blank-line-100638.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-ids.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-in-summary.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-reference-ids.rs (100%) rename tests/{rustdoc => rustdoc-html}/footnote-reference-in-footnote-def.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-unstable-if-unmarked-106421-not-internal.rs (100%) rename tests/{rustdoc => rustdoc-html}/force-unstable-if-unmarked-106421.rs (100%) rename tests/{rustdoc => rustdoc-html}/foreigntype.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gat-elided-lifetime-94683.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gat-linkification-109488.rs (100%) rename tests/{rustdoc => rustdoc-html}/generic-associated-types/gats.rs (100%) rename tests/{rustdoc => rustdoc-html}/glob-shadowing.rs (100%) rename tests/{rustdoc => rustdoc-html}/heading-levels-89309.rs (100%) rename tests/{rustdoc => rustdoc-html}/heterogeneous-concat.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-line.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-trait-methods-with-document-hidden-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/hidden-trait-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/hide-unstable-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/higher-ranked-trait-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/highlight-invalid-rust-12834.rs (100%) rename tests/{rustdoc => rustdoc-html}/ice-type-error-19181.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/cross-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/extern-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/incoherent-impl-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-100204-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-17476.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-21092.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-22025.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/issue-53689.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/precise-capturing.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/real_gimli.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/realcore.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/rustdoc-default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/blanket-impl-29503.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/blanket-impl-78673.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/cross-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deduplicate-glob-import-impl-21474.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deduplicate-trait-impl-22025.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/deprecated-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/doc-hidden-trait-implementors-33069.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/doc_auto_cfg_nested_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/duplicated_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/empty-impl-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/empty-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/extern-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/extern-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/foreign-implementors-js-43701.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/generic-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-implementors-90781.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hidden-trait-struct-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-alias-substituted.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-assoc-type-21092.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-associated-items-order.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-associated-items-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-blanket-53689.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-box.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-disambiguation.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-everywhere.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-in-const-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-on-ty-alias-issue-119015.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-parts-crosscrate.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-parts.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-ref-20175.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-43869.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-trait-precise-capturing.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/impl-type-parameter-33592.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/implementor-stable-version.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/implementors-unstable-75588.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/inline-impl-through-glob-import-100204.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/manual_impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/method-link-foreign-trait-impl-17476.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/module-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/must_implement_one_of.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl-no-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl-sidebar.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/negative-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/return-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/rustc-incoherent-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/same-crate-hidden-impl-parameter.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/sidebar-trait-impl-disambiguate-78701.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/struct-implementations-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/trait-implementations-duplicate-self-45584.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/underscore-type-in-trait-impl-96381.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/universal-impl-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/impl/unneeded-trait-implementations-title.rs (100%) rename tests/{rustdoc => rustdoc-html}/import-remapped-paths.rs (100%) rename tests/{rustdoc => rustdoc-html}/impossible-default.rs (100%) rename tests/{rustdoc => rustdoc-html}/include_str_cut.rs (100%) rename tests/{rustdoc => rustdoc-html}/index-page.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection-16265-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection-16265-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/infinite-redirection.rs (100%) rename tests/{rustdoc => rustdoc-html}/inherent-projections.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline-default-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline-rename-34473.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/add-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc-const-equality.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out0.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out2.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.out9.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/assoc_item_trait_bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/add-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc-const-equality.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/assoc_item_trait_bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/async-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/attributes.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/cross-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/default-generic-args.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/dyn_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/early-late-bound-lifetime-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/fn-ptr-ty.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl-inline-without-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/impl_trait_aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/implementors_inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-21801.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-23207-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-23207-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-24183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-27362-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-29584.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-33113.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-46727.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-57180.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-76736-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-76736-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/issue-85454.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/macro-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/renamed-via-module.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-hidden-sig.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/rustdoc-trait-object-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/use_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/auxiliary/use_crate_2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-effect-param.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-eval-46727.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/const-fn-27362.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/cross-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/deduplicate-inlined-items-23207.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/default-generic-args.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/default-trait-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-hidden-broken-link-28480.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-hidden-extern-trait-impl-29584.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/doc-reachability-impl-31948.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/dyn_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/early-late-bound-lifetime-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/fn-ptr-ty.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/generic-const-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/hidden-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/ice-import-crate-57180.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-dyn-trait-32881.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-inline-without-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-ref-33113.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/impl_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/implementors-js.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/inline_hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/macro-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/qpath-self-85454.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/reexport-with-anonymous-lifetime-98697.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/renamed-via-module.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/ret-pos-impl-trait-in-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/rustc-private-76736-4.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/self-sized-bounds-24183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/sugar-closure-crate-21801.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_cross/use_crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/blanket-impl-reexported-trait-94183.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/doc-no-inline-32343.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/enum-variant-reexport-46766.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/fully-stable-path-is-better.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-extern-document-private-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-extern.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-private-document-private-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/glob-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/hidden-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/macro_by_example.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/parent-path-is-better.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/please_inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-81141-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-generics-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-hidden-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/private-reexport-in-public-api-private-81141.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/pub-re-export-28537.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/staged-inline.rs (100%) rename tests/{rustdoc => rustdoc-html}/inline_local/trait-vis.rs (100%) rename tests/{rustdoc => rustdoc-html}/internal.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc-crate/auxiliary/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc-crate/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/anchors.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/assoc-reexport-super.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/associated-defaults.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/associated-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/empty2.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/extern-inherent-impl-dep.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-pub-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/intra-links-external-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/issue-66159-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/my-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/proc-macro-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/auxiliary/pub-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/builtin-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/crate-relative-assoc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/crate-relative.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/additional_doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/additional_doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/macro_inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/proc_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/submodule-inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/submodule-outer.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/auxiliary/traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/submodule-inner.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/submodule-outer.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/cross-crate/traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/deps.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/disambiguators-removed.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/email-address.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/enum-self-82209.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/enum-struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-builtin-type-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-crate-only-used-in-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-inherent-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-reference-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/extern-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/external-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/field.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/filter-out-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/generic-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/generic-trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/ice-intra-doc-links-107995.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/in-bodies.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/inherent-associated-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/intra-doc-link-method-trait-impl-72340.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/libstd-re-export.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-in-footnotes-132208.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-same-name-different-disambiguator-108459.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/link-to-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/macro-caching-144965.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/macros-disambiguators.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/mod-ambiguity.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/mod-relative.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/module-scope-name-resolution-55364.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/nested-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/no-doc-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/non-path-primitives.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-assoc.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-associated-traits.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods-external-core.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods-local.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-methods.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-precedence.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/prim-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/primitive-disambiguators.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/primitive-non-default-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/private-failures-ignored.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/private.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/pub-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/raw-ident-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/reexport-additional-docs.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/same-name-different-crates-66159.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/self-cache.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/self.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/trait-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/trait-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/true-false.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/type-alias-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/intra-doc/type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/invalid$crate$name.rs (100%) rename tests/{rustdoc => rustdoc-html}/item-desc-list-at-start.item-table.html (100%) rename tests/{rustdoc => rustdoc-html}/item-desc-list-at-start.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/assoc-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/assoc-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/auxiliary/symbols.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/derive-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/doc-links-calls.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/doc-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/no-body-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/non-local-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/patterns.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/prelude-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/jump-to-def/shebang.rs (100%) rename tests/{rustdoc => rustdoc-html}/keyword.rs (100%) rename tests/{rustdoc => rustdoc-html}/lifetime-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/line-breaks.rs (100%) rename tests/{rustdoc => rustdoc-html}/link-on-path-with-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/link-title-escape.rs (100%) rename tests/{rustdoc => rustdoc-html}/links-in-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class-default.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class-rust.rs (100%) rename tests/{rustdoc => rustdoc-html}/logo-class.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro-expansion/field-followed-by-exclamation.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro-expansion/type-macro-expansion.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/external-macro-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/issue-99221-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/macro_pub_in_module.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/one-line-expand.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/auxiliary/pub-use-extern-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/compiler-derive-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/const-rendering-macros-33302.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/decl_macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/decl_macro_priv.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/doc-proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/external-macro-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-const-display-115295.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-doc-comment-23812.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-export-crate-root-108231.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.macro_linebreak_pre.html (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.macro_morestuff_pre.html (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-generated-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-higher-kinded-function.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-ice-16019.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-in-async-block.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-in-closure.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro-indirect-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_expansion.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_pub_in_module.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macro_rules-matchers.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/multiple-macro-rules-w-same-name-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/multiple-macro-rules-w-same-name-submodule-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/one-line-expand.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/proc-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/pub-use-extern-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/macro/rustc-macro-crate.rs (100%) rename tests/{rustdoc => rustdoc-html}/markdown-60482.rs (100%) rename tests/{rustdoc => rustdoc-html}/markdown-table-escape-pipe-27862.rs (100%) rename tests/{rustdoc => rustdoc-html}/masked.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-separate/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/no-merge-write-anyway/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-include/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite-but-separate/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/overwrite/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-finalize/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-read-write/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-crate-write-anyway/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-finalize/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-none/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-merge-read-write/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/transitive-no-info/sierra.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs (100%) rename tests/{rustdoc => rustdoc-html}/merge-cross-crate-info/two-separate-out-dir/echo.rs (100%) rename tests/{rustdoc => rustdoc-html}/method-list.rs (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S1_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S2_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.S3_top-doc.html (100%) rename tests/{rustdoc => rustdoc-html}/mixing-doc-comments-and-attrs.rs (100%) rename tests/{rustdoc => rustdoc-html}/mod-stackoverflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-foreigns-w-same-name-99734.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-import-levels.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-99734.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-doc-inline-83375.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-mods-w-same-name-doc-inline-last-item-83375.rs (100%) rename tests/{rustdoc => rustdoc-html}/multiple-structs-w-same-name-99221.rs (100%) rename tests/{rustdoc => rustdoc-html}/mut-params.rs (100%) rename tests/{rustdoc => rustdoc-html}/namespaces.rs (100%) rename tests/{rustdoc => rustdoc-html}/nested-items-issue-111415.rs (100%) rename tests/{rustdoc => rustdoc-html}/nested-modules.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-run-still-checks-lints.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-stack-overflow-25295.rs (100%) rename tests/{rustdoc => rustdoc-html}/no-unit-struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/non_lifetime_binders.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.negative.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.positive.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-negative.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-slice.bare_fn_matches.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait-slice.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.bare-fn.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.some-struct-new.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait.wrap-me.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/notable-trait-generics.rs (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/spotlight-from-dependency.odd.html (100%) rename tests/{rustdoc => rustdoc-html}/notable-trait/spotlight-from-dependency.rs (100%) rename tests/{rustdoc => rustdoc-html}/nul-error.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-arg.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-none.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground-syntax-error.rs (100%) rename tests/{rustdoc => rustdoc-html}/playground.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/auxiliary/issue-15318.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/auxiliary/primitive-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/cross-crate-primitive-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/no_std-primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/no_std.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-generic-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-dox-15318-3.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-link-15318.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-reference.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-slice-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-tuple-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-tuple-variadic.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive-unit-auto-trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/primitive.rs (100%) rename tests/{rustdoc => rustdoc-html}/primitive/search-index-primitive-inherent-method-23511.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-both.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-neither.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/doc-hidden-private-67851-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-impl-block-private-with-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-impl-block-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/empty-mod-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/enum-variant-private-46767.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/files-creation-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/hidden-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/inline-private-with-intermediate-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/inner-private-110422.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-document-private-duplicate.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-document-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/macro-private-not-documented.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/missing-private-inlining-109258.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-fields-tuple-struct.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-non-local-fields-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-non-local-fields.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-type-alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-type-cycle-110629.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-use-decl-macro-47038.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/private-use.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/public-impl-mention-private-generic-46380-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/private/traits-in-bodies-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/process-termination.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-use-loop-107350.rs (100%) rename tests/{rustdoc => rustdoc-html}/pub-use-root-path-95873.rs (100%) rename tests/{rustdoc => rustdoc-html}/range-arg-pattern.rs (100%) rename tests/{rustdoc => rustdoc-html}/raw-ident-eliminate-r-hashtag.rs (100%) rename tests/{rustdoc => rustdoc-html}/read-more-unneeded.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion1.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion2.rs (100%) rename tests/{rustdoc => rustdoc-html}/recursion3.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-map-empty.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-map.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect-rename.rs (100%) rename tests/{rustdoc => rustdoc-html}/redirect.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/alias-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/alias-reexport2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/anonymous-reexport-108931.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/anonymous-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/alias-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/alias-reexport2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/all-item-types.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/issue-28927-1.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/issue-28927-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/primitive-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexport-check.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexport-doc-aux.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/auxiliary/wrap-unnamable-type.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/blanket-reexport-item.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/cfg_doc_reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/doc-hidden-reexports-109449.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/duplicated-glob-reexport-60522.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/enum-variant-reexport-35488.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/enum-variant.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/extern-135092.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/foreigntype-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/glob-reexport-attribute-merge-120487.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/ice-reexport-crate-root-28927.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/import_trait_associated_functions.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/local-reexport-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/merge-glob-and-non-glob.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/no-compiler-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/overlapping-reexport-105735-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/overlapping-reexport-105735.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/primitive-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/private-mod-override-reexport.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/pub-reexport-of-pub-reexport-46506.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-attr-merge.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-cfg.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-check.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-dep-foreign-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc-hidden-inside-private.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-hidden-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-of-doc-hidden.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-of-reexport-108679.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-stability-tags-deprecated-and-portability.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-stability-tags-unstable-and-portability.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-trait-from-hidden-111064-2.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexport-trait-from-hidden-111064.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports-of-same-name.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports-priv.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/reexports.rs (100%) rename tests/{rustdoc => rustdoc-html}/reexport/wrapped-unnamble-type-143222.rs (100%) rename tests/{rustdoc => rustdoc-html}/remove-duplicates.rs (100%) rename tests/{rustdoc => rustdoc-html}/remove-url-from-headings.rs (100%) rename tests/{rustdoc => rustdoc-html}/repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/resolve-ice-124363.rs (100%) rename tests/{rustdoc => rustdoc-html}/return-type-notation.rs (100%) rename tests/{rustdoc => rustdoc-html}/safe-intrinsic.rs (100%) rename tests/{rustdoc => rustdoc-html}/sanitizer-option.rs (100%) rename tests/{rustdoc => rustdoc-html}/search-index-summaries.rs (100%) rename tests/{rustdoc => rustdoc-html}/search-index.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-docblock-codeblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-docblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/short-line.md (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/module.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-all-page.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-items.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-link-generation.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/sidebar-links-to-foreign-impl.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-html.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-idmap.rs (100%) rename tests/{rustdoc => rustdoc-html}/sidebar/top-toc-nil.rs (100%) rename tests/{rustdoc => rustdoc-html}/sized_trait.rs (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_box_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_box_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_slice_generic.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.link_slice_u32.html (100%) rename tests/{rustdoc => rustdoc-html}/slice-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/smart-punct.rs (100%) rename tests/{rustdoc => rustdoc-html}/smoke.rs (100%) rename tests/{rustdoc => rustdoc-html}/sort-53812.rs (100%) rename tests/{rustdoc => rustdoc-html}/sort-modules-by-appearance.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/assoc-type-source-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/issue-26606-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/issue-34274.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/source-code-bar.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/source_code.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/auxiliary/src-links-external.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/check-source-code-urls-to-def-std.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/check-source-code-urls-to-def.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/doc-hidden-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/failing-expansion-on-wrong-macro.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/frontmatter.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/html-no-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/keyword-macros.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/shebang.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-code-highlight.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-file.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-line-numbers.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/source-version-separator.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-link-external-macro-26606.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-auto-impls.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-external.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-implementor-43893.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links-inlined-34274.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/compiletest-ignore-dir (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/fizz.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-links/mod.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/src-mod-path-absolute-26995.rs (100%) rename tests/{rustdoc => rustdoc-html}/source-code-pages/version-separator-without-source.rs (100%) rename tests/{rustdoc => rustdoc-html}/stability.rs (100%) rename tests/{rustdoc => rustdoc-html}/staged-api-deprecated-unstable-32374.rs (100%) rename tests/{rustdoc => rustdoc-html}/staged-api-feature-issue-27759.rs (100%) rename tests/{rustdoc => rustdoc-html}/static-root-path.rs (100%) rename tests/{rustdoc => rustdoc-html}/static.rs (100%) rename tests/{rustdoc => rustdoc-html}/strip-block-doc-comments-stars.docblock.html (100%) rename tests/{rustdoc => rustdoc-html}/strip-block-doc-comments-stars.rs (100%) rename tests/{rustdoc => rustdoc-html}/strip-priv-imports-pass-27104.rs (100%) rename tests/{rustdoc => rustdoc-html}/struct-arg-pattern.rs (100%) rename tests/{rustdoc => rustdoc-html}/struct-field.rs (100%) rename tests/{rustdoc => rustdoc-html}/structfields.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-codeblock-31899.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-header-46377.rs (100%) rename tests/{rustdoc => rustdoc-html}/summary-reference-link-30366.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/auto-trait-lifetimes-56822.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/basic.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/complex.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/crate-local.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/issue-72213-projection-lifetime.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/lifetimes.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/manual.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/negative.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/nested.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/no-redundancy.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/normalize-auto-trait-80233.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/overflow.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/project.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/self-referential.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/send-impl-conditional-60726.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/static-region.rs (100%) rename tests/{rustdoc => rustdoc-html}/synthetic_auto/supertrait-bounds.rs (100%) rename tests/{rustdoc => rustdoc-html}/tab_title.rs (100%) rename tests/{rustdoc => rustdoc-html}/table-in-docblock.rs (100%) rename tests/{rustdoc => rustdoc-html}/target-feature.rs (100%) rename tests/{rustdoc => rustdoc-html}/task-lists.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-lists.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-parens.rs (100%) rename tests/{rustdoc => rustdoc-html}/test-strikethrough.rs (100%) rename tests/{rustdoc => rustdoc-html}/test_option_check/bar.rs (100%) rename tests/{rustdoc => rustdoc-html}/test_option_check/test.rs (100%) rename tests/{rustdoc => rustdoc-html}/thread-local-src.rs (100%) rename tests/{rustdoc => rustdoc-html}/titles.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-item-contents.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-method.rs (100%) rename tests/{rustdoc => rustdoc-html}/toggle-trait-fn.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-aliases.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-item-info.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-self-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-src-link.rs (100%) rename tests/{rustdoc => rustdoc-html}/trait-visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/traits-in-bodies.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuple-struct-fields-doc.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuple-struct-where-clause-34928.rs (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link1_i32.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link1_t.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_i32.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_t.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link2_tu.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.link_unit.html (100%) rename tests/{rustdoc => rustdoc-html}/tuples.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/auxiliary/parent-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/cross-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/deeply-nested-112515.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/deref-32077.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/impl_trait_in_assoc_type.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/primitive-local-link-121106.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/repr.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-alias/same-crate-115718.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-layout-flag-required.rs (100%) rename tests/{rustdoc => rustdoc-html}/type-layout.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef-inner-variants-lazy_type_alias.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef-inner-variants.rs (100%) rename tests/{rustdoc => rustdoc-html}/typedef.rs (100%) rename tests/{rustdoc => rustdoc-html}/underscore-import-61592.rs (100%) rename tests/{rustdoc => rustdoc-html}/unindent.md (100%) rename tests/{rustdoc => rustdoc-html}/unindent.rs (100%) rename tests/{rustdoc => rustdoc-html}/union-fields-html.rs (100%) rename tests/{rustdoc => rustdoc-html}/union.rs (100%) rename tests/{rustdoc => rustdoc-html}/unit-return.rs (100%) rename tests/{rustdoc => rustdoc-html}/unsafe-binder.rs (100%) rename tests/{rustdoc => rustdoc-html}/use-attr.rs (100%) rename tests/{rustdoc => rustdoc-html}/useless_lifetime_bound.rs (100%) rename tests/{rustdoc => rustdoc-html}/variadic.rs (100%) rename tests/{rustdoc => rustdoc-html}/viewpath-rename.rs (100%) rename tests/{rustdoc => rustdoc-html}/viewpath-self.rs (100%) rename tests/{rustdoc => rustdoc-html}/visibility.rs (100%) rename tests/{rustdoc => rustdoc-html}/where-clause-order.rs (100%) rename tests/{rustdoc => rustdoc-html}/where-sized.rs (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_Echo_impl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_Simd_item-decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.SWhere_TraitWhere_item-decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.alpha_trait_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.bravo_trait_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.charlie_fn_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.golf_type_alias_decl.html (100%) rename tests/{rustdoc => rustdoc-html}/where.rs (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.enum.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.enum2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.rs (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.struct.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.struct2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.trait.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.trait2.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.union.html (100%) rename tests/{rustdoc => rustdoc-html}/whitespace-after-where-clause.union2.html (100%) rename tests/{rustdoc => rustdoc-html}/without-redirect.rs (100%) rename tests/{rustdoc => rustdoc-html}/wrapping.rs (100%) diff --git a/rustfmt.toml b/rustfmt.toml index 6172a2bb3bf9..910eea103798 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -21,7 +21,7 @@ ignore = [ "/tests/pretty/", # These tests are very sensitive to source code layout. "/tests/run-make/export", # These tests contain syntax errors. "/tests/run-make/translation/test.rs", # This test contains syntax errors. - "/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive. + "/tests/rustdoc-html/", # Some have syntax errors, some are whitespace-sensitive. "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. "/tests/ui/", # Some have syntax errors, some are whitespace-sensitive. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a3c13fc4b095..b26df1586e71 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1582,10 +1582,10 @@ test!(UiFullDeps { IS_HOST: true, }); -test!(Rustdoc { - path: "tests/rustdoc", - mode: CompiletestMode::Rustdoc, - suite: "rustdoc", +test!(RustdocHtml { + path: "tests/rustdoc-html", + mode: CompiletestMode::RustdocHtml, + suite: "rustdoc-html", default: true, IS_HOST: true, }); @@ -1969,7 +1969,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the if matches!( mode, CompiletestMode::RunMake - | CompiletestMode::Rustdoc + | CompiletestMode::RustdocHtml | CompiletestMode::RustdocJs | CompiletestMode::RustdocJson ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc") @@ -2758,7 +2758,7 @@ impl Step for ErrorIndex { fn make_run(run: RunConfig<'_>) { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest - // tests in tests/rustdoc) so that it shares the same artifacts. + // tests in tests/rustdoc-html) so that it shares the same artifacts. let compilers = RustcPrivateCompilers::new( run.builder, run.builder.top_stage, @@ -3159,7 +3159,7 @@ impl Step for CrateRustdoc { builder.compiler(builder.top_stage, target) } else { // Use the previous stage compiler to reuse the artifacts that are - // created when running compiletest for tests/rustdoc. If this used + // created when running compiletest for tests/rustdoc-html. If this used // `compiler`, then it would cause rustdoc to be built *again*, which // isn't really necessary. builder.compiler_for(builder.top_stage, target, target) diff --git a/src/bootstrap/src/core/build_steps/test/compiletest.rs b/src/bootstrap/src/core/build_steps/test/compiletest.rs index 359f6bb1a6ef..230ed75a0868 100644 --- a/src/bootstrap/src/core/build_steps/test/compiletest.rs +++ b/src/bootstrap/src/core/build_steps/test/compiletest.rs @@ -21,7 +21,7 @@ pub(crate) enum CompiletestMode { MirOpt, Pretty, RunMake, - Rustdoc, + RustdocHtml, RustdocJs, RustdocJson, Ui, @@ -49,7 +49,7 @@ impl CompiletestMode { Self::MirOpt => "mir-opt", Self::Pretty => "pretty", Self::RunMake => "run-make", - Self::Rustdoc => "rustdoc", + Self::RustdocHtml => "rustdoc-html", Self::RustdocJs => "rustdoc-js", Self::RustdocJson => "rustdoc-json", Self::Ui => "ui", diff --git a/src/bootstrap/src/core/builder/cli_paths.rs b/src/bootstrap/src/core/builder/cli_paths.rs index 470e83d341c7..5ff2b380e4b9 100644 --- a/src/bootstrap/src/core/builder/cli_paths.rs +++ b/src/bootstrap/src/core/builder/cli_paths.rs @@ -31,8 +31,8 @@ pub(crate) const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/pretty", "tests/run-make", "tests/run-make-cargo", - "tests/rustdoc", "tests/rustdoc-gui", + "tests/rustdoc-html", "tests/rustdoc-js", "tests/rustdoc-js-std", "tests/rustdoc-json", diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index fd18b59a9c6d..4ab84c3cabc1 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -1,6 +1,5 @@ --- source: src/bootstrap/src/core/builder/cli_paths/tests.rs -assertion_line: 68 expression: test --- [Test] test::Tidy @@ -38,9 +37,9 @@ expression: test [Test] test::UiFullDeps targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/ui-fulldeps) -[Test] test::Rustdoc +[Test] test::RustdocHtml targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) + - Suite(test::tests/rustdoc-html) [Test] test::CoverageRunRustdoc targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/coverage-run-rustdoc) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap index 6522a7e8edaf..c8eee72aec42 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap @@ -5,9 +5,6 @@ expression: test librustdoc rustdoc [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - Set({test::src/librustdoc, test::src/tools/rustdoc}) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocBook targets: [x86_64-unknown-linux-gnu] - Set({test::src/doc/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap new file mode 100644 index 000000000000..21acc1e46069 --- /dev/null +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc_html.snap @@ -0,0 +1,10 @@ +--- +source: src/bootstrap/src/core/builder/cli_paths/tests.rs +expression: test librustdoc rustdoc-html +--- +[Test] test::CrateRustdoc + targets: [x86_64-unknown-linux-gnu] + - Set({test::src/librustdoc}) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap index 337ad33fe35f..897372dcd1c7 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc.snap @@ -2,9 +2,6 @@ source: src/bootstrap/src/core/builder/cli_paths/tests.rs expression: test rustdoc --- -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - Set({test::src/tools/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap new file mode 100644 index 000000000000..a6a2a27c075e --- /dev/null +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_rustdoc_html.snap @@ -0,0 +1,7 @@ +--- +source: src/bootstrap/src/core/builder/cli_paths/tests.rs +expression: test rustdoc-html +--- +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index 171680515476..2a4805e4fd68 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -1,6 +1,5 @@ --- source: src/bootstrap/src/core/builder/cli_paths/tests.rs -assertion_line: 68 expression: test --skip=coverage --- [Test] test::Tidy @@ -37,9 +36,9 @@ expression: test --skip=coverage [Test] test::UiFullDeps targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/ui-fulldeps) -[Test] test::Rustdoc +[Test] test::RustdocHtml targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) + - Suite(test::tests/rustdoc-html) [Test] test::CoverageRunRustdoc targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/coverage-run-rustdoc) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap index b38af13d49c3..ad9660ef5c91 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests.snap @@ -38,12 +38,12 @@ expression: test tests [Test] test::RunMakeCargo targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/run-make-cargo) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocGUI targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-gui) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) [Test] test::RustdocJSNotStd targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-js) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap index 6a158ea62bb3..4572f089b0ae 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_tests_skip_coverage.snap @@ -35,12 +35,12 @@ expression: test tests --skip=coverage [Test] test::RunMakeCargo targets: [aarch64-unknown-linux-gnu] - Suite(test::tests/run-make-cargo) -[Test] test::Rustdoc - targets: [x86_64-unknown-linux-gnu] - - Suite(test::tests/rustdoc) [Test] test::RustdocGUI targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-gui) +[Test] test::RustdocHtml + targets: [x86_64-unknown-linux-gnu] + - Suite(test::tests/rustdoc-html) [Test] test::RustdocJSNotStd targets: [x86_64-unknown-linux-gnu] - Suite(test::tests/rustdoc-js) diff --git a/src/bootstrap/src/core/builder/cli_paths/tests.rs b/src/bootstrap/src/core/builder/cli_paths/tests.rs index 49f75c8bea77..39293abd4fb9 100644 --- a/src/bootstrap/src/core/builder/cli_paths/tests.rs +++ b/src/bootstrap/src/core/builder/cli_paths/tests.rs @@ -169,7 +169,9 @@ declare_tests!( (x_test_library, "test library"), (x_test_librustdoc, "test librustdoc"), (x_test_librustdoc_rustdoc, "test librustdoc rustdoc"), + (x_test_librustdoc_rustdoc_html, "test librustdoc rustdoc-html"), (x_test_rustdoc, "test rustdoc"), + (x_test_rustdoc_html, "test rustdoc-html"), (x_test_skip_coverage, "test --skip=coverage"), // FIXME(Zalathar): This doesn't skip the coverage-map or coverage-run tests. (x_test_skip_tests, "test --skip=tests"), diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 92a6eb8ce837..9e1a65bca79d 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -880,7 +880,7 @@ impl<'a> Builder<'a> { test::Incremental, test::Debuginfo, test::UiFullDeps, - test::Rustdoc, + test::RustdocHtml, test::CoverageRunRustdoc, test::Pretty, test::CodegenCranelift, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 9146c470e358..66614cc6cced 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2099,7 +2099,7 @@ mod snapshot { [test] compiletest-debuginfo 1 [test] compiletest-ui-fulldeps 1 [build] rustdoc 1 - [test] compiletest-rustdoc 1 + [test] compiletest-rustdoc-html 1 [test] compiletest-coverage-run-rustdoc 1 [test] compiletest-pretty 1 [build] rustc 1 -> std 1 @@ -2169,7 +2169,7 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc", "rustdoc-gui", "incremental"]) + .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) .render_steps(), @r" [build] llvm [build] rustc 0 -> rustc 1 @@ -2180,11 +2180,10 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 1 [test] compiletest-run-make 1 - [test] compiletest-rustdoc 1 + [test] compiletest-rustdoc-html 1 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 1 [test] compiletest-incremental 1 - [build] rustc 1 -> rustc 2 "); } @@ -2193,7 +2192,7 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("test") - .args(&["ui", "ui-fulldeps", "run-make", "rustdoc", "rustdoc-gui", "incremental"]) + .args(&["ui", "ui-fulldeps", "run-make", "rustdoc-html", "rustdoc-gui", "incremental"]) .stage(2) .render_steps(), @r" [build] llvm @@ -2208,11 +2207,10 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 2 [test] compiletest-run-make 2 - [test] compiletest-rustdoc 2 + [test] compiletest-rustdoc-html 2 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 2 [test] compiletest-incremental 2 - [build] rustdoc 1 "); } @@ -2241,12 +2239,11 @@ mod snapshot { [build] rustc 0 -> RunMakeSupport 1 [build] rustdoc 2 [test] compiletest-run-make 2 - [test] compiletest-rustdoc 2 + [build] rustc 1 -> rustc 2 + [build] rustdoc 1 [build] rustc 0 -> RustdocGUITest 1 [test] rustdoc-gui 2 [test] compiletest-incremental 2 - [build] rustc 1 -> rustc 2 - [build] rustdoc 1 [build] rustc 2 -> std 2 [build] rustdoc 2 "); @@ -2283,7 +2280,7 @@ mod snapshot { [build] rustc 2 -> rustc 3 [test] compiletest-ui-fulldeps 2 [build] rustdoc 2 - [test] compiletest-rustdoc 2 + [test] compiletest-rustdoc-html 2 [test] compiletest-coverage-run-rustdoc 2 [test] compiletest-pretty 2 [build] rustc 2 -> std 2 diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index 512c80628574..e26104905491 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc-html -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile index 0fd14ae232d7..f9c1ea531add 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile @@ -45,7 +45,7 @@ ENV SCRIPT python3 ../x.py \ --test-codegen-backend gcc \ --skip tests/coverage \ --skip tests/coverage-run-rustdoc \ - --skip tests/rustdoc \ + --skip tests/rustdoc-html \ --skip tests/rustdoc-gui \ --skip tests/rustdoc-js \ --skip tests/rustdoc-js-std \ diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e0a37c95257c..af97ae93a2b9 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -882,7 +882,8 @@ impl<'item> DocVisitor<'item> for TypeImplCollector<'_, '_, 'item> { // // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this // to use type unification. - // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. + // Be aware of `tests/rustdoc-html/type-alias/deeply-nested-112515.rs` which might + // regress. let Some(impl_did) = impl_item_id.as_def_id() else { continue }; let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); let reject_cx = DeepRejectCtxt::relate_infer_infer(self.cx.tcx()); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5563abe92a80..450fde3bbc38 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -18,7 +18,7 @@ string_enum! { Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", - Rustdoc => "rustdoc", + RustdocHtml => "rustdoc-html", RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", @@ -69,7 +69,7 @@ string_enum! { Pretty => "pretty", RunMake => "run-make", RunMakeCargo => "run-make-cargo", - Rustdoc => "rustdoc", + RustdocHtml => "rustdoc-html", RustdocGui => "rustdoc-gui", RustdocJs => "rustdoc-js", RustdocJsStd=> "rustdoc-js-std", diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 5865954558d8..624f4dd7c2b1 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -552,7 +552,7 @@ fn check_directive<'a>( let is_known_directive = KNOWN_DIRECTIVE_NAMES_SET.contains(&directive_name) || match mode { - TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name), + TestMode::RustdocHtml => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name), TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES.contains(&directive_name), _ => false, }; diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 0d3777b8e60c..2dc878fa2a20 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -630,7 +630,7 @@ fn test_forbidden_revisions_allowed_in_non_filecheck_dir() { let modes = [ "pretty", "debuginfo", - "rustdoc", + "rustdoc-html", "rustdoc-json", "codegen-units", "incremental", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a64c7850aad4..c219a8887f8f 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -85,7 +85,7 @@ fn parse_config(args: Vec) -> Config { "", "mode", "which sort of compile tests to run", - "pretty | debug-info | codegen | rustdoc \ + "pretty | debug-info | codegen | rustdoc-html \ | rustdoc-json | codegen-units | incremental | run-make | ui \ | rustdoc-js | mir-opt | assembly | crashes", ) @@ -1094,8 +1094,8 @@ fn make_test_name_and_filterable_path( /// of some other tests's name. /// /// For example, suppose the test suite contains these two test files: -/// - `tests/rustdoc/primitive.rs` -/// - `tests/rustdoc/primitive/no_std.rs` +/// - `tests/rustdoc-html/primitive.rs` +/// - `tests/rustdoc-html/primitive/no_std.rs` /// /// The test runner might put the output from those tests in these directories: /// - `$build/test/rustdoc/primitive/` diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1216ba888328..6efdb5a99ee2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -269,7 +269,7 @@ impl<'test> TestCx<'test> { TestMode::Pretty => self.run_pretty_test(), TestMode::DebugInfo => self.run_debuginfo_test(), TestMode::Codegen => self.run_codegen_test(), - TestMode::Rustdoc => self.run_rustdoc_test(), + TestMode::RustdocHtml => self.run_rustdoc_html_test(), TestMode::RustdocJson => self.run_rustdoc_json_test(), TestMode::CodegenUnits => self.run_codegen_units_test(), TestMode::Incremental => self.run_incremental_test(), @@ -1758,7 +1758,7 @@ impl<'test> TestCx<'test> { } TestMode::Pretty | TestMode::DebugInfo - | TestMode::Rustdoc + | TestMode::RustdocHtml | TestMode::RustdocJson | TestMode::RunMake | TestMode::RustdocJs => { diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index 3c80521e51ec..8907848e0ca5 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -3,7 +3,7 @@ use std::process::Command; use super::{DocKind, TestCx, remove_and_create_dir_all}; impl TestCx<'_> { - pub(super) fn run_rustdoc_test(&self) { + pub(super) fn run_rustdoc_html_test(&self) { assert!(self.revision.is_none(), "revisions not supported in this test suite"); let out_dir = self.output_base_dir(); diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index 4454ffb1f59e..bacc8061d209 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -50,7 +50,7 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { // // For instance, `//@ ignore-stage1` will not work at all. Config { - mode: TestMode::Rustdoc, + mode: TestMode::RustdocHtml, // E.g. this has no sensible default tbh. suite: TestSuite::Ui, diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 29168b25f7f6..1aacfeaf538e 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -123,7 +123,7 @@ llvm-config = "{llvm_config}" "tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist", "tests/ui", "tests/crashes", - "tests/rustdoc", + "tests/rustdoc-html", ]; for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 08061bd834e3..43e6c18382af 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -107,7 +107,7 @@ pub fn check( &tests_path.join("ui"), &tests_path.join("ui-fulldeps"), &tests_path.join("rustdoc-ui"), - &tests_path.join("rustdoc"), + &tests_path.join("rustdoc-html"), ], |path, _is_dir| { filter_dirs(path) diff --git a/tests/rustdoc/all.rs b/tests/rustdoc-html/all.rs similarity index 100% rename from tests/rustdoc/all.rs rename to tests/rustdoc-html/all.rs diff --git a/tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc-html/anchors/anchor-id-duplicate-method-name-25001.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs rename to tests/rustdoc-html/anchors/anchor-id-duplicate-method-name-25001.rs diff --git a/tests/rustdoc/anchors/anchor-id-trait-method-15169.rs b/tests/rustdoc-html/anchors/anchor-id-trait-method-15169.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-trait-method-15169.rs rename to tests/rustdoc-html/anchors/anchor-id-trait-method-15169.rs diff --git a/tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs b/tests/rustdoc-html/anchors/anchor-id-trait-tymethod-28478.rs similarity index 100% rename from tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs rename to tests/rustdoc-html/anchors/anchor-id-trait-tymethod-28478.rs diff --git a/tests/rustdoc/anchors/anchors.no_const_anchor.html b/tests/rustdoc-html/anchors/anchors.no_const_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_const_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_const_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_const_anchor2.html b/tests/rustdoc-html/anchors/anchors.no_const_anchor2.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_const_anchor2.html rename to tests/rustdoc-html/anchors/anchors.no_const_anchor2.html diff --git a/tests/rustdoc/anchors/anchors.no_method_anchor.html b/tests/rustdoc-html/anchors/anchors.no_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_method_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_method_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_trait_method_anchor.html b/tests/rustdoc-html/anchors/anchors.no_trait_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_trait_method_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_trait_method_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_tymethod_anchor.html b/tests/rustdoc-html/anchors/anchors.no_tymethod_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_tymethod_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_tymethod_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_type_anchor.html b/tests/rustdoc-html/anchors/anchors.no_type_anchor.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_type_anchor.html rename to tests/rustdoc-html/anchors/anchors.no_type_anchor.html diff --git a/tests/rustdoc/anchors/anchors.no_type_anchor2.html b/tests/rustdoc-html/anchors/anchors.no_type_anchor2.html similarity index 100% rename from tests/rustdoc/anchors/anchors.no_type_anchor2.html rename to tests/rustdoc-html/anchors/anchors.no_type_anchor2.html diff --git a/tests/rustdoc/anchors/anchors.rs b/tests/rustdoc-html/anchors/anchors.rs similarity index 100% rename from tests/rustdoc/anchors/anchors.rs rename to tests/rustdoc-html/anchors/anchors.rs diff --git a/tests/rustdoc/anchors/auxiliary/issue-86620-1.rs b/tests/rustdoc-html/anchors/auxiliary/issue-86620-1.rs similarity index 100% rename from tests/rustdoc/anchors/auxiliary/issue-86620-1.rs rename to tests/rustdoc-html/anchors/auxiliary/issue-86620-1.rs diff --git a/tests/rustdoc/anchors/disambiguate-anchors-32890.rs b/tests/rustdoc-html/anchors/disambiguate-anchors-32890.rs similarity index 100% rename from tests/rustdoc/anchors/disambiguate-anchors-32890.rs rename to tests/rustdoc-html/anchors/disambiguate-anchors-32890.rs diff --git a/tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs b/tests/rustdoc-html/anchors/disambiguate-anchors-header-29449.rs similarity index 100% rename from tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs rename to tests/rustdoc-html/anchors/disambiguate-anchors-header-29449.rs diff --git a/tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs b/tests/rustdoc-html/anchors/method-anchor-in-blanket-impl-86620.rs similarity index 100% rename from tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs rename to tests/rustdoc-html/anchors/method-anchor-in-blanket-impl-86620.rs diff --git a/tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs b/tests/rustdoc-html/anchors/trait-impl-items-links-and-anchors.rs similarity index 100% rename from tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs rename to tests/rustdoc-html/anchors/trait-impl-items-links-and-anchors.rs diff --git a/tests/rustdoc/anon-fn-params.rs b/tests/rustdoc-html/anon-fn-params.rs similarity index 100% rename from tests/rustdoc/anon-fn-params.rs rename to tests/rustdoc-html/anon-fn-params.rs diff --git a/tests/rustdoc/anonymous-lifetime.rs b/tests/rustdoc-html/anonymous-lifetime.rs similarity index 100% rename from tests/rustdoc/anonymous-lifetime.rs rename to tests/rustdoc-html/anonymous-lifetime.rs diff --git a/tests/rustdoc/array-links.link_box_generic.html b/tests/rustdoc-html/array-links.link_box_generic.html similarity index 100% rename from tests/rustdoc/array-links.link_box_generic.html rename to tests/rustdoc-html/array-links.link_box_generic.html diff --git a/tests/rustdoc/array-links.link_box_u32.html b/tests/rustdoc-html/array-links.link_box_u32.html similarity index 100% rename from tests/rustdoc/array-links.link_box_u32.html rename to tests/rustdoc-html/array-links.link_box_u32.html diff --git a/tests/rustdoc/array-links.link_slice_generic.html b/tests/rustdoc-html/array-links.link_slice_generic.html similarity index 100% rename from tests/rustdoc/array-links.link_slice_generic.html rename to tests/rustdoc-html/array-links.link_slice_generic.html diff --git a/tests/rustdoc/array-links.link_slice_u32.html b/tests/rustdoc-html/array-links.link_slice_u32.html similarity index 100% rename from tests/rustdoc/array-links.link_slice_u32.html rename to tests/rustdoc-html/array-links.link_slice_u32.html diff --git a/tests/rustdoc/array-links.rs b/tests/rustdoc-html/array-links.rs similarity index 100% rename from tests/rustdoc/array-links.rs rename to tests/rustdoc-html/array-links.rs diff --git a/tests/rustdoc/asm-foreign.rs b/tests/rustdoc-html/asm-foreign.rs similarity index 100% rename from tests/rustdoc/asm-foreign.rs rename to tests/rustdoc-html/asm-foreign.rs diff --git a/tests/rustdoc/asm-foreign2.rs b/tests/rustdoc-html/asm-foreign2.rs similarity index 100% rename from tests/rustdoc/asm-foreign2.rs rename to tests/rustdoc-html/asm-foreign2.rs diff --git a/tests/rustdoc/asref-for-and-of-local-82465.rs b/tests/rustdoc-html/asref-for-and-of-local-82465.rs similarity index 100% rename from tests/rustdoc/asref-for-and-of-local-82465.rs rename to tests/rustdoc-html/asref-for-and-of-local-82465.rs diff --git a/tests/rustdoc/assoc/assoc-fns.rs b/tests/rustdoc-html/assoc/assoc-fns.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-fns.rs rename to tests/rustdoc-html/assoc/assoc-fns.rs diff --git a/tests/rustdoc/assoc/assoc-item-cast.rs b/tests/rustdoc-html/assoc/assoc-item-cast.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-item-cast.rs rename to tests/rustdoc-html/assoc/assoc-item-cast.rs diff --git a/tests/rustdoc/assoc/assoc-type-bindings-20646.rs b/tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-type-bindings-20646.rs rename to tests/rustdoc-html/assoc/assoc-type-bindings-20646.rs diff --git a/tests/rustdoc/assoc/assoc-types.rs b/tests/rustdoc-html/assoc/assoc-types.rs similarity index 100% rename from tests/rustdoc/assoc/assoc-types.rs rename to tests/rustdoc-html/assoc/assoc-types.rs diff --git a/tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc-html/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc-html/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/assoc/auxiliary/issue-20646.rs b/tests/rustdoc-html/assoc/auxiliary/issue-20646.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/issue-20646.rs rename to tests/rustdoc-html/assoc/auxiliary/issue-20646.rs diff --git a/tests/rustdoc/assoc/auxiliary/issue-20727.rs b/tests/rustdoc-html/assoc/auxiliary/issue-20727.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/issue-20727.rs rename to tests/rustdoc-html/assoc/auxiliary/issue-20727.rs diff --git a/tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs b/tests/rustdoc-html/assoc/auxiliary/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs rename to tests/rustdoc-html/assoc/auxiliary/normalize-assoc-item.rs diff --git a/tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc-html/assoc/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc-html/assoc/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/assoc/doc-assoc-item.rs b/tests/rustdoc-html/assoc/doc-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/doc-assoc-item.rs rename to tests/rustdoc-html/assoc/doc-assoc-item.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bindings.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bindings.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-deref.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-deref.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-index.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds-index.rs diff --git a/tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs b/tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds.rs similarity index 100% rename from tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs rename to tests/rustdoc-html/assoc/inline-assoc-type-20727-bounds.rs diff --git a/tests/rustdoc/assoc/normalize-assoc-item.rs b/tests/rustdoc-html/assoc/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/assoc/normalize-assoc-item.rs rename to tests/rustdoc-html/assoc/normalize-assoc-item.rs diff --git a/tests/rustdoc/async/async-fn-opaque-item.rs b/tests/rustdoc-html/async/async-fn-opaque-item.rs similarity index 100% rename from tests/rustdoc/async/async-fn-opaque-item.rs rename to tests/rustdoc-html/async/async-fn-opaque-item.rs diff --git a/tests/rustdoc/async/async-fn.rs b/tests/rustdoc-html/async/async-fn.rs similarity index 100% rename from tests/rustdoc/async/async-fn.rs rename to tests/rustdoc-html/async/async-fn.rs diff --git a/tests/rustdoc/async/async-move-doctest.rs b/tests/rustdoc-html/async/async-move-doctest.rs similarity index 100% rename from tests/rustdoc/async/async-move-doctest.rs rename to tests/rustdoc-html/async/async-move-doctest.rs diff --git a/tests/rustdoc/async/async-trait-sig.rs b/tests/rustdoc-html/async/async-trait-sig.rs similarity index 100% rename from tests/rustdoc/async/async-trait-sig.rs rename to tests/rustdoc-html/async/async-trait-sig.rs diff --git a/tests/rustdoc/async/async-trait.rs b/tests/rustdoc-html/async/async-trait.rs similarity index 100% rename from tests/rustdoc/async/async-trait.rs rename to tests/rustdoc-html/async/async-trait.rs diff --git a/tests/rustdoc/async/auxiliary/async-trait-dep.rs b/tests/rustdoc-html/async/auxiliary/async-trait-dep.rs similarity index 100% rename from tests/rustdoc/async/auxiliary/async-trait-dep.rs rename to tests/rustdoc-html/async/auxiliary/async-trait-dep.rs diff --git a/tests/rustdoc/attributes-2021-edition.rs b/tests/rustdoc-html/attributes-2021-edition.rs similarity index 100% rename from tests/rustdoc/attributes-2021-edition.rs rename to tests/rustdoc-html/attributes-2021-edition.rs diff --git a/tests/rustdoc/attributes-inlining-108281.rs b/tests/rustdoc-html/attributes-inlining-108281.rs similarity index 100% rename from tests/rustdoc/attributes-inlining-108281.rs rename to tests/rustdoc-html/attributes-inlining-108281.rs diff --git a/tests/rustdoc/attributes-re-export-2021-edition.rs b/tests/rustdoc-html/attributes-re-export-2021-edition.rs similarity index 100% rename from tests/rustdoc/attributes-re-export-2021-edition.rs rename to tests/rustdoc-html/attributes-re-export-2021-edition.rs diff --git a/tests/rustdoc/attributes-re-export.rs b/tests/rustdoc-html/attributes-re-export.rs similarity index 100% rename from tests/rustdoc/attributes-re-export.rs rename to tests/rustdoc-html/attributes-re-export.rs diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc-html/attributes.rs similarity index 100% rename from tests/rustdoc/attributes.rs rename to tests/rustdoc-html/attributes.rs diff --git a/tests/rustdoc/auto/auto-impl-for-trait.rs b/tests/rustdoc-html/auto/auto-impl-for-trait.rs similarity index 100% rename from tests/rustdoc/auto/auto-impl-for-trait.rs rename to tests/rustdoc-html/auto/auto-impl-for-trait.rs diff --git a/tests/rustdoc/auto/auto-impl-primitive.rs b/tests/rustdoc-html/auto/auto-impl-primitive.rs similarity index 100% rename from tests/rustdoc/auto/auto-impl-primitive.rs rename to tests/rustdoc-html/auto/auto-impl-primitive.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs b/tests/rustdoc-html/auto/auto-trait-bounds-by-associated-type-50159.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-by-associated-type-50159.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs b/tests/rustdoc-html/auto/auto-trait-bounds-inference-variables-54705.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-inference-variables-54705.rs diff --git a/tests/rustdoc/auto/auto-trait-bounds-where-51236.rs b/tests/rustdoc-html/auto/auto-trait-bounds-where-51236.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-bounds-where-51236.rs rename to tests/rustdoc-html/auto/auto-trait-bounds-where-51236.rs diff --git a/tests/rustdoc/auto/auto-trait-negative-impl-55321.rs b/tests/rustdoc-html/auto/auto-trait-negative-impl-55321.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-negative-impl-55321.rs rename to tests/rustdoc-html/auto/auto-trait-negative-impl-55321.rs diff --git a/tests/rustdoc/auto/auto-trait-not-send.rs b/tests/rustdoc-html/auto/auto-trait-not-send.rs similarity index 100% rename from tests/rustdoc/auto/auto-trait-not-send.rs rename to tests/rustdoc-html/auto/auto-trait-not-send.rs diff --git a/tests/rustdoc/auto/auto-traits.rs b/tests/rustdoc-html/auto/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto/auto-traits.rs rename to tests/rustdoc-html/auto/auto-traits.rs diff --git a/tests/rustdoc/auto/auto_aliases.rs b/tests/rustdoc-html/auto/auto_aliases.rs similarity index 100% rename from tests/rustdoc/auto/auto_aliases.rs rename to tests/rustdoc-html/auto/auto_aliases.rs diff --git a/tests/rustdoc/auto/auxiliary/auto-traits.rs b/tests/rustdoc-html/auto/auxiliary/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto/auxiliary/auto-traits.rs rename to tests/rustdoc-html/auto/auxiliary/auto-traits.rs diff --git a/tests/rustdoc/auxiliary/all-item-types.rs b/tests/rustdoc-html/auxiliary/all-item-types.rs similarity index 100% rename from tests/rustdoc/auxiliary/all-item-types.rs rename to tests/rustdoc-html/auxiliary/all-item-types.rs diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs rename to tests/rustdoc-html/auxiliary/cross_crate_generic_typedef.rs diff --git a/tests/rustdoc/auxiliary/elided-lifetime.rs b/tests/rustdoc-html/auxiliary/elided-lifetime.rs similarity index 100% rename from tests/rustdoc/auxiliary/elided-lifetime.rs rename to tests/rustdoc-html/auxiliary/elided-lifetime.rs diff --git a/tests/rustdoc/auxiliary/empty.rs b/tests/rustdoc-html/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/auxiliary/empty.rs rename to tests/rustdoc-html/auxiliary/empty.rs diff --git a/tests/rustdoc/auxiliary/enum-primitive.rs b/tests/rustdoc-html/auxiliary/enum-primitive.rs similarity index 100% rename from tests/rustdoc/auxiliary/enum-primitive.rs rename to tests/rustdoc-html/auxiliary/enum-primitive.rs diff --git a/tests/rustdoc/auxiliary/ext-anon-fn-params.rs b/tests/rustdoc-html/auxiliary/ext-anon-fn-params.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-anon-fn-params.rs rename to tests/rustdoc-html/auxiliary/ext-anon-fn-params.rs diff --git a/tests/rustdoc/auxiliary/ext-repr.rs b/tests/rustdoc-html/auxiliary/ext-repr.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-repr.rs rename to tests/rustdoc-html/auxiliary/ext-repr.rs diff --git a/tests/rustdoc/auxiliary/ext-trait-aliases.rs b/tests/rustdoc-html/auxiliary/ext-trait-aliases.rs similarity index 100% rename from tests/rustdoc/auxiliary/ext-trait-aliases.rs rename to tests/rustdoc-html/auxiliary/ext-trait-aliases.rs diff --git a/tests/rustdoc/auxiliary/inline-default-methods.rs b/tests/rustdoc-html/auxiliary/inline-default-methods.rs similarity index 100% rename from tests/rustdoc/auxiliary/inline-default-methods.rs rename to tests/rustdoc-html/auxiliary/inline-default-methods.rs diff --git a/tests/rustdoc/auxiliary/issue-106421-force-unstable.rs b/tests/rustdoc-html/auxiliary/issue-106421-force-unstable.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-106421-force-unstable.rs rename to tests/rustdoc-html/auxiliary/issue-106421-force-unstable.rs diff --git a/tests/rustdoc/auxiliary/issue-13698.rs b/tests/rustdoc-html/auxiliary/issue-13698.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-13698.rs rename to tests/rustdoc-html/auxiliary/issue-13698.rs diff --git a/tests/rustdoc/auxiliary/issue-19190-3.rs b/tests/rustdoc-html/auxiliary/issue-19190-3.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-19190-3.rs rename to tests/rustdoc-html/auxiliary/issue-19190-3.rs diff --git a/tests/rustdoc/auxiliary/issue-61592.rs b/tests/rustdoc-html/auxiliary/issue-61592.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-61592.rs rename to tests/rustdoc-html/auxiliary/issue-61592.rs diff --git a/tests/rustdoc/auxiliary/issue-99221-aux.rs b/tests/rustdoc-html/auxiliary/issue-99221-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-99221-aux.rs rename to tests/rustdoc-html/auxiliary/issue-99221-aux.rs diff --git a/tests/rustdoc/auxiliary/issue-99734-aux.rs b/tests/rustdoc-html/auxiliary/issue-99734-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-99734-aux.rs rename to tests/rustdoc-html/auxiliary/issue-99734-aux.rs diff --git a/tests/rustdoc/auxiliary/jump-to-def-res-err-handling-aux.rs b/tests/rustdoc-html/auxiliary/jump-to-def-res-err-handling-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/jump-to-def-res-err-handling-aux.rs rename to tests/rustdoc-html/auxiliary/jump-to-def-res-err-handling-aux.rs diff --git a/tests/rustdoc/auxiliary/masked.rs b/tests/rustdoc-html/auxiliary/masked.rs similarity index 100% rename from tests/rustdoc/auxiliary/masked.rs rename to tests/rustdoc-html/auxiliary/masked.rs diff --git a/tests/rustdoc/auxiliary/mod-stackoverflow.rs b/tests/rustdoc-html/auxiliary/mod-stackoverflow.rs similarity index 100% rename from tests/rustdoc/auxiliary/mod-stackoverflow.rs rename to tests/rustdoc-html/auxiliary/mod-stackoverflow.rs diff --git a/tests/rustdoc/auxiliary/reexp-stripped.rs b/tests/rustdoc-html/auxiliary/reexp-stripped.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexp-stripped.rs rename to tests/rustdoc-html/auxiliary/reexp-stripped.rs diff --git a/tests/rustdoc/auxiliary/remapped-paths.rs b/tests/rustdoc-html/auxiliary/remapped-paths.rs similarity index 100% rename from tests/rustdoc/auxiliary/remapped-paths.rs rename to tests/rustdoc-html/auxiliary/remapped-paths.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-ffi.rs b/tests/rustdoc-html/auxiliary/rustdoc-ffi.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-ffi.rs rename to tests/rustdoc-html/auxiliary/rustdoc-ffi.rs diff --git a/tests/rustdoc/auxiliary/trait-visibility.rs b/tests/rustdoc-html/auxiliary/trait-visibility.rs similarity index 100% rename from tests/rustdoc/auxiliary/trait-visibility.rs rename to tests/rustdoc-html/auxiliary/trait-visibility.rs diff --git a/tests/rustdoc/auxiliary/unit-return.rs b/tests/rustdoc-html/auxiliary/unit-return.rs similarity index 100% rename from tests/rustdoc/auxiliary/unit-return.rs rename to tests/rustdoc-html/auxiliary/unit-return.rs diff --git a/tests/rustdoc/auxiliary/unsafe-binder-dep.rs b/tests/rustdoc-html/auxiliary/unsafe-binder-dep.rs similarity index 100% rename from tests/rustdoc/auxiliary/unsafe-binder-dep.rs rename to tests/rustdoc-html/auxiliary/unsafe-binder-dep.rs diff --git a/tests/rustdoc/auxiliary/unstable-trait.rs b/tests/rustdoc-html/auxiliary/unstable-trait.rs similarity index 100% rename from tests/rustdoc/auxiliary/unstable-trait.rs rename to tests/rustdoc-html/auxiliary/unstable-trait.rs diff --git a/tests/rustdoc/bad-codeblock-syntax.rs b/tests/rustdoc-html/bad-codeblock-syntax.rs similarity index 100% rename from tests/rustdoc/bad-codeblock-syntax.rs rename to tests/rustdoc-html/bad-codeblock-syntax.rs diff --git a/tests/rustdoc/blank-line-in-doc-block-47197.rs b/tests/rustdoc-html/blank-line-in-doc-block-47197.rs similarity index 100% rename from tests/rustdoc/blank-line-in-doc-block-47197.rs rename to tests/rustdoc-html/blank-line-in-doc-block-47197.rs diff --git a/tests/rustdoc/bold-tag-101743.rs b/tests/rustdoc-html/bold-tag-101743.rs similarity index 100% rename from tests/rustdoc/bold-tag-101743.rs rename to tests/rustdoc-html/bold-tag-101743.rs diff --git a/tests/rustdoc/bounds.rs b/tests/rustdoc-html/bounds.rs similarity index 100% rename from tests/rustdoc/bounds.rs rename to tests/rustdoc-html/bounds.rs diff --git a/tests/rustdoc/cap-lints.rs b/tests/rustdoc-html/cap-lints.rs similarity index 100% rename from tests/rustdoc/cap-lints.rs rename to tests/rustdoc-html/cap-lints.rs diff --git a/tests/rustdoc/cfg-bool.rs b/tests/rustdoc-html/cfg-bool.rs similarity index 100% rename from tests/rustdoc/cfg-bool.rs rename to tests/rustdoc-html/cfg-bool.rs diff --git a/tests/rustdoc/cfg-doctest.rs b/tests/rustdoc-html/cfg-doctest.rs similarity index 100% rename from tests/rustdoc/cfg-doctest.rs rename to tests/rustdoc-html/cfg-doctest.rs diff --git a/tests/rustdoc/check-styled-link.rs b/tests/rustdoc-html/check-styled-link.rs similarity index 100% rename from tests/rustdoc/check-styled-link.rs rename to tests/rustdoc-html/check-styled-link.rs diff --git a/tests/rustdoc/check.rs b/tests/rustdoc-html/check.rs similarity index 100% rename from tests/rustdoc/check.rs rename to tests/rustdoc-html/check.rs diff --git a/tests/rustdoc/codeblock-title.rs b/tests/rustdoc-html/codeblock-title.rs similarity index 100% rename from tests/rustdoc/codeblock-title.rs rename to tests/rustdoc-html/codeblock-title.rs diff --git a/tests/rustdoc/comment-in-doctest.rs b/tests/rustdoc-html/comment-in-doctest.rs similarity index 100% rename from tests/rustdoc/comment-in-doctest.rs rename to tests/rustdoc-html/comment-in-doctest.rs diff --git a/tests/rustdoc/const-fn-76501.rs b/tests/rustdoc-html/const-fn-76501.rs similarity index 100% rename from tests/rustdoc/const-fn-76501.rs rename to tests/rustdoc-html/const-fn-76501.rs diff --git a/tests/rustdoc/const-fn-effects.rs b/tests/rustdoc-html/const-fn-effects.rs similarity index 100% rename from tests/rustdoc/const-fn-effects.rs rename to tests/rustdoc-html/const-fn-effects.rs diff --git a/tests/rustdoc/const-fn.rs b/tests/rustdoc-html/const-fn.rs similarity index 100% rename from tests/rustdoc/const-fn.rs rename to tests/rustdoc-html/const-fn.rs diff --git a/tests/rustdoc/const-generics/add-impl.rs b/tests/rustdoc-html/const-generics/add-impl.rs similarity index 100% rename from tests/rustdoc/const-generics/add-impl.rs rename to tests/rustdoc-html/const-generics/add-impl.rs diff --git a/tests/rustdoc/const-generics/auxiliary/extern_crate.rs b/tests/rustdoc-html/const-generics/auxiliary/extern_crate.rs similarity index 100% rename from tests/rustdoc/const-generics/auxiliary/extern_crate.rs rename to tests/rustdoc-html/const-generics/auxiliary/extern_crate.rs diff --git a/tests/rustdoc/const-generics/const-generic-defaults.rs b/tests/rustdoc-html/const-generics/const-generic-defaults.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generic-defaults.rs rename to tests/rustdoc-html/const-generics/const-generic-defaults.rs diff --git a/tests/rustdoc/const-generics/const-generic-slice.rs b/tests/rustdoc-html/const-generics/const-generic-slice.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generic-slice.rs rename to tests/rustdoc-html/const-generics/const-generic-slice.rs diff --git a/tests/rustdoc/const-generics/const-generics-docs.rs b/tests/rustdoc-html/const-generics/const-generics-docs.rs similarity index 100% rename from tests/rustdoc/const-generics/const-generics-docs.rs rename to tests/rustdoc-html/const-generics/const-generics-docs.rs diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc-html/const-generics/const-impl.rs similarity index 100% rename from tests/rustdoc/const-generics/const-impl.rs rename to tests/rustdoc-html/const-generics/const-impl.rs diff --git a/tests/rustdoc/const-generics/const-param-type-references-generics.rs b/tests/rustdoc-html/const-generics/const-param-type-references-generics.rs similarity index 100% rename from tests/rustdoc/const-generics/const-param-type-references-generics.rs rename to tests/rustdoc-html/const-generics/const-param-type-references-generics.rs diff --git a/tests/rustdoc/const-generics/generic_const_exprs.rs b/tests/rustdoc-html/const-generics/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/const-generics/generic_const_exprs.rs rename to tests/rustdoc-html/const-generics/generic_const_exprs.rs diff --git a/tests/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs b/tests/rustdoc-html/const-generics/lazy_normalization_consts/const-equate-pred.rs similarity index 100% rename from tests/rustdoc/const-generics/lazy_normalization_consts/const-equate-pred.rs rename to tests/rustdoc-html/const-generics/lazy_normalization_consts/const-equate-pred.rs diff --git a/tests/rustdoc/const-generics/type-alias.rs b/tests/rustdoc-html/const-generics/type-alias.rs similarity index 100% rename from tests/rustdoc/const-generics/type-alias.rs rename to tests/rustdoc-html/const-generics/type-alias.rs diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc-html/const-intrinsic.rs similarity index 100% rename from tests/rustdoc/const-intrinsic.rs rename to tests/rustdoc-html/const-intrinsic.rs diff --git a/tests/rustdoc/constant/assoc-consts-underscore.rs b/tests/rustdoc-html/constant/assoc-consts-underscore.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts-underscore.rs rename to tests/rustdoc-html/constant/assoc-consts-underscore.rs diff --git a/tests/rustdoc/constant/assoc-consts-version.rs b/tests/rustdoc-html/constant/assoc-consts-version.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts-version.rs rename to tests/rustdoc-html/constant/assoc-consts-version.rs diff --git a/tests/rustdoc/constant/assoc-consts.rs b/tests/rustdoc-html/constant/assoc-consts.rs similarity index 100% rename from tests/rustdoc/constant/assoc-consts.rs rename to tests/rustdoc-html/constant/assoc-consts.rs diff --git a/tests/rustdoc/constant/associated-consts.rs b/tests/rustdoc-html/constant/associated-consts.rs similarity index 100% rename from tests/rustdoc/constant/associated-consts.rs rename to tests/rustdoc-html/constant/associated-consts.rs diff --git a/tests/rustdoc/constant/const-display.rs b/tests/rustdoc-html/constant/const-display.rs similarity index 100% rename from tests/rustdoc/constant/const-display.rs rename to tests/rustdoc-html/constant/const-display.rs diff --git a/tests/rustdoc/constant/const-doc.rs b/tests/rustdoc-html/constant/const-doc.rs similarity index 100% rename from tests/rustdoc/constant/const-doc.rs rename to tests/rustdoc-html/constant/const-doc.rs diff --git a/tests/rustdoc/constant/const-effect-param.rs b/tests/rustdoc-html/constant/const-effect-param.rs similarity index 100% rename from tests/rustdoc/constant/const-effect-param.rs rename to tests/rustdoc-html/constant/const-effect-param.rs diff --git a/tests/rustdoc/constant/const-trait-and-impl-methods.rs b/tests/rustdoc-html/constant/const-trait-and-impl-methods.rs similarity index 100% rename from tests/rustdoc/constant/const-trait-and-impl-methods.rs rename to tests/rustdoc-html/constant/const-trait-and-impl-methods.rs diff --git a/tests/rustdoc/constant/const-underscore.rs b/tests/rustdoc-html/constant/const-underscore.rs similarity index 100% rename from tests/rustdoc/constant/const-underscore.rs rename to tests/rustdoc-html/constant/const-underscore.rs diff --git a/tests/rustdoc/constant/const-value-display.rs b/tests/rustdoc-html/constant/const-value-display.rs similarity index 100% rename from tests/rustdoc/constant/const-value-display.rs rename to tests/rustdoc-html/constant/const-value-display.rs diff --git a/tests/rustdoc/constant/const.rs b/tests/rustdoc-html/constant/const.rs similarity index 100% rename from tests/rustdoc/constant/const.rs rename to tests/rustdoc-html/constant/const.rs diff --git a/tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs b/tests/rustdoc-html/constant/document-item-with-associated-const-in-where-clause.rs similarity index 100% rename from tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs rename to tests/rustdoc-html/constant/document-item-with-associated-const-in-where-clause.rs diff --git a/tests/rustdoc/constant/generic-const-items.rs b/tests/rustdoc-html/constant/generic-const-items.rs similarity index 100% rename from tests/rustdoc/constant/generic-const-items.rs rename to tests/rustdoc-html/constant/generic-const-items.rs diff --git a/tests/rustdoc/constant/generic_const_exprs.rs b/tests/rustdoc-html/constant/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/constant/generic_const_exprs.rs rename to tests/rustdoc-html/constant/generic_const_exprs.rs diff --git a/tests/rustdoc/constant/glob-shadowing-const.rs b/tests/rustdoc-html/constant/glob-shadowing-const.rs similarity index 100% rename from tests/rustdoc/constant/glob-shadowing-const.rs rename to tests/rustdoc-html/constant/glob-shadowing-const.rs diff --git a/tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs b/tests/rustdoc-html/constant/hide-complex-unevaluated-const-arguments.rs similarity index 100% rename from tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs rename to tests/rustdoc-html/constant/hide-complex-unevaluated-const-arguments.rs diff --git a/tests/rustdoc/constant/hide-complex-unevaluated-consts.rs b/tests/rustdoc-html/constant/hide-complex-unevaluated-consts.rs similarity index 100% rename from tests/rustdoc/constant/hide-complex-unevaluated-consts.rs rename to tests/rustdoc-html/constant/hide-complex-unevaluated-consts.rs diff --git a/tests/rustdoc/constant/ice-associated-const-equality-105952.rs b/tests/rustdoc-html/constant/ice-associated-const-equality-105952.rs similarity index 100% rename from tests/rustdoc/constant/ice-associated-const-equality-105952.rs rename to tests/rustdoc-html/constant/ice-associated-const-equality-105952.rs diff --git a/tests/rustdoc/constant/legacy-const-generic.rs b/tests/rustdoc-html/constant/legacy-const-generic.rs similarity index 100% rename from tests/rustdoc/constant/legacy-const-generic.rs rename to tests/rustdoc-html/constant/legacy-const-generic.rs diff --git a/tests/rustdoc/constant/link-assoc-const.rs b/tests/rustdoc-html/constant/link-assoc-const.rs similarity index 100% rename from tests/rustdoc/constant/link-assoc-const.rs rename to tests/rustdoc-html/constant/link-assoc-const.rs diff --git a/tests/rustdoc/constant/redirect-const.rs b/tests/rustdoc-html/constant/redirect-const.rs similarity index 100% rename from tests/rustdoc/constant/redirect-const.rs rename to tests/rustdoc-html/constant/redirect-const.rs diff --git a/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs b/tests/rustdoc-html/constant/rfc-2632-const-trait-impl.rs similarity index 100% rename from tests/rustdoc/constant/rfc-2632-const-trait-impl.rs rename to tests/rustdoc-html/constant/rfc-2632-const-trait-impl.rs diff --git a/tests/rustdoc/constant/show-const-contents.rs b/tests/rustdoc-html/constant/show-const-contents.rs similarity index 100% rename from tests/rustdoc/constant/show-const-contents.rs rename to tests/rustdoc-html/constant/show-const-contents.rs diff --git a/tests/rustdoc/constructor-imports.rs b/tests/rustdoc-html/constructor-imports.rs similarity index 100% rename from tests/rustdoc/constructor-imports.rs rename to tests/rustdoc-html/constructor-imports.rs diff --git a/tests/rustdoc/crate-doc-hidden-109695.rs b/tests/rustdoc-html/crate-doc-hidden-109695.rs similarity index 100% rename from tests/rustdoc/crate-doc-hidden-109695.rs rename to tests/rustdoc-html/crate-doc-hidden-109695.rs diff --git a/tests/rustdoc/crate-version-escape.rs b/tests/rustdoc-html/crate-version-escape.rs similarity index 100% rename from tests/rustdoc/crate-version-escape.rs rename to tests/rustdoc-html/crate-version-escape.rs diff --git a/tests/rustdoc/crate-version-extra.rs b/tests/rustdoc-html/crate-version-extra.rs similarity index 100% rename from tests/rustdoc/crate-version-extra.rs rename to tests/rustdoc-html/crate-version-extra.rs diff --git a/tests/rustdoc/crate-version.rs b/tests/rustdoc-html/crate-version.rs similarity index 100% rename from tests/rustdoc/crate-version.rs rename to tests/rustdoc-html/crate-version.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive-no-index/s.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive-no-index/s.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-transitive/s.rs b/tests/rustdoc-html/cross-crate-info/cargo-transitive/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-transitive/s.rs rename to tests/rustdoc-html/cross-crate-info/cargo-transitive/s.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/cargo-two-no-index/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two-no-index/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two-no-index/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs b/tests/rustdoc-html/cross-crate-info/cargo-two-no-index/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two-no-index/e.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two-no-index/e.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/cargo-two/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/cargo-two/e.rs b/tests/rustdoc-html/cross-crate-info/cargo-two/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/cargo-two/e.rs rename to tests/rustdoc-html/cross-crate-info/cargo-two/e.rs diff --git a/tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/index-on-last/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/index-on-last/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/index-on-last/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/index-on-last/e.rs b/tests/rustdoc-html/cross-crate-info/index-on-last/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/index-on-last/e.rs rename to tests/rustdoc-html/cross-crate-info/index-on-last/e.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/r.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/r.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/r.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/s.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/s.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/kitchen-sink/i.rs b/tests/rustdoc-html/cross-crate-info/kitchen-sink/i.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/kitchen-sink/i.rs rename to tests/rustdoc-html/cross-crate-info/kitchen-sink/i.rs diff --git a/tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs b/tests/rustdoc-html/cross-crate-info/single-crate-baseline/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/single-crate-baseline/q.rs rename to tests/rustdoc-html/cross-crate-info/single-crate-baseline/q.rs diff --git a/tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs b/tests/rustdoc-html/cross-crate-info/single-crate-no-index/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/single-crate-no-index/q.rs rename to tests/rustdoc-html/cross-crate-info/single-crate-no-index/q.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs b/tests/rustdoc-html/cross-crate-info/transitive/auxiliary/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/auxiliary/q.rs rename to tests/rustdoc-html/cross-crate-info/transitive/auxiliary/q.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs b/tests/rustdoc-html/cross-crate-info/transitive/auxiliary/t.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/auxiliary/t.rs rename to tests/rustdoc-html/cross-crate-info/transitive/auxiliary/t.rs diff --git a/tests/rustdoc/cross-crate-info/transitive/s.rs b/tests/rustdoc-html/cross-crate-info/transitive/s.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/transitive/s.rs rename to tests/rustdoc-html/cross-crate-info/transitive/s.rs diff --git a/tests/rustdoc/cross-crate-info/two/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/two/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/two/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/two/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/two/e.rs b/tests/rustdoc-html/cross-crate-info/two/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/two/e.rs rename to tests/rustdoc-html/cross-crate-info/two/e.rs diff --git a/tests/rustdoc/cross-crate-info/working-dir-examples/q.rs b/tests/rustdoc-html/cross-crate-info/working-dir-examples/q.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/working-dir-examples/q.rs rename to tests/rustdoc-html/cross-crate-info/working-dir-examples/q.rs diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs b/tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs rename to tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/auxiliary/f.rs diff --git a/tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs b/tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/e.rs similarity index 100% rename from tests/rustdoc/cross-crate-info/write-docs-somewhere-else/e.rs rename to tests/rustdoc-html/cross-crate-info/write-docs-somewhere-else/e.rs diff --git a/tests/rustdoc/cross-crate-links.rs b/tests/rustdoc-html/cross-crate-links.rs similarity index 100% rename from tests/rustdoc/cross-crate-links.rs rename to tests/rustdoc-html/cross-crate-links.rs diff --git a/tests/rustdoc/custom_code_classes.rs b/tests/rustdoc-html/custom_code_classes.rs similarity index 100% rename from tests/rustdoc/custom_code_classes.rs rename to tests/rustdoc-html/custom_code_classes.rs diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html b/tests/rustdoc-html/decl-line-wrapping-empty-arg-list.decl.html similarity index 100% rename from tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html rename to tests/rustdoc-html/decl-line-wrapping-empty-arg-list.decl.html diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.rs b/tests/rustdoc-html/decl-line-wrapping-empty-arg-list.rs similarity index 100% rename from tests/rustdoc/decl-line-wrapping-empty-arg-list.rs rename to tests/rustdoc-html/decl-line-wrapping-empty-arg-list.rs diff --git a/tests/rustdoc/decl-trailing-whitespace.declaration.html b/tests/rustdoc-html/decl-trailing-whitespace.declaration.html similarity index 100% rename from tests/rustdoc/decl-trailing-whitespace.declaration.html rename to tests/rustdoc-html/decl-trailing-whitespace.declaration.html diff --git a/tests/rustdoc/decl-trailing-whitespace.rs b/tests/rustdoc-html/decl-trailing-whitespace.rs similarity index 100% rename from tests/rustdoc/decl-trailing-whitespace.rs rename to tests/rustdoc-html/decl-trailing-whitespace.rs diff --git a/tests/rustdoc/deep-structures.rs b/tests/rustdoc-html/deep-structures.rs similarity index 100% rename from tests/rustdoc/deep-structures.rs rename to tests/rustdoc-html/deep-structures.rs diff --git a/tests/rustdoc/default-theme.rs b/tests/rustdoc-html/default-theme.rs similarity index 100% rename from tests/rustdoc/default-theme.rs rename to tests/rustdoc-html/default-theme.rs diff --git a/tests/rustdoc/default-trait-method-link.rs b/tests/rustdoc-html/default-trait-method-link.rs similarity index 100% rename from tests/rustdoc/default-trait-method-link.rs rename to tests/rustdoc-html/default-trait-method-link.rs diff --git a/tests/rustdoc/default-trait-method.rs b/tests/rustdoc-html/default-trait-method.rs similarity index 100% rename from tests/rustdoc/default-trait-method.rs rename to tests/rustdoc-html/default-trait-method.rs diff --git a/tests/rustdoc/demo-allocator-54478.rs b/tests/rustdoc-html/demo-allocator-54478.rs similarity index 100% rename from tests/rustdoc/demo-allocator-54478.rs rename to tests/rustdoc-html/demo-allocator-54478.rs diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc-html/deprecated-future-staged-api.rs similarity index 100% rename from tests/rustdoc/deprecated-future-staged-api.rs rename to tests/rustdoc-html/deprecated-future-staged-api.rs diff --git a/tests/rustdoc/deprecated-future.rs b/tests/rustdoc-html/deprecated-future.rs similarity index 100% rename from tests/rustdoc/deprecated-future.rs rename to tests/rustdoc-html/deprecated-future.rs diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc-html/deprecated.rs similarity index 100% rename from tests/rustdoc/deprecated.rs rename to tests/rustdoc-html/deprecated.rs diff --git a/tests/rustdoc/deref-methods-19190-foreign-type.rs b/tests/rustdoc-html/deref-methods-19190-foreign-type.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190-foreign-type.rs rename to tests/rustdoc-html/deref-methods-19190-foreign-type.rs diff --git a/tests/rustdoc/deref-methods-19190-inline.rs b/tests/rustdoc-html/deref-methods-19190-inline.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190-inline.rs rename to tests/rustdoc-html/deref-methods-19190-inline.rs diff --git a/tests/rustdoc/deref-methods-19190.rs b/tests/rustdoc-html/deref-methods-19190.rs similarity index 100% rename from tests/rustdoc/deref-methods-19190.rs rename to tests/rustdoc-html/deref-methods-19190.rs diff --git a/tests/rustdoc/deref-mut-35169-2.rs b/tests/rustdoc-html/deref-mut-35169-2.rs similarity index 100% rename from tests/rustdoc/deref-mut-35169-2.rs rename to tests/rustdoc-html/deref-mut-35169-2.rs diff --git a/tests/rustdoc/deref-mut-35169.rs b/tests/rustdoc-html/deref-mut-35169.rs similarity index 100% rename from tests/rustdoc/deref-mut-35169.rs rename to tests/rustdoc-html/deref-mut-35169.rs diff --git a/tests/rustdoc/deref/deref-const-fn.rs b/tests/rustdoc-html/deref/deref-const-fn.rs similarity index 100% rename from tests/rustdoc/deref/deref-const-fn.rs rename to tests/rustdoc-html/deref/deref-const-fn.rs diff --git a/tests/rustdoc/deref/deref-methods-24686-target.rs b/tests/rustdoc-html/deref/deref-methods-24686-target.rs similarity index 100% rename from tests/rustdoc/deref/deref-methods-24686-target.rs rename to tests/rustdoc-html/deref/deref-methods-24686-target.rs diff --git a/tests/rustdoc/deref/deref-multiple-impl-blocks.rs b/tests/rustdoc-html/deref/deref-multiple-impl-blocks.rs similarity index 100% rename from tests/rustdoc/deref/deref-multiple-impl-blocks.rs rename to tests/rustdoc-html/deref/deref-multiple-impl-blocks.rs diff --git a/tests/rustdoc/deref/deref-mut-methods.rs b/tests/rustdoc-html/deref/deref-mut-methods.rs similarity index 100% rename from tests/rustdoc/deref/deref-mut-methods.rs rename to tests/rustdoc-html/deref/deref-mut-methods.rs diff --git a/tests/rustdoc/deref/deref-recursive-pathbuf.rs b/tests/rustdoc-html/deref/deref-recursive-pathbuf.rs similarity index 100% rename from tests/rustdoc/deref/deref-recursive-pathbuf.rs rename to tests/rustdoc-html/deref/deref-recursive-pathbuf.rs diff --git a/tests/rustdoc/deref/deref-recursive.rs b/tests/rustdoc-html/deref/deref-recursive.rs similarity index 100% rename from tests/rustdoc/deref/deref-recursive.rs rename to tests/rustdoc-html/deref/deref-recursive.rs diff --git a/tests/rustdoc/deref/deref-slice-core.rs b/tests/rustdoc-html/deref/deref-slice-core.rs similarity index 100% rename from tests/rustdoc/deref/deref-slice-core.rs rename to tests/rustdoc-html/deref/deref-slice-core.rs diff --git a/tests/rustdoc/deref/deref-to-primitive.rs b/tests/rustdoc-html/deref/deref-to-primitive.rs similarity index 100% rename from tests/rustdoc/deref/deref-to-primitive.rs rename to tests/rustdoc-html/deref/deref-to-primitive.rs diff --git a/tests/rustdoc/deref/deref-typedef.rs b/tests/rustdoc-html/deref/deref-typedef.rs similarity index 100% rename from tests/rustdoc/deref/deref-typedef.rs rename to tests/rustdoc-html/deref/deref-typedef.rs diff --git a/tests/rustdoc/deref/escape-deref-methods.rs b/tests/rustdoc-html/deref/escape-deref-methods.rs similarity index 100% rename from tests/rustdoc/deref/escape-deref-methods.rs rename to tests/rustdoc-html/deref/escape-deref-methods.rs diff --git a/tests/rustdoc/deref/recursive-deref-sidebar.rs b/tests/rustdoc-html/deref/recursive-deref-sidebar.rs similarity index 100% rename from tests/rustdoc/deref/recursive-deref-sidebar.rs rename to tests/rustdoc-html/deref/recursive-deref-sidebar.rs diff --git a/tests/rustdoc/deref/recursive-deref.rs b/tests/rustdoc-html/deref/recursive-deref.rs similarity index 100% rename from tests/rustdoc/deref/recursive-deref.rs rename to tests/rustdoc-html/deref/recursive-deref.rs diff --git a/tests/rustdoc/deref/sidebar-links-deref-100679.rs b/tests/rustdoc-html/deref/sidebar-links-deref-100679.rs similarity index 100% rename from tests/rustdoc/deref/sidebar-links-deref-100679.rs rename to tests/rustdoc-html/deref/sidebar-links-deref-100679.rs diff --git a/tests/rustdoc/description.rs b/tests/rustdoc-html/description.rs similarity index 100% rename from tests/rustdoc/description.rs rename to tests/rustdoc-html/description.rs diff --git a/tests/rustdoc/description_default.rs b/tests/rustdoc-html/description_default.rs similarity index 100% rename from tests/rustdoc/description_default.rs rename to tests/rustdoc-html/description_default.rs diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc-html/display-hidden-items.rs similarity index 100% rename from tests/rustdoc/display-hidden-items.rs rename to tests/rustdoc-html/display-hidden-items.rs diff --git a/tests/rustdoc/doc-attr-comment-mix-42760.rs b/tests/rustdoc-html/doc-attr-comment-mix-42760.rs similarity index 100% rename from tests/rustdoc/doc-attr-comment-mix-42760.rs rename to tests/rustdoc-html/doc-attr-comment-mix-42760.rs diff --git a/tests/rustdoc/doc-attribute.rs b/tests/rustdoc-html/doc-attribute.rs similarity index 100% rename from tests/rustdoc/doc-attribute.rs rename to tests/rustdoc-html/doc-attribute.rs diff --git a/tests/rustdoc/doc-auto-cfg-public-in-private.rs b/tests/rustdoc-html/doc-auto-cfg-public-in-private.rs similarity index 100% rename from tests/rustdoc/doc-auto-cfg-public-in-private.rs rename to tests/rustdoc-html/doc-auto-cfg-public-in-private.rs diff --git a/tests/rustdoc/doc-auto-cfg.rs b/tests/rustdoc-html/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/doc-auto-cfg.rs rename to tests/rustdoc-html/doc-auto-cfg.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-hide.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-hide.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-hide.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-hide.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-implicit-gate.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-implicit-gate.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-implicit.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-implicit.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-implicit.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-inherit-from-module-79201.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-inherit-from-module-79201.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-simplification.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-simplification.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-simplification.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-simplification.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg-traits.rs b/tests/rustdoc-html/doc-cfg/doc-cfg-traits.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg-traits.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg-traits.rs diff --git a/tests/rustdoc/doc-cfg/doc-cfg.rs b/tests/rustdoc-html/doc-cfg/doc-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg/doc-cfg.rs rename to tests/rustdoc-html/doc-cfg/doc-cfg.rs diff --git a/tests/rustdoc/doc-cfg/duplicate-cfg.rs b/tests/rustdoc-html/doc-cfg/duplicate-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg/duplicate-cfg.rs rename to tests/rustdoc-html/doc-cfg/duplicate-cfg.rs diff --git a/tests/rustdoc/doc-hidden-crate.rs b/tests/rustdoc-html/doc-hidden-crate.rs similarity index 100% rename from tests/rustdoc/doc-hidden-crate.rs rename to tests/rustdoc-html/doc-hidden-crate.rs diff --git a/tests/rustdoc/doc-hidden-method-13698.rs b/tests/rustdoc-html/doc-hidden-method-13698.rs similarity index 100% rename from tests/rustdoc/doc-hidden-method-13698.rs rename to tests/rustdoc-html/doc-hidden-method-13698.rs diff --git a/tests/rustdoc/doc-on-keyword.rs b/tests/rustdoc-html/doc-on-keyword.rs similarity index 100% rename from tests/rustdoc/doc-on-keyword.rs rename to tests/rustdoc-html/doc-on-keyword.rs diff --git a/tests/rustdoc/doc-test-attr-18199.rs b/tests/rustdoc-html/doc-test-attr-18199.rs similarity index 100% rename from tests/rustdoc/doc-test-attr-18199.rs rename to tests/rustdoc-html/doc-test-attr-18199.rs diff --git a/tests/rustdoc/doc_auto_cfg.rs b/tests/rustdoc-html/doc_auto_cfg.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg.rs rename to tests/rustdoc-html/doc_auto_cfg.rs diff --git a/tests/rustdoc/doc_auto_cfg_reexports.rs b/tests/rustdoc-html/doc_auto_cfg_reexports.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg_reexports.rs rename to tests/rustdoc-html/doc_auto_cfg_reexports.rs diff --git a/tests/rustdoc/doctest/auxiliary/doctest-runtool.rs b/tests/rustdoc-html/doctest/auxiliary/doctest-runtool.rs similarity index 100% rename from tests/rustdoc/doctest/auxiliary/doctest-runtool.rs rename to tests/rustdoc-html/doctest/auxiliary/doctest-runtool.rs diff --git a/tests/rustdoc/doctest/auxiliary/empty.rs b/tests/rustdoc-html/doctest/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/doctest/auxiliary/empty.rs rename to tests/rustdoc-html/doctest/auxiliary/empty.rs diff --git a/tests/rustdoc/doctest/doctest-cfg-feature-30252.rs b/tests/rustdoc-html/doctest/doctest-cfg-feature-30252.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-cfg-feature-30252.rs rename to tests/rustdoc-html/doctest/doctest-cfg-feature-30252.rs diff --git a/tests/rustdoc/doctest/doctest-crate-attributes-38129.rs b/tests/rustdoc-html/doctest/doctest-crate-attributes-38129.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-crate-attributes-38129.rs rename to tests/rustdoc-html/doctest/doctest-crate-attributes-38129.rs diff --git a/tests/rustdoc/doctest/doctest-escape-boring-41783.codeblock.html b/tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html similarity index 100% rename from tests/rustdoc/doctest/doctest-escape-boring-41783.codeblock.html rename to tests/rustdoc-html/doctest/doctest-escape-boring-41783.codeblock.html diff --git a/tests/rustdoc/doctest/doctest-escape-boring-41783.rs b/tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-escape-boring-41783.rs rename to tests/rustdoc-html/doctest/doctest-escape-boring-41783.rs diff --git a/tests/rustdoc/doctest/doctest-hide-empty-line-23106.rs b/tests/rustdoc-html/doctest/doctest-hide-empty-line-23106.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-hide-empty-line-23106.rs rename to tests/rustdoc-html/doctest/doctest-hide-empty-line-23106.rs diff --git a/tests/rustdoc/doctest/doctest-ignore-32556.rs b/tests/rustdoc-html/doctest/doctest-ignore-32556.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-ignore-32556.rs rename to tests/rustdoc-html/doctest/doctest-ignore-32556.rs diff --git a/tests/rustdoc/doctest/doctest-include-43153.rs b/tests/rustdoc-html/doctest/doctest-include-43153.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-include-43153.rs rename to tests/rustdoc-html/doctest/doctest-include-43153.rs diff --git a/tests/rustdoc/doctest/doctest-macro-38219.rs b/tests/rustdoc-html/doctest/doctest-macro-38219.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-macro-38219.rs rename to tests/rustdoc-html/doctest/doctest-macro-38219.rs diff --git a/tests/rustdoc/doctest/doctest-manual-crate-name.rs b/tests/rustdoc-html/doctest/doctest-manual-crate-name.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-manual-crate-name.rs rename to tests/rustdoc-html/doctest/doctest-manual-crate-name.rs diff --git a/tests/rustdoc/doctest/doctest-markdown-inline-parse-23744.rs b/tests/rustdoc-html/doctest/doctest-markdown-inline-parse-23744.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-markdown-inline-parse-23744.rs rename to tests/rustdoc-html/doctest/doctest-markdown-inline-parse-23744.rs diff --git a/tests/rustdoc/doctest/doctest-markdown-trailing-docblock-48377.rs b/tests/rustdoc-html/doctest/doctest-markdown-trailing-docblock-48377.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-markdown-trailing-docblock-48377.rs rename to tests/rustdoc-html/doctest/doctest-markdown-trailing-docblock-48377.rs diff --git a/tests/rustdoc/doctest/doctest-multi-line-string-literal-25944.rs b/tests/rustdoc-html/doctest/doctest-multi-line-string-literal-25944.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-multi-line-string-literal-25944.rs rename to tests/rustdoc-html/doctest/doctest-multi-line-string-literal-25944.rs diff --git a/tests/rustdoc/doctest/doctest-runtool.rs b/tests/rustdoc-html/doctest/doctest-runtool.rs similarity index 100% rename from tests/rustdoc/doctest/doctest-runtool.rs rename to tests/rustdoc-html/doctest/doctest-runtool.rs diff --git a/tests/rustdoc/doctest/ignore-sometimes.rs b/tests/rustdoc-html/doctest/ignore-sometimes.rs similarity index 100% rename from tests/rustdoc/doctest/ignore-sometimes.rs rename to tests/rustdoc-html/doctest/ignore-sometimes.rs diff --git a/tests/rustdoc/document-hidden-items-15347.rs b/tests/rustdoc-html/document-hidden-items-15347.rs similarity index 100% rename from tests/rustdoc/document-hidden-items-15347.rs rename to tests/rustdoc-html/document-hidden-items-15347.rs diff --git a/tests/rustdoc/double-hyphen-to-dash.rs b/tests/rustdoc-html/double-hyphen-to-dash.rs similarity index 100% rename from tests/rustdoc/double-hyphen-to-dash.rs rename to tests/rustdoc-html/double-hyphen-to-dash.rs diff --git a/tests/rustdoc/double-quote-escape.rs b/tests/rustdoc-html/double-quote-escape.rs similarity index 100% rename from tests/rustdoc/double-quote-escape.rs rename to tests/rustdoc-html/double-quote-escape.rs diff --git a/tests/rustdoc/duplicate-flags.rs b/tests/rustdoc-html/duplicate-flags.rs similarity index 100% rename from tests/rustdoc/duplicate-flags.rs rename to tests/rustdoc-html/duplicate-flags.rs diff --git a/tests/rustdoc/duplicate_impls/impls.rs b/tests/rustdoc-html/duplicate_impls/impls.rs similarity index 100% rename from tests/rustdoc/duplicate_impls/impls.rs rename to tests/rustdoc-html/duplicate_impls/impls.rs diff --git a/tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs b/tests/rustdoc-html/duplicate_impls/sidebar-links-duplicate-impls-33054.rs similarity index 100% rename from tests/rustdoc/duplicate_impls/sidebar-links-duplicate-impls-33054.rs rename to tests/rustdoc-html/duplicate_impls/sidebar-links-duplicate-impls-33054.rs diff --git a/tests/rustdoc/dyn-compatibility.rs b/tests/rustdoc-html/dyn-compatibility.rs similarity index 100% rename from tests/rustdoc/dyn-compatibility.rs rename to tests/rustdoc-html/dyn-compatibility.rs diff --git a/tests/rustdoc/early-unindent.rs b/tests/rustdoc-html/early-unindent.rs similarity index 100% rename from tests/rustdoc/early-unindent.rs rename to tests/rustdoc-html/early-unindent.rs diff --git a/tests/rustdoc/edition-doctest.rs b/tests/rustdoc-html/edition-doctest.rs similarity index 100% rename from tests/rustdoc/edition-doctest.rs rename to tests/rustdoc-html/edition-doctest.rs diff --git a/tests/rustdoc/edition-flag.rs b/tests/rustdoc-html/edition-flag.rs similarity index 100% rename from tests/rustdoc/edition-flag.rs rename to tests/rustdoc-html/edition-flag.rs diff --git a/tests/rustdoc/elided-lifetime.rs b/tests/rustdoc-html/elided-lifetime.rs similarity index 100% rename from tests/rustdoc/elided-lifetime.rs rename to tests/rustdoc-html/elided-lifetime.rs diff --git a/tests/rustdoc/empty-doc-comment.rs b/tests/rustdoc-html/empty-doc-comment.rs similarity index 100% rename from tests/rustdoc/empty-doc-comment.rs rename to tests/rustdoc-html/empty-doc-comment.rs diff --git a/tests/rustdoc/empty-mod-public.rs b/tests/rustdoc-html/empty-mod-public.rs similarity index 100% rename from tests/rustdoc/empty-mod-public.rs rename to tests/rustdoc-html/empty-mod-public.rs diff --git a/tests/rustdoc/empty-section.rs b/tests/rustdoc-html/empty-section.rs similarity index 100% rename from tests/rustdoc/empty-section.rs rename to tests/rustdoc-html/empty-section.rs diff --git a/tests/rustdoc/empty-tuple-struct-118180.rs b/tests/rustdoc-html/empty-tuple-struct-118180.rs similarity index 100% rename from tests/rustdoc/empty-tuple-struct-118180.rs rename to tests/rustdoc-html/empty-tuple-struct-118180.rs diff --git a/tests/rustdoc/ensure-src-link.rs b/tests/rustdoc-html/ensure-src-link.rs similarity index 100% rename from tests/rustdoc/ensure-src-link.rs rename to tests/rustdoc-html/ensure-src-link.rs diff --git a/tests/rustdoc/enum/auxiliary/enum-variant.rs b/tests/rustdoc-html/enum/auxiliary/enum-variant.rs similarity index 100% rename from tests/rustdoc/enum/auxiliary/enum-variant.rs rename to tests/rustdoc-html/enum/auxiliary/enum-variant.rs diff --git a/tests/rustdoc/enum/auxiliary/variant-struct.rs b/tests/rustdoc-html/enum/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/enum/auxiliary/variant-struct.rs rename to tests/rustdoc-html/enum/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/enum/enum-headings.rs b/tests/rustdoc-html/enum/enum-headings.rs similarity index 100% rename from tests/rustdoc/enum/enum-headings.rs rename to tests/rustdoc-html/enum/enum-headings.rs diff --git a/tests/rustdoc/enum/enum-non-exhaustive-108925.rs b/tests/rustdoc-html/enum/enum-non-exhaustive-108925.rs similarity index 100% rename from tests/rustdoc/enum/enum-non-exhaustive-108925.rs rename to tests/rustdoc-html/enum/enum-non-exhaustive-108925.rs diff --git a/tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs b/tests/rustdoc-html/enum/enum-variant-doc-hidden-field-88600.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs rename to tests/rustdoc-html/enum/enum-variant-doc-hidden-field-88600.rs diff --git a/tests/rustdoc/enum/enum-variant-fields-heading.rs b/tests/rustdoc-html/enum/enum-variant-fields-heading.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-fields-heading.rs rename to tests/rustdoc-html/enum/enum-variant-fields-heading.rs diff --git a/tests/rustdoc/enum/enum-variant-fields-heading.variants.html b/tests/rustdoc-html/enum/enum-variant-fields-heading.variants.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-fields-heading.variants.html rename to tests/rustdoc-html/enum/enum-variant-fields-heading.variants.html diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.rs b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.rs rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.rs diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-alias-code.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.type-alias-code.html rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-alias-code.html diff --git a/tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html b/tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-code.html similarity index 100% rename from tests/rustdoc/enum/enum-variant-non_exhaustive.type-code.html rename to tests/rustdoc-html/enum/enum-variant-non_exhaustive.type-code.html diff --git a/tests/rustdoc/enum/enum-variant-value.rs b/tests/rustdoc-html/enum/enum-variant-value.rs similarity index 100% rename from tests/rustdoc/enum/enum-variant-value.rs rename to tests/rustdoc-html/enum/enum-variant-value.rs diff --git a/tests/rustdoc/enum/render-enum-variant-structlike-32395.rs b/tests/rustdoc-html/enum/render-enum-variant-structlike-32395.rs similarity index 100% rename from tests/rustdoc/enum/render-enum-variant-structlike-32395.rs rename to tests/rustdoc-html/enum/render-enum-variant-structlike-32395.rs diff --git a/tests/rustdoc/enum/strip-enum-variant.no-not-shown.html b/tests/rustdoc-html/enum/strip-enum-variant.no-not-shown.html similarity index 100% rename from tests/rustdoc/enum/strip-enum-variant.no-not-shown.html rename to tests/rustdoc-html/enum/strip-enum-variant.no-not-shown.html diff --git a/tests/rustdoc/enum/strip-enum-variant.rs b/tests/rustdoc-html/enum/strip-enum-variant.rs similarity index 100% rename from tests/rustdoc/enum/strip-enum-variant.rs rename to tests/rustdoc-html/enum/strip-enum-variant.rs diff --git a/tests/rustdoc/extern/auxiliary/empty.rs b/tests/rustdoc-html/extern/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/empty.rs rename to tests/rustdoc-html/extern/auxiliary/empty.rs diff --git a/tests/rustdoc/extern/auxiliary/extern-links.rs b/tests/rustdoc-html/extern/auxiliary/extern-links.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/extern-links.rs rename to tests/rustdoc-html/extern/auxiliary/extern-links.rs diff --git a/tests/rustdoc/extern/auxiliary/external-cross-doc.md b/tests/rustdoc-html/extern/auxiliary/external-cross-doc.md similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-cross-doc.md rename to tests/rustdoc-html/extern/auxiliary/external-cross-doc.md diff --git a/tests/rustdoc/extern/auxiliary/external-cross.rs b/tests/rustdoc-html/extern/auxiliary/external-cross.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-cross.rs rename to tests/rustdoc-html/extern/auxiliary/external-cross.rs diff --git a/tests/rustdoc/extern/auxiliary/external-doc.md b/tests/rustdoc-html/extern/auxiliary/external-doc.md similarity index 100% rename from tests/rustdoc/extern/auxiliary/external-doc.md rename to tests/rustdoc-html/extern/auxiliary/external-doc.md diff --git a/tests/rustdoc/extern/auxiliary/html_root.rs b/tests/rustdoc-html/extern/auxiliary/html_root.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/html_root.rs rename to tests/rustdoc-html/extern/auxiliary/html_root.rs diff --git a/tests/rustdoc/extern/auxiliary/issue-30109-1.rs b/tests/rustdoc-html/extern/auxiliary/issue-30109-1.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/issue-30109-1.rs rename to tests/rustdoc-html/extern/auxiliary/issue-30109-1.rs diff --git a/tests/rustdoc/extern/auxiliary/no_html_root.rs b/tests/rustdoc-html/extern/auxiliary/no_html_root.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/no_html_root.rs rename to tests/rustdoc-html/extern/auxiliary/no_html_root.rs diff --git a/tests/rustdoc/extern/auxiliary/panic-item.rs b/tests/rustdoc-html/extern/auxiliary/panic-item.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/panic-item.rs rename to tests/rustdoc-html/extern/auxiliary/panic-item.rs diff --git a/tests/rustdoc/extern/auxiliary/pub-extern-crate.rs b/tests/rustdoc-html/extern/auxiliary/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/pub-extern-crate.rs rename to tests/rustdoc-html/extern/auxiliary/pub-extern-crate.rs diff --git a/tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs b/tests/rustdoc-html/extern/auxiliary/rustdoc-extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs rename to tests/rustdoc-html/extern/auxiliary/rustdoc-extern-default-method.rs diff --git a/tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs b/tests/rustdoc-html/extern/auxiliary/rustdoc-extern-method.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs rename to tests/rustdoc-html/extern/auxiliary/rustdoc-extern-method.rs diff --git a/tests/rustdoc/extern/auxiliary/variant-struct.rs b/tests/rustdoc-html/extern/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/extern/auxiliary/variant-struct.rs rename to tests/rustdoc-html/extern/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/extern/duplicate-reexports-section-150211.rs b/tests/rustdoc-html/extern/duplicate-reexports-section-150211.rs similarity index 100% rename from tests/rustdoc/extern/duplicate-reexports-section-150211.rs rename to tests/rustdoc-html/extern/duplicate-reexports-section-150211.rs diff --git a/tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html b/tests/rustdoc-html/extern/extern-default-method.no_href_on_anchor.html similarity index 100% rename from tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html rename to tests/rustdoc-html/extern/extern-default-method.no_href_on_anchor.html diff --git a/tests/rustdoc/extern/extern-default-method.rs b/tests/rustdoc-html/extern/extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern/extern-default-method.rs rename to tests/rustdoc-html/extern/extern-default-method.rs diff --git a/tests/rustdoc/extern/extern-fn-22038.rs b/tests/rustdoc-html/extern/extern-fn-22038.rs similarity index 100% rename from tests/rustdoc/extern/extern-fn-22038.rs rename to tests/rustdoc-html/extern/extern-fn-22038.rs diff --git a/tests/rustdoc/extern/extern-html-alias.rs b/tests/rustdoc-html/extern/extern-html-alias.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-alias.rs rename to tests/rustdoc-html/extern/extern-html-alias.rs diff --git a/tests/rustdoc/extern/extern-html-fallback.rs b/tests/rustdoc-html/extern/extern-html-fallback.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-fallback.rs rename to tests/rustdoc-html/extern/extern-html-fallback.rs diff --git a/tests/rustdoc/extern/extern-html-root-url-precedence.rs b/tests/rustdoc-html/extern/extern-html-root-url-precedence.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-root-url-precedence.rs rename to tests/rustdoc-html/extern/extern-html-root-url-precedence.rs diff --git a/tests/rustdoc/extern/extern-html-root-url.rs b/tests/rustdoc-html/extern/extern-html-root-url.rs similarity index 100% rename from tests/rustdoc/extern/extern-html-root-url.rs rename to tests/rustdoc-html/extern/extern-html-root-url.rs diff --git a/tests/rustdoc/extern/extern-links.rs b/tests/rustdoc-html/extern/extern-links.rs similarity index 100% rename from tests/rustdoc/extern/extern-links.rs rename to tests/rustdoc-html/extern/extern-links.rs diff --git a/tests/rustdoc/extern/extern-method.rs b/tests/rustdoc-html/extern/extern-method.rs similarity index 100% rename from tests/rustdoc/extern/extern-method.rs rename to tests/rustdoc-html/extern/extern-method.rs diff --git a/tests/rustdoc/extern/external-cross.rs b/tests/rustdoc-html/extern/external-cross.rs similarity index 100% rename from tests/rustdoc/extern/external-cross.rs rename to tests/rustdoc-html/extern/external-cross.rs diff --git a/tests/rustdoc/extern/external-doc.rs b/tests/rustdoc-html/extern/external-doc.rs similarity index 100% rename from tests/rustdoc/extern/external-doc.rs rename to tests/rustdoc-html/extern/external-doc.rs diff --git a/tests/rustdoc/extern/hidden-extern-34025.rs b/tests/rustdoc-html/extern/hidden-extern-34025.rs similarity index 100% rename from tests/rustdoc/extern/hidden-extern-34025.rs rename to tests/rustdoc-html/extern/hidden-extern-34025.rs diff --git a/tests/rustdoc/extern/link-extern-crate-33178.rs b/tests/rustdoc-html/extern/link-extern-crate-33178.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-33178.rs rename to tests/rustdoc-html/extern/link-extern-crate-33178.rs diff --git a/tests/rustdoc/extern/link-extern-crate-item-30109.rs b/tests/rustdoc-html/extern/link-extern-crate-item-30109.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-item-30109.rs rename to tests/rustdoc-html/extern/link-extern-crate-item-30109.rs diff --git a/tests/rustdoc/extern/link-extern-crate-title-33178.rs b/tests/rustdoc-html/extern/link-extern-crate-title-33178.rs similarity index 100% rename from tests/rustdoc/extern/link-extern-crate-title-33178.rs rename to tests/rustdoc-html/extern/link-extern-crate-title-33178.rs diff --git a/tests/rustdoc/extern/pub-extern-crate-150176.rs b/tests/rustdoc-html/extern/pub-extern-crate-150176.rs similarity index 100% rename from tests/rustdoc/extern/pub-extern-crate-150176.rs rename to tests/rustdoc-html/extern/pub-extern-crate-150176.rs diff --git a/tests/rustdoc/extern/pub-extern-crate.rs b/tests/rustdoc-html/extern/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/pub-extern-crate.rs rename to tests/rustdoc-html/extern/pub-extern-crate.rs diff --git a/tests/rustdoc/extern/unsafe-extern-blocks.rs b/tests/rustdoc-html/extern/unsafe-extern-blocks.rs similarity index 100% rename from tests/rustdoc/extern/unsafe-extern-blocks.rs rename to tests/rustdoc-html/extern/unsafe-extern-blocks.rs diff --git a/tests/rustdoc/extern/unused-extern-crate.rs b/tests/rustdoc-html/extern/unused-extern-crate.rs similarity index 100% rename from tests/rustdoc/extern/unused-extern-crate.rs rename to tests/rustdoc-html/extern/unused-extern-crate.rs diff --git a/tests/rustdoc/extremely_long_typename.extremely_long_typename.html b/tests/rustdoc-html/extremely_long_typename.extremely_long_typename.html similarity index 100% rename from tests/rustdoc/extremely_long_typename.extremely_long_typename.html rename to tests/rustdoc-html/extremely_long_typename.extremely_long_typename.html diff --git a/tests/rustdoc/extremely_long_typename.rs b/tests/rustdoc-html/extremely_long_typename.rs similarity index 100% rename from tests/rustdoc/extremely_long_typename.rs rename to tests/rustdoc-html/extremely_long_typename.rs diff --git a/tests/rustdoc/feature-gate-doc_auto_cfg.rs b/tests/rustdoc-html/feature-gate-doc_auto_cfg.rs similarity index 100% rename from tests/rustdoc/feature-gate-doc_auto_cfg.rs rename to tests/rustdoc-html/feature-gate-doc_auto_cfg.rs diff --git a/tests/rustdoc/ffi.rs b/tests/rustdoc-html/ffi.rs similarity index 100% rename from tests/rustdoc/ffi.rs rename to tests/rustdoc-html/ffi.rs diff --git a/tests/rustdoc/file-creation-111249.rs b/tests/rustdoc-html/file-creation-111249.rs similarity index 100% rename from tests/rustdoc/file-creation-111249.rs rename to tests/rustdoc-html/file-creation-111249.rs diff --git a/tests/rustdoc/files-creation-hidden.rs b/tests/rustdoc-html/files-creation-hidden.rs similarity index 100% rename from tests/rustdoc/files-creation-hidden.rs rename to tests/rustdoc-html/files-creation-hidden.rs diff --git a/tests/rustdoc/fn-bound.rs b/tests/rustdoc-html/fn-bound.rs similarity index 100% rename from tests/rustdoc/fn-bound.rs rename to tests/rustdoc-html/fn-bound.rs diff --git a/tests/rustdoc/fn-pointer-arg-name.rs b/tests/rustdoc-html/fn-pointer-arg-name.rs similarity index 100% rename from tests/rustdoc/fn-pointer-arg-name.rs rename to tests/rustdoc-html/fn-pointer-arg-name.rs diff --git a/tests/rustdoc/fn-sidebar.rs b/tests/rustdoc-html/fn-sidebar.rs similarity index 100% rename from tests/rustdoc/fn-sidebar.rs rename to tests/rustdoc-html/fn-sidebar.rs diff --git a/tests/rustdoc/fn-type.rs b/tests/rustdoc-html/fn-type.rs similarity index 100% rename from tests/rustdoc/fn-type.rs rename to tests/rustdoc-html/fn-type.rs diff --git a/tests/rustdoc/footnote-definition-without-blank-line-100638.rs b/tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs similarity index 100% rename from tests/rustdoc/footnote-definition-without-blank-line-100638.rs rename to tests/rustdoc-html/footnote-definition-without-blank-line-100638.rs diff --git a/tests/rustdoc/footnote-ids.rs b/tests/rustdoc-html/footnote-ids.rs similarity index 100% rename from tests/rustdoc/footnote-ids.rs rename to tests/rustdoc-html/footnote-ids.rs diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc-html/footnote-in-summary.rs similarity index 100% rename from tests/rustdoc/footnote-in-summary.rs rename to tests/rustdoc-html/footnote-in-summary.rs diff --git a/tests/rustdoc/footnote-reference-ids.rs b/tests/rustdoc-html/footnote-reference-ids.rs similarity index 100% rename from tests/rustdoc/footnote-reference-ids.rs rename to tests/rustdoc-html/footnote-reference-ids.rs diff --git a/tests/rustdoc/footnote-reference-in-footnote-def.rs b/tests/rustdoc-html/footnote-reference-in-footnote-def.rs similarity index 100% rename from tests/rustdoc/footnote-reference-in-footnote-def.rs rename to tests/rustdoc-html/footnote-reference-in-footnote-def.rs diff --git a/tests/rustdoc/force-target-feature.rs b/tests/rustdoc-html/force-target-feature.rs similarity index 100% rename from tests/rustdoc/force-target-feature.rs rename to tests/rustdoc-html/force-target-feature.rs diff --git a/tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs b/tests/rustdoc-html/force-unstable-if-unmarked-106421-not-internal.rs similarity index 100% rename from tests/rustdoc/force-unstable-if-unmarked-106421-not-internal.rs rename to tests/rustdoc-html/force-unstable-if-unmarked-106421-not-internal.rs diff --git a/tests/rustdoc/force-unstable-if-unmarked-106421.rs b/tests/rustdoc-html/force-unstable-if-unmarked-106421.rs similarity index 100% rename from tests/rustdoc/force-unstable-if-unmarked-106421.rs rename to tests/rustdoc-html/force-unstable-if-unmarked-106421.rs diff --git a/tests/rustdoc/foreigntype.rs b/tests/rustdoc-html/foreigntype.rs similarity index 100% rename from tests/rustdoc/foreigntype.rs rename to tests/rustdoc-html/foreigntype.rs diff --git a/tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs b/tests/rustdoc-html/generic-associated-types/gat-elided-lifetime-94683.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gat-elided-lifetime-94683.rs rename to tests/rustdoc-html/generic-associated-types/gat-elided-lifetime-94683.rs diff --git a/tests/rustdoc/generic-associated-types/gat-linkification-109488.rs b/tests/rustdoc-html/generic-associated-types/gat-linkification-109488.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gat-linkification-109488.rs rename to tests/rustdoc-html/generic-associated-types/gat-linkification-109488.rs diff --git a/tests/rustdoc/generic-associated-types/gats.rs b/tests/rustdoc-html/generic-associated-types/gats.rs similarity index 100% rename from tests/rustdoc/generic-associated-types/gats.rs rename to tests/rustdoc-html/generic-associated-types/gats.rs diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc-html/glob-shadowing.rs similarity index 100% rename from tests/rustdoc/glob-shadowing.rs rename to tests/rustdoc-html/glob-shadowing.rs diff --git a/tests/rustdoc/heading-levels-89309.rs b/tests/rustdoc-html/heading-levels-89309.rs similarity index 100% rename from tests/rustdoc/heading-levels-89309.rs rename to tests/rustdoc-html/heading-levels-89309.rs diff --git a/tests/rustdoc/heterogeneous-concat.rs b/tests/rustdoc-html/heterogeneous-concat.rs similarity index 100% rename from tests/rustdoc/heterogeneous-concat.rs rename to tests/rustdoc-html/heterogeneous-concat.rs diff --git a/tests/rustdoc/hidden-line.rs b/tests/rustdoc-html/hidden-line.rs similarity index 100% rename from tests/rustdoc/hidden-line.rs rename to tests/rustdoc-html/hidden-line.rs diff --git a/tests/rustdoc/hidden-methods.rs b/tests/rustdoc-html/hidden-methods.rs similarity index 100% rename from tests/rustdoc/hidden-methods.rs rename to tests/rustdoc-html/hidden-methods.rs diff --git a/tests/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs similarity index 100% rename from tests/rustdoc/hidden-trait-methods-with-document-hidden-items.rs rename to tests/rustdoc-html/hidden-trait-methods-with-document-hidden-items.rs diff --git a/tests/rustdoc/hidden-trait-methods.rs b/tests/rustdoc-html/hidden-trait-methods.rs similarity index 100% rename from tests/rustdoc/hidden-trait-methods.rs rename to tests/rustdoc-html/hidden-trait-methods.rs diff --git a/tests/rustdoc/hide-unstable-trait.rs b/tests/rustdoc-html/hide-unstable-trait.rs similarity index 100% rename from tests/rustdoc/hide-unstable-trait.rs rename to tests/rustdoc-html/hide-unstable-trait.rs diff --git a/tests/rustdoc/higher-ranked-trait-bounds.rs b/tests/rustdoc-html/higher-ranked-trait-bounds.rs similarity index 100% rename from tests/rustdoc/higher-ranked-trait-bounds.rs rename to tests/rustdoc-html/higher-ranked-trait-bounds.rs diff --git a/tests/rustdoc/highlight-invalid-rust-12834.rs b/tests/rustdoc-html/highlight-invalid-rust-12834.rs similarity index 100% rename from tests/rustdoc/highlight-invalid-rust-12834.rs rename to tests/rustdoc-html/highlight-invalid-rust-12834.rs diff --git a/tests/rustdoc/ice-type-error-19181.rs b/tests/rustdoc-html/ice-type-error-19181.rs similarity index 100% rename from tests/rustdoc/ice-type-error-19181.rs rename to tests/rustdoc-html/ice-type-error-19181.rs diff --git a/tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/auxiliary/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/auxiliary/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/auxiliary/extern-impl-trait.rs b/tests/rustdoc-html/impl/auxiliary/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/extern-impl-trait.rs rename to tests/rustdoc-html/impl/auxiliary/extern-impl-trait.rs diff --git a/tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs b/tests/rustdoc-html/impl/auxiliary/incoherent-impl-types.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs rename to tests/rustdoc-html/impl/auxiliary/incoherent-impl-types.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-100204-aux.rs b/tests/rustdoc-html/impl/auxiliary/issue-100204-aux.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-100204-aux.rs rename to tests/rustdoc-html/impl/auxiliary/issue-100204-aux.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-17476.rs b/tests/rustdoc-html/impl/auxiliary/issue-17476.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-17476.rs rename to tests/rustdoc-html/impl/auxiliary/issue-17476.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-21092.rs b/tests/rustdoc-html/impl/auxiliary/issue-21092.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-21092.rs rename to tests/rustdoc-html/impl/auxiliary/issue-21092.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-22025.rs b/tests/rustdoc-html/impl/auxiliary/issue-22025.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-22025.rs rename to tests/rustdoc-html/impl/auxiliary/issue-22025.rs diff --git a/tests/rustdoc/impl/auxiliary/issue-53689.rs b/tests/rustdoc-html/impl/auxiliary/issue-53689.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/issue-53689.rs rename to tests/rustdoc-html/impl/auxiliary/issue-53689.rs diff --git a/tests/rustdoc/impl/auxiliary/precise-capturing.rs b/tests/rustdoc-html/impl/auxiliary/precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/precise-capturing.rs rename to tests/rustdoc-html/impl/auxiliary/precise-capturing.rs diff --git a/tests/rustdoc/impl/auxiliary/real_gimli.rs b/tests/rustdoc-html/impl/auxiliary/real_gimli.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/real_gimli.rs rename to tests/rustdoc-html/impl/auxiliary/real_gimli.rs diff --git a/tests/rustdoc/impl/auxiliary/realcore.rs b/tests/rustdoc-html/impl/auxiliary/realcore.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/realcore.rs rename to tests/rustdoc-html/impl/auxiliary/realcore.rs diff --git a/tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs b/tests/rustdoc-html/impl/auxiliary/rustdoc-default-impl.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs rename to tests/rustdoc-html/impl/auxiliary/rustdoc-default-impl.rs diff --git a/tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs b/tests/rustdoc-html/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs rename to tests/rustdoc-html/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl/blanket-impl-29503.rs b/tests/rustdoc-html/impl/blanket-impl-29503.rs similarity index 100% rename from tests/rustdoc/impl/blanket-impl-29503.rs rename to tests/rustdoc-html/impl/blanket-impl-29503.rs diff --git a/tests/rustdoc/impl/blanket-impl-78673.rs b/tests/rustdoc-html/impl/blanket-impl-78673.rs similarity index 100% rename from tests/rustdoc/impl/blanket-impl-78673.rs rename to tests/rustdoc-html/impl/blanket-impl-78673.rs diff --git a/tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs b/tests/rustdoc-html/impl/deduplicate-glob-import-impl-21474.rs similarity index 100% rename from tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs rename to tests/rustdoc-html/impl/deduplicate-glob-import-impl-21474.rs diff --git a/tests/rustdoc/impl/deduplicate-trait-impl-22025.rs b/tests/rustdoc-html/impl/deduplicate-trait-impl-22025.rs similarity index 100% rename from tests/rustdoc/impl/deduplicate-trait-impl-22025.rs rename to tests/rustdoc-html/impl/deduplicate-trait-impl-22025.rs diff --git a/tests/rustdoc/impl/default-impl.rs b/tests/rustdoc-html/impl/default-impl.rs similarity index 100% rename from tests/rustdoc/impl/default-impl.rs rename to tests/rustdoc-html/impl/default-impl.rs diff --git a/tests/rustdoc/impl/deprecated-impls.rs b/tests/rustdoc-html/impl/deprecated-impls.rs similarity index 100% rename from tests/rustdoc/impl/deprecated-impls.rs rename to tests/rustdoc-html/impl/deprecated-impls.rs diff --git a/tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs b/tests/rustdoc-html/impl/doc-hidden-trait-implementors-33069.rs similarity index 100% rename from tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs rename to tests/rustdoc-html/impl/doc-hidden-trait-implementors-33069.rs diff --git a/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs b/tests/rustdoc-html/impl/doc_auto_cfg_nested_impl.rs similarity index 100% rename from tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs rename to tests/rustdoc-html/impl/doc_auto_cfg_nested_impl.rs diff --git a/tests/rustdoc/impl/duplicated_impl.rs b/tests/rustdoc-html/impl/duplicated_impl.rs similarity index 100% rename from tests/rustdoc/impl/duplicated_impl.rs rename to tests/rustdoc-html/impl/duplicated_impl.rs diff --git a/tests/rustdoc/impl/empty-impl-block.rs b/tests/rustdoc-html/impl/empty-impl-block.rs similarity index 100% rename from tests/rustdoc/impl/empty-impl-block.rs rename to tests/rustdoc-html/impl/empty-impl-block.rs diff --git a/tests/rustdoc/impl/empty-impls.rs b/tests/rustdoc-html/impl/empty-impls.rs similarity index 100% rename from tests/rustdoc/impl/empty-impls.rs rename to tests/rustdoc-html/impl/empty-impls.rs diff --git a/tests/rustdoc/impl/extern-impl-trait.rs b/tests/rustdoc-html/impl/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/extern-impl-trait.rs rename to tests/rustdoc-html/impl/extern-impl-trait.rs diff --git a/tests/rustdoc/impl/extern-impl.rs b/tests/rustdoc-html/impl/extern-impl.rs similarity index 100% rename from tests/rustdoc/impl/extern-impl.rs rename to tests/rustdoc-html/impl/extern-impl.rs diff --git a/tests/rustdoc/impl/foreign-implementors-js-43701.rs b/tests/rustdoc-html/impl/foreign-implementors-js-43701.rs similarity index 100% rename from tests/rustdoc/impl/foreign-implementors-js-43701.rs rename to tests/rustdoc-html/impl/foreign-implementors-js-43701.rs diff --git a/tests/rustdoc/impl/generic-impl.rs b/tests/rustdoc-html/impl/generic-impl.rs similarity index 100% rename from tests/rustdoc/impl/generic-impl.rs rename to tests/rustdoc-html/impl/generic-impl.rs diff --git a/tests/rustdoc/impl/hidden-implementors-90781.rs b/tests/rustdoc-html/impl/hidden-implementors-90781.rs similarity index 100% rename from tests/rustdoc/impl/hidden-implementors-90781.rs rename to tests/rustdoc-html/impl/hidden-implementors-90781.rs diff --git a/tests/rustdoc/impl/hidden-impls.rs b/tests/rustdoc-html/impl/hidden-impls.rs similarity index 100% rename from tests/rustdoc/impl/hidden-impls.rs rename to tests/rustdoc-html/impl/hidden-impls.rs diff --git a/tests/rustdoc/impl/hidden-trait-struct-impls.rs b/tests/rustdoc-html/impl/hidden-trait-struct-impls.rs similarity index 100% rename from tests/rustdoc/impl/hidden-trait-struct-impls.rs rename to tests/rustdoc-html/impl/hidden-trait-struct-impls.rs diff --git a/tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs b/tests/rustdoc-html/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs similarity index 100% rename from tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs rename to tests/rustdoc-html/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs diff --git a/tests/rustdoc/impl/impl-alias-substituted.rs b/tests/rustdoc-html/impl/impl-alias-substituted.rs similarity index 100% rename from tests/rustdoc/impl/impl-alias-substituted.rs rename to tests/rustdoc-html/impl/impl-alias-substituted.rs diff --git a/tests/rustdoc/impl/impl-assoc-type-21092.rs b/tests/rustdoc-html/impl/impl-assoc-type-21092.rs similarity index 100% rename from tests/rustdoc/impl/impl-assoc-type-21092.rs rename to tests/rustdoc-html/impl/impl-assoc-type-21092.rs diff --git a/tests/rustdoc/impl/impl-associated-items-order.rs b/tests/rustdoc-html/impl/impl-associated-items-order.rs similarity index 100% rename from tests/rustdoc/impl/impl-associated-items-order.rs rename to tests/rustdoc-html/impl/impl-associated-items-order.rs diff --git a/tests/rustdoc/impl/impl-associated-items-sidebar.rs b/tests/rustdoc-html/impl/impl-associated-items-sidebar.rs similarity index 100% rename from tests/rustdoc/impl/impl-associated-items-sidebar.rs rename to tests/rustdoc-html/impl/impl-associated-items-sidebar.rs diff --git a/tests/rustdoc/impl/impl-blanket-53689.rs b/tests/rustdoc-html/impl/impl-blanket-53689.rs similarity index 100% rename from tests/rustdoc/impl/impl-blanket-53689.rs rename to tests/rustdoc-html/impl/impl-blanket-53689.rs diff --git a/tests/rustdoc/impl/impl-box.rs b/tests/rustdoc-html/impl/impl-box.rs similarity index 100% rename from tests/rustdoc/impl/impl-box.rs rename to tests/rustdoc-html/impl/impl-box.rs diff --git a/tests/rustdoc/impl/impl-disambiguation.rs b/tests/rustdoc-html/impl/impl-disambiguation.rs similarity index 100% rename from tests/rustdoc/impl/impl-disambiguation.rs rename to tests/rustdoc-html/impl/impl-disambiguation.rs diff --git a/tests/rustdoc/impl/impl-everywhere.rs b/tests/rustdoc-html/impl/impl-everywhere.rs similarity index 100% rename from tests/rustdoc/impl/impl-everywhere.rs rename to tests/rustdoc-html/impl/impl-everywhere.rs diff --git a/tests/rustdoc/impl/impl-in-const-block.rs b/tests/rustdoc-html/impl/impl-in-const-block.rs similarity index 100% rename from tests/rustdoc/impl/impl-in-const-block.rs rename to tests/rustdoc-html/impl/impl-in-const-block.rs diff --git a/tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc-html/impl/impl-on-ty-alias-issue-119015.rs similarity index 100% rename from tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs rename to tests/rustdoc-html/impl/impl-on-ty-alias-issue-119015.rs diff --git a/tests/rustdoc/impl/impl-parts-crosscrate.rs b/tests/rustdoc-html/impl/impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl/impl-parts-crosscrate.rs rename to tests/rustdoc-html/impl/impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl/impl-parts.rs b/tests/rustdoc-html/impl/impl-parts.rs similarity index 100% rename from tests/rustdoc/impl/impl-parts.rs rename to tests/rustdoc-html/impl/impl-parts.rs diff --git a/tests/rustdoc/impl/impl-ref-20175.rs b/tests/rustdoc-html/impl/impl-ref-20175.rs similarity index 100% rename from tests/rustdoc/impl/impl-ref-20175.rs rename to tests/rustdoc-html/impl/impl-ref-20175.rs diff --git a/tests/rustdoc/impl/impl-trait-43869.rs b/tests/rustdoc-html/impl/impl-trait-43869.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-43869.rs rename to tests/rustdoc-html/impl/impl-trait-43869.rs diff --git a/tests/rustdoc/impl/impl-trait-alias.rs b/tests/rustdoc-html/impl/impl-trait-alias.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-alias.rs rename to tests/rustdoc-html/impl/impl-trait-alias.rs diff --git a/tests/rustdoc/impl/impl-trait-precise-capturing.rs b/tests/rustdoc-html/impl/impl-trait-precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl/impl-trait-precise-capturing.rs rename to tests/rustdoc-html/impl/impl-trait-precise-capturing.rs diff --git a/tests/rustdoc/impl/impl-type-parameter-33592.rs b/tests/rustdoc-html/impl/impl-type-parameter-33592.rs similarity index 100% rename from tests/rustdoc/impl/impl-type-parameter-33592.rs rename to tests/rustdoc-html/impl/impl-type-parameter-33592.rs diff --git a/tests/rustdoc/impl/implementor-stable-version.rs b/tests/rustdoc-html/impl/implementor-stable-version.rs similarity index 100% rename from tests/rustdoc/impl/implementor-stable-version.rs rename to tests/rustdoc-html/impl/implementor-stable-version.rs diff --git a/tests/rustdoc/impl/implementors-unstable-75588.rs b/tests/rustdoc-html/impl/implementors-unstable-75588.rs similarity index 100% rename from tests/rustdoc/impl/implementors-unstable-75588.rs rename to tests/rustdoc-html/impl/implementors-unstable-75588.rs diff --git a/tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs b/tests/rustdoc-html/impl/inline-impl-through-glob-import-100204.rs similarity index 100% rename from tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs rename to tests/rustdoc-html/impl/inline-impl-through-glob-import-100204.rs diff --git a/tests/rustdoc/impl/manual_impl.rs b/tests/rustdoc-html/impl/manual_impl.rs similarity index 100% rename from tests/rustdoc/impl/manual_impl.rs rename to tests/rustdoc-html/impl/manual_impl.rs diff --git a/tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs b/tests/rustdoc-html/impl/method-link-foreign-trait-impl-17476.rs similarity index 100% rename from tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs rename to tests/rustdoc-html/impl/method-link-foreign-trait-impl-17476.rs diff --git a/tests/rustdoc/impl/module-impls.rs b/tests/rustdoc-html/impl/module-impls.rs similarity index 100% rename from tests/rustdoc/impl/module-impls.rs rename to tests/rustdoc-html/impl/module-impls.rs diff --git a/tests/rustdoc/impl/must_implement_one_of.rs b/tests/rustdoc-html/impl/must_implement_one_of.rs similarity index 100% rename from tests/rustdoc/impl/must_implement_one_of.rs rename to tests/rustdoc-html/impl/must_implement_one_of.rs diff --git a/tests/rustdoc/impl/negative-impl-no-items.rs b/tests/rustdoc-html/impl/negative-impl-no-items.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl-no-items.rs rename to tests/rustdoc-html/impl/negative-impl-no-items.rs diff --git a/tests/rustdoc/impl/negative-impl-sidebar.rs b/tests/rustdoc-html/impl/negative-impl-sidebar.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl-sidebar.rs rename to tests/rustdoc-html/impl/negative-impl-sidebar.rs diff --git a/tests/rustdoc/impl/negative-impl.rs b/tests/rustdoc-html/impl/negative-impl.rs similarity index 100% rename from tests/rustdoc/impl/negative-impl.rs rename to tests/rustdoc-html/impl/negative-impl.rs diff --git a/tests/rustdoc/impl/return-impl-trait.rs b/tests/rustdoc-html/impl/return-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/return-impl-trait.rs rename to tests/rustdoc-html/impl/return-impl-trait.rs diff --git a/tests/rustdoc/impl/rustc-incoherent-impls.rs b/tests/rustdoc-html/impl/rustc-incoherent-impls.rs similarity index 100% rename from tests/rustdoc/impl/rustc-incoherent-impls.rs rename to tests/rustdoc-html/impl/rustc-incoherent-impls.rs diff --git a/tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs b/tests/rustdoc-html/impl/same-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs rename to tests/rustdoc-html/impl/same-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs b/tests/rustdoc-html/impl/sidebar-trait-impl-disambiguate-78701.rs similarity index 100% rename from tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs rename to tests/rustdoc-html/impl/sidebar-trait-impl-disambiguate-78701.rs diff --git a/tests/rustdoc/impl/struct-implementations-title.rs b/tests/rustdoc-html/impl/struct-implementations-title.rs similarity index 100% rename from tests/rustdoc/impl/struct-implementations-title.rs rename to tests/rustdoc-html/impl/struct-implementations-title.rs diff --git a/tests/rustdoc/impl/trait-impl.rs b/tests/rustdoc-html/impl/trait-impl.rs similarity index 100% rename from tests/rustdoc/impl/trait-impl.rs rename to tests/rustdoc-html/impl/trait-impl.rs diff --git a/tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs b/tests/rustdoc-html/impl/trait-implementations-duplicate-self-45584.rs similarity index 100% rename from tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs rename to tests/rustdoc-html/impl/trait-implementations-duplicate-self-45584.rs diff --git a/tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs b/tests/rustdoc-html/impl/underscore-type-in-trait-impl-96381.rs similarity index 100% rename from tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs rename to tests/rustdoc-html/impl/underscore-type-in-trait-impl-96381.rs diff --git a/tests/rustdoc/impl/universal-impl-trait.rs b/tests/rustdoc-html/impl/universal-impl-trait.rs similarity index 100% rename from tests/rustdoc/impl/universal-impl-trait.rs rename to tests/rustdoc-html/impl/universal-impl-trait.rs diff --git a/tests/rustdoc/impl/unneeded-trait-implementations-title.rs b/tests/rustdoc-html/impl/unneeded-trait-implementations-title.rs similarity index 100% rename from tests/rustdoc/impl/unneeded-trait-implementations-title.rs rename to tests/rustdoc-html/impl/unneeded-trait-implementations-title.rs diff --git a/tests/rustdoc/import-remapped-paths.rs b/tests/rustdoc-html/import-remapped-paths.rs similarity index 100% rename from tests/rustdoc/import-remapped-paths.rs rename to tests/rustdoc-html/import-remapped-paths.rs diff --git a/tests/rustdoc/impossible-default.rs b/tests/rustdoc-html/impossible-default.rs similarity index 100% rename from tests/rustdoc/impossible-default.rs rename to tests/rustdoc-html/impossible-default.rs diff --git a/tests/rustdoc/include_str_cut.rs b/tests/rustdoc-html/include_str_cut.rs similarity index 100% rename from tests/rustdoc/include_str_cut.rs rename to tests/rustdoc-html/include_str_cut.rs diff --git a/tests/rustdoc/index-page.rs b/tests/rustdoc-html/index-page.rs similarity index 100% rename from tests/rustdoc/index-page.rs rename to tests/rustdoc-html/index-page.rs diff --git a/tests/rustdoc/infinite-redirection-16265-1.rs b/tests/rustdoc-html/infinite-redirection-16265-1.rs similarity index 100% rename from tests/rustdoc/infinite-redirection-16265-1.rs rename to tests/rustdoc-html/infinite-redirection-16265-1.rs diff --git a/tests/rustdoc/infinite-redirection-16265-2.rs b/tests/rustdoc-html/infinite-redirection-16265-2.rs similarity index 100% rename from tests/rustdoc/infinite-redirection-16265-2.rs rename to tests/rustdoc-html/infinite-redirection-16265-2.rs diff --git a/tests/rustdoc/infinite-redirection.rs b/tests/rustdoc-html/infinite-redirection.rs similarity index 100% rename from tests/rustdoc/infinite-redirection.rs rename to tests/rustdoc-html/infinite-redirection.rs diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc-html/inherent-projections.rs similarity index 100% rename from tests/rustdoc/inherent-projections.rs rename to tests/rustdoc-html/inherent-projections.rs diff --git a/tests/rustdoc/inline-default-methods.rs b/tests/rustdoc-html/inline-default-methods.rs similarity index 100% rename from tests/rustdoc/inline-default-methods.rs rename to tests/rustdoc-html/inline-default-methods.rs diff --git a/tests/rustdoc/inline-rename-34473.rs b/tests/rustdoc-html/inline-rename-34473.rs similarity index 100% rename from tests/rustdoc/inline-rename-34473.rs rename to tests/rustdoc-html/inline-rename-34473.rs diff --git a/tests/rustdoc/inline_cross/add-docs.rs b/tests/rustdoc-html/inline_cross/add-docs.rs similarity index 100% rename from tests/rustdoc/inline_cross/add-docs.rs rename to tests/rustdoc-html/inline_cross/add-docs.rs diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc-html/inline_cross/assoc-const-equality.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc-const-equality.rs rename to tests/rustdoc-html/inline_cross/assoc-const-equality.rs diff --git a/tests/rustdoc/inline_cross/assoc-items.rs b/tests/rustdoc-html/inline_cross/assoc-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc-items.rs rename to tests/rustdoc-html/inline_cross/assoc-items.rs diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out0.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out0.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out2.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out2.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out9.html similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.out9.html diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs b/tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.rs similarity index 100% rename from tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs rename to tests/rustdoc-html/inline_cross/assoc_item_trait_bounds.rs diff --git a/tests/rustdoc/inline_cross/async-fn.rs b/tests/rustdoc-html/inline_cross/async-fn.rs similarity index 100% rename from tests/rustdoc/inline_cross/async-fn.rs rename to tests/rustdoc-html/inline_cross/async-fn.rs diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc-html/inline_cross/attributes.rs similarity index 100% rename from tests/rustdoc/inline_cross/attributes.rs rename to tests/rustdoc-html/inline_cross/attributes.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/add-docs.rs b/tests/rustdoc-html/inline_cross/auxiliary/add-docs.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/add-docs.rs rename to tests/rustdoc-html/inline_cross/auxiliary/add-docs.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc-const-equality.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc-const-equality.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-items.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc-items.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc-items.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs b/tests/rustdoc-html/inline_cross/auxiliary/assoc_item_trait_bounds.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs rename to tests/rustdoc-html/inline_cross/auxiliary/assoc_item_trait_bounds.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/async-fn.rs b/tests/rustdoc-html/inline_cross/auxiliary/async-fn.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/async-fn.rs rename to tests/rustdoc-html/inline_cross/auxiliary/async-fn.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc-html/inline_cross/auxiliary/attributes.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/attributes.rs rename to tests/rustdoc-html/inline_cross/auxiliary/attributes.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs b/tests/rustdoc-html/inline_cross/auxiliary/const-effect-param.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/const-effect-param.rs rename to tests/rustdoc-html/inline_cross/auxiliary/const-effect-param.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/cross-glob.rs b/tests/rustdoc-html/inline_cross/auxiliary/cross-glob.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/cross-glob.rs rename to tests/rustdoc-html/inline_cross/auxiliary/cross-glob.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs b/tests/rustdoc-html/inline_cross/auxiliary/default-generic-args.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/default-generic-args.rs rename to tests/rustdoc-html/inline_cross/auxiliary/default-generic-args.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/default-trait-method.rs b/tests/rustdoc-html/inline_cross/auxiliary/default-trait-method.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/default-trait-method.rs rename to tests/rustdoc-html/inline_cross/auxiliary/default-trait-method.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/doc-auto-cfg.rs b/tests/rustdoc-html/inline_cross/auxiliary/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/doc-auto-cfg.rs rename to tests/rustdoc-html/inline_cross/auxiliary/doc-auto-cfg.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/dyn_trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs b/tests/rustdoc-html/inline_cross/auxiliary/early-late-bound-lifetime-params.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/early-late-bound-lifetime-params.rs rename to tests/rustdoc-html/inline_cross/auxiliary/early-late-bound-lifetime-params.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs b/tests/rustdoc-html/inline_cross/auxiliary/fn-ptr-ty.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs rename to tests/rustdoc-html/inline_cross/auxiliary/fn-ptr-ty.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs b/tests/rustdoc-html/inline_cross/auxiliary/generic-const-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs rename to tests/rustdoc-html/inline_cross/auxiliary/generic-const-items.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl-inline-without-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl-inline-without-trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl-inline-without-trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl-sized.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl-sized.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl-sized.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl-sized.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/tests/rustdoc-html/inline_cross/auxiliary/impl_trait_aux.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs rename to tests/rustdoc-html/inline_cross/auxiliary/impl_trait_aux.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/tests/rustdoc-html/inline_cross/auxiliary/implementors_inline.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/implementors_inline.rs rename to tests/rustdoc-html/inline_cross/auxiliary/implementors_inline.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-21801.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-21801.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-21801.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-21801.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-23207-1.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-23207-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-23207-1.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-23207-1.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-23207-2.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-23207-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-23207-2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-23207-2.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-24183.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-24183.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-24183.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-24183.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-27362-aux.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-27362-aux.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-27362-aux.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-27362-aux.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-29584.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-29584.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-29584.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-33113.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-33113.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-33113.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-33113.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-46727.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-46727.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-46727.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-46727.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-57180.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-57180.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-57180.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-57180.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-76736-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-76736-1.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-76736-1.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-76736-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-76736-2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/issue-85454.rs b/tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/issue-85454.rs rename to tests/rustdoc-html/inline_cross/auxiliary/issue-85454.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/macro-vis.rs b/tests/rustdoc-html/inline_cross/auxiliary/macro-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/macro-vis.rs rename to tests/rustdoc-html/inline_cross/auxiliary/macro-vis.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/macros.rs b/tests/rustdoc-html/inline_cross/auxiliary/macros.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/macros.rs rename to tests/rustdoc-html/inline_cross/auxiliary/macros.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/non_lifetime_binders.rs b/tests/rustdoc-html/inline_cross/auxiliary/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/non_lifetime_binders.rs rename to tests/rustdoc-html/inline_cross/auxiliary/non_lifetime_binders.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/proc_macro.rs b/tests/rustdoc-html/inline_cross/auxiliary/proc_macro.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/proc_macro.rs rename to tests/rustdoc-html/inline_cross/auxiliary/proc_macro.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs b/tests/rustdoc-html/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs rename to tests/rustdoc-html/inline_cross/auxiliary/reexport-with-anonymous-lifetime-98697.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/renamed-via-module.rs b/tests/rustdoc-html/inline_cross/auxiliary/renamed-via-module.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/renamed-via-module.rs rename to tests/rustdoc-html/inline_cross/auxiliary/renamed-via-module.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs b/tests/rustdoc-html/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs rename to tests/rustdoc-html/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden-sig.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden-sig.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden-sig.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-hidden.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-hidden.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-nonreachable-impls.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs b/tests/rustdoc-html/inline_cross/auxiliary/rustdoc-trait-object-impl.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/rustdoc-trait-object-impl.rs rename to tests/rustdoc-html/inline_cross/auxiliary/rustdoc-trait-object-impl.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/trait-vis.rs b/tests/rustdoc-html/inline_cross/auxiliary/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/trait-vis.rs rename to tests/rustdoc-html/inline_cross/auxiliary/trait-vis.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/use_crate.rs b/tests/rustdoc-html/inline_cross/auxiliary/use_crate.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/use_crate.rs rename to tests/rustdoc-html/inline_cross/auxiliary/use_crate.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/use_crate_2.rs b/tests/rustdoc-html/inline_cross/auxiliary/use_crate_2.rs similarity index 100% rename from tests/rustdoc/inline_cross/auxiliary/use_crate_2.rs rename to tests/rustdoc-html/inline_cross/auxiliary/use_crate_2.rs diff --git a/tests/rustdoc/inline_cross/const-effect-param.rs b/tests/rustdoc-html/inline_cross/const-effect-param.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-effect-param.rs rename to tests/rustdoc-html/inline_cross/const-effect-param.rs diff --git a/tests/rustdoc/inline_cross/const-eval-46727.rs b/tests/rustdoc-html/inline_cross/const-eval-46727.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-eval-46727.rs rename to tests/rustdoc-html/inline_cross/const-eval-46727.rs diff --git a/tests/rustdoc/inline_cross/const-fn-27362.rs b/tests/rustdoc-html/inline_cross/const-fn-27362.rs similarity index 100% rename from tests/rustdoc/inline_cross/const-fn-27362.rs rename to tests/rustdoc-html/inline_cross/const-fn-27362.rs diff --git a/tests/rustdoc/inline_cross/cross-glob.rs b/tests/rustdoc-html/inline_cross/cross-glob.rs similarity index 100% rename from tests/rustdoc/inline_cross/cross-glob.rs rename to tests/rustdoc-html/inline_cross/cross-glob.rs diff --git a/tests/rustdoc/inline_cross/deduplicate-inlined-items-23207.rs b/tests/rustdoc-html/inline_cross/deduplicate-inlined-items-23207.rs similarity index 100% rename from tests/rustdoc/inline_cross/deduplicate-inlined-items-23207.rs rename to tests/rustdoc-html/inline_cross/deduplicate-inlined-items-23207.rs diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc-html/inline_cross/default-generic-args.rs similarity index 100% rename from tests/rustdoc/inline_cross/default-generic-args.rs rename to tests/rustdoc-html/inline_cross/default-generic-args.rs diff --git a/tests/rustdoc/inline_cross/default-trait-method.rs b/tests/rustdoc-html/inline_cross/default-trait-method.rs similarity index 100% rename from tests/rustdoc/inline_cross/default-trait-method.rs rename to tests/rustdoc-html/inline_cross/default-trait-method.rs diff --git a/tests/rustdoc/inline_cross/doc-auto-cfg.rs b/tests/rustdoc-html/inline_cross/doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-auto-cfg.rs rename to tests/rustdoc-html/inline_cross/doc-auto-cfg.rs diff --git a/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs b/tests/rustdoc-html/inline_cross/doc-hidden-broken-link-28480.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs rename to tests/rustdoc-html/inline_cross/doc-hidden-broken-link-28480.rs diff --git a/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs b/tests/rustdoc-html/inline_cross/doc-hidden-extern-trait-impl-29584.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs rename to tests/rustdoc-html/inline_cross/doc-hidden-extern-trait-impl-29584.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-1.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948-2.rs diff --git a/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs b/tests/rustdoc-html/inline_cross/doc-reachability-impl-31948.rs similarity index 100% rename from tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs rename to tests/rustdoc-html/inline_cross/doc-reachability-impl-31948.rs diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc-html/inline_cross/dyn_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/dyn_trait.rs rename to tests/rustdoc-html/inline_cross/dyn_trait.rs diff --git a/tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs b/tests/rustdoc-html/inline_cross/early-late-bound-lifetime-params.rs similarity index 100% rename from tests/rustdoc/inline_cross/early-late-bound-lifetime-params.rs rename to tests/rustdoc-html/inline_cross/early-late-bound-lifetime-params.rs diff --git a/tests/rustdoc/inline_cross/fn-ptr-ty.rs b/tests/rustdoc-html/inline_cross/fn-ptr-ty.rs similarity index 100% rename from tests/rustdoc/inline_cross/fn-ptr-ty.rs rename to tests/rustdoc-html/inline_cross/fn-ptr-ty.rs diff --git a/tests/rustdoc/inline_cross/generic-const-items.rs b/tests/rustdoc-html/inline_cross/generic-const-items.rs similarity index 100% rename from tests/rustdoc/inline_cross/generic-const-items.rs rename to tests/rustdoc-html/inline_cross/generic-const-items.rs diff --git a/tests/rustdoc/inline_cross/hidden-use.rs b/tests/rustdoc-html/inline_cross/hidden-use.rs similarity index 100% rename from tests/rustdoc/inline_cross/hidden-use.rs rename to tests/rustdoc-html/inline_cross/hidden-use.rs diff --git a/tests/rustdoc/inline_cross/ice-import-crate-57180.rs b/tests/rustdoc-html/inline_cross/ice-import-crate-57180.rs similarity index 100% rename from tests/rustdoc/inline_cross/ice-import-crate-57180.rs rename to tests/rustdoc-html/inline_cross/ice-import-crate-57180.rs diff --git a/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs b/tests/rustdoc-html/inline_cross/impl-dyn-trait-32881.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs rename to tests/rustdoc-html/inline_cross/impl-dyn-trait-32881.rs diff --git a/tests/rustdoc/inline_cross/impl-inline-without-trait.rs b/tests/rustdoc-html/inline_cross/impl-inline-without-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-inline-without-trait.rs rename to tests/rustdoc-html/inline_cross/impl-inline-without-trait.rs diff --git a/tests/rustdoc/inline_cross/impl-ref-33113.rs b/tests/rustdoc-html/inline_cross/impl-ref-33113.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-ref-33113.rs rename to tests/rustdoc-html/inline_cross/impl-ref-33113.rs diff --git a/tests/rustdoc/inline_cross/impl-sized.rs b/tests/rustdoc-html/inline_cross/impl-sized.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl-sized.rs rename to tests/rustdoc-html/inline_cross/impl-sized.rs diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc-html/inline_cross/impl_trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/impl_trait.rs rename to tests/rustdoc-html/inline_cross/impl_trait.rs diff --git a/tests/rustdoc/inline_cross/implementors-js.rs b/tests/rustdoc-html/inline_cross/implementors-js.rs similarity index 100% rename from tests/rustdoc/inline_cross/implementors-js.rs rename to tests/rustdoc-html/inline_cross/implementors-js.rs diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc-html/inline_cross/inline_hidden.rs similarity index 100% rename from tests/rustdoc/inline_cross/inline_hidden.rs rename to tests/rustdoc-html/inline_cross/inline_hidden.rs diff --git a/tests/rustdoc/inline_cross/macro-vis.rs b/tests/rustdoc-html/inline_cross/macro-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/macro-vis.rs rename to tests/rustdoc-html/inline_cross/macro-vis.rs diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc-html/inline_cross/macros.rs similarity index 100% rename from tests/rustdoc/inline_cross/macros.rs rename to tests/rustdoc-html/inline_cross/macros.rs diff --git a/tests/rustdoc/inline_cross/non_lifetime_binders.rs b/tests/rustdoc-html/inline_cross/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/inline_cross/non_lifetime_binders.rs rename to tests/rustdoc-html/inline_cross/non_lifetime_binders.rs diff --git a/tests/rustdoc/inline_cross/proc_macro.rs b/tests/rustdoc-html/inline_cross/proc_macro.rs similarity index 100% rename from tests/rustdoc/inline_cross/proc_macro.rs rename to tests/rustdoc-html/inline_cross/proc_macro.rs diff --git a/tests/rustdoc/inline_cross/qpath-self-85454.rs b/tests/rustdoc-html/inline_cross/qpath-self-85454.rs similarity index 100% rename from tests/rustdoc/inline_cross/qpath-self-85454.rs rename to tests/rustdoc-html/inline_cross/qpath-self-85454.rs diff --git a/tests/rustdoc/inline_cross/reexport-with-anonymous-lifetime-98697.rs b/tests/rustdoc-html/inline_cross/reexport-with-anonymous-lifetime-98697.rs similarity index 100% rename from tests/rustdoc/inline_cross/reexport-with-anonymous-lifetime-98697.rs rename to tests/rustdoc-html/inline_cross/reexport-with-anonymous-lifetime-98697.rs diff --git a/tests/rustdoc/inline_cross/renamed-via-module.rs b/tests/rustdoc-html/inline_cross/renamed-via-module.rs similarity index 100% rename from tests/rustdoc/inline_cross/renamed-via-module.rs rename to tests/rustdoc-html/inline_cross/renamed-via-module.rs diff --git a/tests/rustdoc/inline_cross/ret-pos-impl-trait-in-trait.rs b/tests/rustdoc-html/inline_cross/ret-pos-impl-trait-in-trait.rs similarity index 100% rename from tests/rustdoc/inline_cross/ret-pos-impl-trait-in-trait.rs rename to tests/rustdoc-html/inline_cross/ret-pos-impl-trait-in-trait.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-1.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-1.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-1.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-1.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-2.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-2.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-2.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-2.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-3.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-3.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-3.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-3.rs diff --git a/tests/rustdoc/inline_cross/rustc-private-76736-4.rs b/tests/rustdoc-html/inline_cross/rustc-private-76736-4.rs similarity index 100% rename from tests/rustdoc/inline_cross/rustc-private-76736-4.rs rename to tests/rustdoc-html/inline_cross/rustc-private-76736-4.rs diff --git a/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html b/tests/rustdoc-html/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html similarity index 100% rename from tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html rename to tests/rustdoc-html/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html diff --git a/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs b/tests/rustdoc-html/inline_cross/self-sized-bounds-24183.rs similarity index 100% rename from tests/rustdoc/inline_cross/self-sized-bounds-24183.rs rename to tests/rustdoc-html/inline_cross/self-sized-bounds-24183.rs diff --git a/tests/rustdoc/inline_cross/sugar-closure-crate-21801.rs b/tests/rustdoc-html/inline_cross/sugar-closure-crate-21801.rs similarity index 100% rename from tests/rustdoc/inline_cross/sugar-closure-crate-21801.rs rename to tests/rustdoc-html/inline_cross/sugar-closure-crate-21801.rs diff --git a/tests/rustdoc/inline_cross/trait-vis.rs b/tests/rustdoc-html/inline_cross/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_cross/trait-vis.rs rename to tests/rustdoc-html/inline_cross/trait-vis.rs diff --git a/tests/rustdoc/inline_cross/use_crate.rs b/tests/rustdoc-html/inline_cross/use_crate.rs similarity index 100% rename from tests/rustdoc/inline_cross/use_crate.rs rename to tests/rustdoc-html/inline_cross/use_crate.rs diff --git a/tests/rustdoc/inline_local/blanket-impl-reexported-trait-94183.rs b/tests/rustdoc-html/inline_local/blanket-impl-reexported-trait-94183.rs similarity index 100% rename from tests/rustdoc/inline_local/blanket-impl-reexported-trait-94183.rs rename to tests/rustdoc-html/inline_local/blanket-impl-reexported-trait-94183.rs diff --git a/tests/rustdoc/inline_local/doc-no-inline-32343.rs b/tests/rustdoc-html/inline_local/doc-no-inline-32343.rs similarity index 100% rename from tests/rustdoc/inline_local/doc-no-inline-32343.rs rename to tests/rustdoc-html/inline_local/doc-no-inline-32343.rs diff --git a/tests/rustdoc/inline_local/enum-variant-reexport-46766.rs b/tests/rustdoc-html/inline_local/enum-variant-reexport-46766.rs similarity index 100% rename from tests/rustdoc/inline_local/enum-variant-reexport-46766.rs rename to tests/rustdoc-html/inline_local/enum-variant-reexport-46766.rs diff --git a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs similarity index 100% rename from tests/rustdoc/inline_local/fully-stable-path-is-better.rs rename to tests/rustdoc-html/inline_local/fully-stable-path-is-better.rs diff --git a/tests/rustdoc/inline_local/glob-extern-document-private-items.rs b/tests/rustdoc-html/inline_local/glob-extern-document-private-items.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-extern-document-private-items.rs rename to tests/rustdoc-html/inline_local/glob-extern-document-private-items.rs diff --git a/tests/rustdoc/inline_local/glob-extern.rs b/tests/rustdoc-html/inline_local/glob-extern.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-extern.rs rename to tests/rustdoc-html/inline_local/glob-extern.rs diff --git a/tests/rustdoc/inline_local/glob-private-document-private-items.rs b/tests/rustdoc-html/inline_local/glob-private-document-private-items.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-private-document-private-items.rs rename to tests/rustdoc-html/inline_local/glob-private-document-private-items.rs diff --git a/tests/rustdoc/inline_local/glob-private.rs b/tests/rustdoc-html/inline_local/glob-private.rs similarity index 100% rename from tests/rustdoc/inline_local/glob-private.rs rename to tests/rustdoc-html/inline_local/glob-private.rs diff --git a/tests/rustdoc/inline_local/hidden-use.rs b/tests/rustdoc-html/inline_local/hidden-use.rs similarity index 100% rename from tests/rustdoc/inline_local/hidden-use.rs rename to tests/rustdoc-html/inline_local/hidden-use.rs diff --git a/tests/rustdoc/inline_local/macro_by_example.rs b/tests/rustdoc-html/inline_local/macro_by_example.rs similarity index 100% rename from tests/rustdoc/inline_local/macro_by_example.rs rename to tests/rustdoc-html/inline_local/macro_by_example.rs diff --git a/tests/rustdoc/inline_local/parent-path-is-better.rs b/tests/rustdoc-html/inline_local/parent-path-is-better.rs similarity index 100% rename from tests/rustdoc/inline_local/parent-path-is-better.rs rename to tests/rustdoc-html/inline_local/parent-path-is-better.rs diff --git a/tests/rustdoc/inline_local/please_inline.rs b/tests/rustdoc-html/inline_local/please_inline.rs similarity index 100% rename from tests/rustdoc/inline_local/please_inline.rs rename to tests/rustdoc-html/inline_local/please_inline.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-81141-2.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141-2.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-81141-2.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141-2.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-generics-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-generics-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-generics-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-generics-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-hidden-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-hidden-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-hidden-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-hidden-81141.rs diff --git a/tests/rustdoc/inline_local/private-reexport-in-public-api-private-81141.rs b/tests/rustdoc-html/inline_local/private-reexport-in-public-api-private-81141.rs similarity index 100% rename from tests/rustdoc/inline_local/private-reexport-in-public-api-private-81141.rs rename to tests/rustdoc-html/inline_local/private-reexport-in-public-api-private-81141.rs diff --git a/tests/rustdoc/inline_local/pub-re-export-28537.rs b/tests/rustdoc-html/inline_local/pub-re-export-28537.rs similarity index 100% rename from tests/rustdoc/inline_local/pub-re-export-28537.rs rename to tests/rustdoc-html/inline_local/pub-re-export-28537.rs diff --git a/tests/rustdoc/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs b/tests/rustdoc-html/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs similarity index 100% rename from tests/rustdoc/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs rename to tests/rustdoc-html/inline_local/reexported-macro-and-macro-export-sidebar-89852.rs diff --git a/tests/rustdoc/inline_local/staged-inline.rs b/tests/rustdoc-html/inline_local/staged-inline.rs similarity index 100% rename from tests/rustdoc/inline_local/staged-inline.rs rename to tests/rustdoc-html/inline_local/staged-inline.rs diff --git a/tests/rustdoc/inline_local/trait-vis.rs b/tests/rustdoc-html/inline_local/trait-vis.rs similarity index 100% rename from tests/rustdoc/inline_local/trait-vis.rs rename to tests/rustdoc-html/inline_local/trait-vis.rs diff --git a/tests/rustdoc/internal.rs b/tests/rustdoc-html/internal.rs similarity index 100% rename from tests/rustdoc/internal.rs rename to tests/rustdoc-html/internal.rs diff --git a/tests/rustdoc/intra-doc-crate/auxiliary/self.rs b/tests/rustdoc-html/intra-doc-crate/auxiliary/self.rs similarity index 100% rename from tests/rustdoc/intra-doc-crate/auxiliary/self.rs rename to tests/rustdoc-html/intra-doc-crate/auxiliary/self.rs diff --git a/tests/rustdoc/intra-doc-crate/self.rs b/tests/rustdoc-html/intra-doc-crate/self.rs similarity index 100% rename from tests/rustdoc/intra-doc-crate/self.rs rename to tests/rustdoc-html/intra-doc-crate/self.rs diff --git a/tests/rustdoc/intra-doc/anchors.rs b/tests/rustdoc-html/intra-doc/anchors.rs similarity index 100% rename from tests/rustdoc/intra-doc/anchors.rs rename to tests/rustdoc-html/intra-doc/anchors.rs diff --git a/tests/rustdoc/intra-doc/assoc-reexport-super.rs b/tests/rustdoc-html/intra-doc/assoc-reexport-super.rs similarity index 100% rename from tests/rustdoc/intra-doc/assoc-reexport-super.rs rename to tests/rustdoc-html/intra-doc/assoc-reexport-super.rs diff --git a/tests/rustdoc/intra-doc/associated-defaults.rs b/tests/rustdoc-html/intra-doc/associated-defaults.rs similarity index 100% rename from tests/rustdoc/intra-doc/associated-defaults.rs rename to tests/rustdoc-html/intra-doc/associated-defaults.rs diff --git a/tests/rustdoc/intra-doc/associated-items.rs b/tests/rustdoc-html/intra-doc/associated-items.rs similarity index 100% rename from tests/rustdoc/intra-doc/associated-items.rs rename to tests/rustdoc-html/intra-doc/associated-items.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/empty.rs b/tests/rustdoc-html/intra-doc/auxiliary/empty.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/empty.rs rename to tests/rustdoc-html/intra-doc/auxiliary/empty.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/empty2.rs b/tests/rustdoc-html/intra-doc/auxiliary/empty2.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/empty2.rs rename to tests/rustdoc-html/intra-doc/auxiliary/empty2.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs b/tests/rustdoc-html/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs rename to tests/rustdoc-html/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/tests/rustdoc-html/intra-doc/auxiliary/extern-inherent-impl-dep.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs rename to tests/rustdoc-html/intra-doc/auxiliary/extern-inherent-impl-dep.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-extern-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-extern-crate.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-pub-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-pub-use.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs b/tests/rustdoc-html/intra-doc/auxiliary/intra-links-external-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs rename to tests/rustdoc-html/intra-doc/auxiliary/intra-links-external-traits.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/issue-66159-1.rs b/tests/rustdoc-html/intra-doc/auxiliary/issue-66159-1.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/issue-66159-1.rs rename to tests/rustdoc-html/intra-doc/auxiliary/issue-66159-1.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/my-core.rs b/tests/rustdoc-html/intra-doc/auxiliary/my-core.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/my-core.rs rename to tests/rustdoc-html/intra-doc/auxiliary/my-core.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs b/tests/rustdoc-html/intra-doc/auxiliary/proc-macro-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs rename to tests/rustdoc-html/intra-doc/auxiliary/proc-macro-macro.rs diff --git a/tests/rustdoc/intra-doc/auxiliary/pub-struct.rs b/tests/rustdoc-html/intra-doc/auxiliary/pub-struct.rs similarity index 100% rename from tests/rustdoc/intra-doc/auxiliary/pub-struct.rs rename to tests/rustdoc-html/intra-doc/auxiliary/pub-struct.rs diff --git a/tests/rustdoc/intra-doc/basic.rs b/tests/rustdoc-html/intra-doc/basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/basic.rs rename to tests/rustdoc-html/intra-doc/basic.rs diff --git a/tests/rustdoc/intra-doc/builtin-macros.rs b/tests/rustdoc-html/intra-doc/builtin-macros.rs similarity index 100% rename from tests/rustdoc/intra-doc/builtin-macros.rs rename to tests/rustdoc-html/intra-doc/builtin-macros.rs diff --git a/tests/rustdoc/intra-doc/crate-relative-assoc.rs b/tests/rustdoc-html/intra-doc/crate-relative-assoc.rs similarity index 100% rename from tests/rustdoc/intra-doc/crate-relative-assoc.rs rename to tests/rustdoc-html/intra-doc/crate-relative-assoc.rs diff --git a/tests/rustdoc/intra-doc/crate-relative.rs b/tests/rustdoc-html/intra-doc/crate-relative.rs similarity index 100% rename from tests/rustdoc/intra-doc/crate-relative.rs rename to tests/rustdoc-html/intra-doc/crate-relative.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/additional_doc.rs b/tests/rustdoc-html/intra-doc/cross-crate/additional_doc.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/additional_doc.rs rename to tests/rustdoc-html/intra-doc/cross-crate/additional_doc.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/additional_doc.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/additional_doc.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/hidden.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/hidden.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/macro_inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/macro_inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/module.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/module.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/module.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/proc_macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/proc_macro.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-outer.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/submodule-outer.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs b/tests/rustdoc-html/intra-doc/cross-crate/auxiliary/traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs rename to tests/rustdoc-html/intra-doc/cross-crate/auxiliary/traits.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/basic.rs b/tests/rustdoc-html/intra-doc/cross-crate/basic.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/basic.rs rename to tests/rustdoc-html/intra-doc/cross-crate/basic.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/crate.rs b/tests/rustdoc-html/intra-doc/cross-crate/crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/crate.rs rename to tests/rustdoc-html/intra-doc/cross-crate/crate.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/hidden.rs b/tests/rustdoc-html/intra-doc/cross-crate/hidden.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/hidden.rs rename to tests/rustdoc-html/intra-doc/cross-crate/hidden.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/macro.rs b/tests/rustdoc-html/intra-doc/cross-crate/macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/macro.rs rename to tests/rustdoc-html/intra-doc/cross-crate/macro.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/module.rs b/tests/rustdoc-html/intra-doc/cross-crate/module.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/module.rs rename to tests/rustdoc-html/intra-doc/cross-crate/module.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/tests/rustdoc-html/intra-doc/cross-crate/submodule-inner.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/submodule-inner.rs rename to tests/rustdoc-html/intra-doc/cross-crate/submodule-inner.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/tests/rustdoc-html/intra-doc/cross-crate/submodule-outer.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/submodule-outer.rs rename to tests/rustdoc-html/intra-doc/cross-crate/submodule-outer.rs diff --git a/tests/rustdoc/intra-doc/cross-crate/traits.rs b/tests/rustdoc-html/intra-doc/cross-crate/traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/cross-crate/traits.rs rename to tests/rustdoc-html/intra-doc/cross-crate/traits.rs diff --git a/tests/rustdoc/intra-doc/deps.rs b/tests/rustdoc-html/intra-doc/deps.rs similarity index 100% rename from tests/rustdoc/intra-doc/deps.rs rename to tests/rustdoc-html/intra-doc/deps.rs diff --git a/tests/rustdoc/intra-doc/disambiguators-removed.rs b/tests/rustdoc-html/intra-doc/disambiguators-removed.rs similarity index 100% rename from tests/rustdoc/intra-doc/disambiguators-removed.rs rename to tests/rustdoc-html/intra-doc/disambiguators-removed.rs diff --git a/tests/rustdoc/intra-doc/email-address.rs b/tests/rustdoc-html/intra-doc/email-address.rs similarity index 100% rename from tests/rustdoc/intra-doc/email-address.rs rename to tests/rustdoc-html/intra-doc/email-address.rs diff --git a/tests/rustdoc/intra-doc/enum-self-82209.rs b/tests/rustdoc-html/intra-doc/enum-self-82209.rs similarity index 100% rename from tests/rustdoc/intra-doc/enum-self-82209.rs rename to tests/rustdoc-html/intra-doc/enum-self-82209.rs diff --git a/tests/rustdoc/intra-doc/enum-struct-field.rs b/tests/rustdoc-html/intra-doc/enum-struct-field.rs similarity index 100% rename from tests/rustdoc/intra-doc/enum-struct-field.rs rename to tests/rustdoc-html/intra-doc/enum-struct-field.rs diff --git a/tests/rustdoc/intra-doc/extern-builtin-type-impl.rs b/tests/rustdoc-html/intra-doc/extern-builtin-type-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-builtin-type-impl.rs rename to tests/rustdoc-html/intra-doc/extern-builtin-type-impl.rs diff --git a/tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/tests/rustdoc-html/intra-doc/extern-crate-only-used-in-link.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-crate-only-used-in-link.rs rename to tests/rustdoc-html/intra-doc/extern-crate-only-used-in-link.rs diff --git a/tests/rustdoc/intra-doc/extern-crate.rs b/tests/rustdoc-html/intra-doc/extern-crate.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-crate.rs rename to tests/rustdoc-html/intra-doc/extern-crate.rs diff --git a/tests/rustdoc/intra-doc/extern-inherent-impl.rs b/tests/rustdoc-html/intra-doc/extern-inherent-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-inherent-impl.rs rename to tests/rustdoc-html/intra-doc/extern-inherent-impl.rs diff --git a/tests/rustdoc/intra-doc/extern-reference-link.rs b/tests/rustdoc-html/intra-doc/extern-reference-link.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-reference-link.rs rename to tests/rustdoc-html/intra-doc/extern-reference-link.rs diff --git a/tests/rustdoc/intra-doc/extern-type.rs b/tests/rustdoc-html/intra-doc/extern-type.rs similarity index 100% rename from tests/rustdoc/intra-doc/extern-type.rs rename to tests/rustdoc-html/intra-doc/extern-type.rs diff --git a/tests/rustdoc/intra-doc/external-traits.rs b/tests/rustdoc-html/intra-doc/external-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/external-traits.rs rename to tests/rustdoc-html/intra-doc/external-traits.rs diff --git a/tests/rustdoc/intra-doc/field.rs b/tests/rustdoc-html/intra-doc/field.rs similarity index 100% rename from tests/rustdoc/intra-doc/field.rs rename to tests/rustdoc-html/intra-doc/field.rs diff --git a/tests/rustdoc/intra-doc/filter-out-private.rs b/tests/rustdoc-html/intra-doc/filter-out-private.rs similarity index 100% rename from tests/rustdoc/intra-doc/filter-out-private.rs rename to tests/rustdoc-html/intra-doc/filter-out-private.rs diff --git a/tests/rustdoc/intra-doc/generic-params.rs b/tests/rustdoc-html/intra-doc/generic-params.rs similarity index 100% rename from tests/rustdoc/intra-doc/generic-params.rs rename to tests/rustdoc-html/intra-doc/generic-params.rs diff --git a/tests/rustdoc/intra-doc/generic-trait-impl.rs b/tests/rustdoc-html/intra-doc/generic-trait-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/generic-trait-impl.rs rename to tests/rustdoc-html/intra-doc/generic-trait-impl.rs diff --git a/tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs b/tests/rustdoc-html/intra-doc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs rename to tests/rustdoc-html/intra-doc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/intra-doc/in-bodies.rs b/tests/rustdoc-html/intra-doc/in-bodies.rs similarity index 100% rename from tests/rustdoc/intra-doc/in-bodies.rs rename to tests/rustdoc-html/intra-doc/in-bodies.rs diff --git a/tests/rustdoc/intra-doc/inherent-associated-types.rs b/tests/rustdoc-html/intra-doc/inherent-associated-types.rs similarity index 100% rename from tests/rustdoc/intra-doc/inherent-associated-types.rs rename to tests/rustdoc-html/intra-doc/inherent-associated-types.rs diff --git a/tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs b/tests/rustdoc-html/intra-doc/intra-doc-link-method-trait-impl-72340.rs similarity index 100% rename from tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs rename to tests/rustdoc-html/intra-doc/intra-doc-link-method-trait-impl-72340.rs diff --git a/tests/rustdoc/intra-doc/libstd-re-export.rs b/tests/rustdoc-html/intra-doc/libstd-re-export.rs similarity index 100% rename from tests/rustdoc/intra-doc/libstd-re-export.rs rename to tests/rustdoc-html/intra-doc/libstd-re-export.rs diff --git a/tests/rustdoc/intra-doc/link-in-footnotes-132208.rs b/tests/rustdoc-html/intra-doc/link-in-footnotes-132208.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-in-footnotes-132208.rs rename to tests/rustdoc-html/intra-doc/link-in-footnotes-132208.rs diff --git a/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs b/tests/rustdoc-html/intra-doc/link-same-name-different-disambiguator-108459.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs rename to tests/rustdoc-html/intra-doc/link-same-name-different-disambiguator-108459.rs diff --git a/tests/rustdoc/intra-doc/link-to-proc-macro.rs b/tests/rustdoc-html/intra-doc/link-to-proc-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/link-to-proc-macro.rs rename to tests/rustdoc-html/intra-doc/link-to-proc-macro.rs diff --git a/tests/rustdoc/intra-doc/macro-caching-144965.rs b/tests/rustdoc-html/intra-doc/macro-caching-144965.rs similarity index 100% rename from tests/rustdoc/intra-doc/macro-caching-144965.rs rename to tests/rustdoc-html/intra-doc/macro-caching-144965.rs diff --git a/tests/rustdoc/intra-doc/macros-disambiguators.rs b/tests/rustdoc-html/intra-doc/macros-disambiguators.rs similarity index 100% rename from tests/rustdoc/intra-doc/macros-disambiguators.rs rename to tests/rustdoc-html/intra-doc/macros-disambiguators.rs diff --git a/tests/rustdoc/intra-doc/mod-ambiguity.rs b/tests/rustdoc-html/intra-doc/mod-ambiguity.rs similarity index 100% rename from tests/rustdoc/intra-doc/mod-ambiguity.rs rename to tests/rustdoc-html/intra-doc/mod-ambiguity.rs diff --git a/tests/rustdoc/intra-doc/mod-relative.rs b/tests/rustdoc-html/intra-doc/mod-relative.rs similarity index 100% rename from tests/rustdoc/intra-doc/mod-relative.rs rename to tests/rustdoc-html/intra-doc/mod-relative.rs diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc-html/intra-doc/module-scope-name-resolution-55364.rs similarity index 100% rename from tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs rename to tests/rustdoc-html/intra-doc/module-scope-name-resolution-55364.rs diff --git a/tests/rustdoc/intra-doc/nested-use.rs b/tests/rustdoc-html/intra-doc/nested-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/nested-use.rs rename to tests/rustdoc-html/intra-doc/nested-use.rs diff --git a/tests/rustdoc/intra-doc/no-doc-primitive.rs b/tests/rustdoc-html/intra-doc/no-doc-primitive.rs similarity index 100% rename from tests/rustdoc/intra-doc/no-doc-primitive.rs rename to tests/rustdoc-html/intra-doc/no-doc-primitive.rs diff --git a/tests/rustdoc/intra-doc/non-path-primitives.rs b/tests/rustdoc-html/intra-doc/non-path-primitives.rs similarity index 100% rename from tests/rustdoc/intra-doc/non-path-primitives.rs rename to tests/rustdoc-html/intra-doc/non-path-primitives.rs diff --git a/tests/rustdoc/intra-doc/prim-assoc.rs b/tests/rustdoc-html/intra-doc/prim-assoc.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-assoc.rs rename to tests/rustdoc-html/intra-doc/prim-assoc.rs diff --git a/tests/rustdoc/intra-doc/prim-associated-traits.rs b/tests/rustdoc-html/intra-doc/prim-associated-traits.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-associated-traits.rs rename to tests/rustdoc-html/intra-doc/prim-associated-traits.rs diff --git a/tests/rustdoc/intra-doc/prim-methods-external-core.rs b/tests/rustdoc-html/intra-doc/prim-methods-external-core.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods-external-core.rs rename to tests/rustdoc-html/intra-doc/prim-methods-external-core.rs diff --git a/tests/rustdoc/intra-doc/prim-methods-local.rs b/tests/rustdoc-html/intra-doc/prim-methods-local.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods-local.rs rename to tests/rustdoc-html/intra-doc/prim-methods-local.rs diff --git a/tests/rustdoc/intra-doc/prim-methods.rs b/tests/rustdoc-html/intra-doc/prim-methods.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-methods.rs rename to tests/rustdoc-html/intra-doc/prim-methods.rs diff --git a/tests/rustdoc/intra-doc/prim-precedence.rs b/tests/rustdoc-html/intra-doc/prim-precedence.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-precedence.rs rename to tests/rustdoc-html/intra-doc/prim-precedence.rs diff --git a/tests/rustdoc/intra-doc/prim-self.rs b/tests/rustdoc-html/intra-doc/prim-self.rs similarity index 100% rename from tests/rustdoc/intra-doc/prim-self.rs rename to tests/rustdoc-html/intra-doc/prim-self.rs diff --git a/tests/rustdoc/intra-doc/primitive-disambiguators.rs b/tests/rustdoc-html/intra-doc/primitive-disambiguators.rs similarity index 100% rename from tests/rustdoc/intra-doc/primitive-disambiguators.rs rename to tests/rustdoc-html/intra-doc/primitive-disambiguators.rs diff --git a/tests/rustdoc/intra-doc/primitive-non-default-impl.rs b/tests/rustdoc-html/intra-doc/primitive-non-default-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/primitive-non-default-impl.rs rename to tests/rustdoc-html/intra-doc/primitive-non-default-impl.rs diff --git a/tests/rustdoc/intra-doc/private-failures-ignored.rs b/tests/rustdoc-html/intra-doc/private-failures-ignored.rs similarity index 100% rename from tests/rustdoc/intra-doc/private-failures-ignored.rs rename to tests/rustdoc-html/intra-doc/private-failures-ignored.rs diff --git a/tests/rustdoc/intra-doc/private.rs b/tests/rustdoc-html/intra-doc/private.rs similarity index 100% rename from tests/rustdoc/intra-doc/private.rs rename to tests/rustdoc-html/intra-doc/private.rs diff --git a/tests/rustdoc/intra-doc/proc-macro.rs b/tests/rustdoc-html/intra-doc/proc-macro.rs similarity index 100% rename from tests/rustdoc/intra-doc/proc-macro.rs rename to tests/rustdoc-html/intra-doc/proc-macro.rs diff --git a/tests/rustdoc/intra-doc/pub-use.rs b/tests/rustdoc-html/intra-doc/pub-use.rs similarity index 100% rename from tests/rustdoc/intra-doc/pub-use.rs rename to tests/rustdoc-html/intra-doc/pub-use.rs diff --git a/tests/rustdoc/intra-doc/raw-ident-self.rs b/tests/rustdoc-html/intra-doc/raw-ident-self.rs similarity index 100% rename from tests/rustdoc/intra-doc/raw-ident-self.rs rename to tests/rustdoc-html/intra-doc/raw-ident-self.rs diff --git a/tests/rustdoc/intra-doc/reexport-additional-docs.rs b/tests/rustdoc-html/intra-doc/reexport-additional-docs.rs similarity index 100% rename from tests/rustdoc/intra-doc/reexport-additional-docs.rs rename to tests/rustdoc-html/intra-doc/reexport-additional-docs.rs diff --git a/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs b/tests/rustdoc-html/intra-doc/same-name-different-crates-66159.rs similarity index 100% rename from tests/rustdoc/intra-doc/same-name-different-crates-66159.rs rename to tests/rustdoc-html/intra-doc/same-name-different-crates-66159.rs diff --git a/tests/rustdoc/intra-doc/self-cache.rs b/tests/rustdoc-html/intra-doc/self-cache.rs similarity index 100% rename from tests/rustdoc/intra-doc/self-cache.rs rename to tests/rustdoc-html/intra-doc/self-cache.rs diff --git a/tests/rustdoc/intra-doc/self.rs b/tests/rustdoc-html/intra-doc/self.rs similarity index 100% rename from tests/rustdoc/intra-doc/self.rs rename to tests/rustdoc-html/intra-doc/self.rs diff --git a/tests/rustdoc/intra-doc/trait-impl.rs b/tests/rustdoc-html/intra-doc/trait-impl.rs similarity index 100% rename from tests/rustdoc/intra-doc/trait-impl.rs rename to tests/rustdoc-html/intra-doc/trait-impl.rs diff --git a/tests/rustdoc/intra-doc/trait-item.rs b/tests/rustdoc-html/intra-doc/trait-item.rs similarity index 100% rename from tests/rustdoc/intra-doc/trait-item.rs rename to tests/rustdoc-html/intra-doc/trait-item.rs diff --git a/tests/rustdoc/intra-doc/true-false.rs b/tests/rustdoc-html/intra-doc/true-false.rs similarity index 100% rename from tests/rustdoc/intra-doc/true-false.rs rename to tests/rustdoc-html/intra-doc/true-false.rs diff --git a/tests/rustdoc/intra-doc/type-alias-primitive.rs b/tests/rustdoc-html/intra-doc/type-alias-primitive.rs similarity index 100% rename from tests/rustdoc/intra-doc/type-alias-primitive.rs rename to tests/rustdoc-html/intra-doc/type-alias-primitive.rs diff --git a/tests/rustdoc/intra-doc/type-alias.rs b/tests/rustdoc-html/intra-doc/type-alias.rs similarity index 100% rename from tests/rustdoc/intra-doc/type-alias.rs rename to tests/rustdoc-html/intra-doc/type-alias.rs diff --git a/tests/rustdoc/invalid$crate$name.rs b/tests/rustdoc-html/invalid$crate$name.rs similarity index 100% rename from tests/rustdoc/invalid$crate$name.rs rename to tests/rustdoc-html/invalid$crate$name.rs diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc-html/item-desc-list-at-start.item-table.html similarity index 100% rename from tests/rustdoc/item-desc-list-at-start.item-table.html rename to tests/rustdoc-html/item-desc-list-at-start.item-table.html diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc-html/item-desc-list-at-start.rs similarity index 100% rename from tests/rustdoc/item-desc-list-at-start.rs rename to tests/rustdoc-html/item-desc-list-at-start.rs diff --git a/tests/rustdoc/jump-to-def/assoc-items.rs b/tests/rustdoc-html/jump-to-def/assoc-items.rs similarity index 100% rename from tests/rustdoc/jump-to-def/assoc-items.rs rename to tests/rustdoc-html/jump-to-def/assoc-items.rs diff --git a/tests/rustdoc/jump-to-def/assoc-types.rs b/tests/rustdoc-html/jump-to-def/assoc-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def/assoc-types.rs rename to tests/rustdoc-html/jump-to-def/assoc-types.rs diff --git a/tests/rustdoc/jump-to-def/auxiliary/symbols.rs b/tests/rustdoc-html/jump-to-def/auxiliary/symbols.rs similarity index 100% rename from tests/rustdoc/jump-to-def/auxiliary/symbols.rs rename to tests/rustdoc-html/jump-to-def/auxiliary/symbols.rs diff --git a/tests/rustdoc/jump-to-def/derive-macro.rs b/tests/rustdoc-html/jump-to-def/derive-macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def/derive-macro.rs rename to tests/rustdoc-html/jump-to-def/derive-macro.rs diff --git a/tests/rustdoc/jump-to-def/doc-links-calls.rs b/tests/rustdoc-html/jump-to-def/doc-links-calls.rs similarity index 100% rename from tests/rustdoc/jump-to-def/doc-links-calls.rs rename to tests/rustdoc-html/jump-to-def/doc-links-calls.rs diff --git a/tests/rustdoc/jump-to-def/doc-links.rs b/tests/rustdoc-html/jump-to-def/doc-links.rs similarity index 100% rename from tests/rustdoc/jump-to-def/doc-links.rs rename to tests/rustdoc-html/jump-to-def/doc-links.rs diff --git a/tests/rustdoc/jump-to-def/macro.rs b/tests/rustdoc-html/jump-to-def/macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def/macro.rs rename to tests/rustdoc-html/jump-to-def/macro.rs diff --git a/tests/rustdoc/jump-to-def/no-body-items.rs b/tests/rustdoc-html/jump-to-def/no-body-items.rs similarity index 100% rename from tests/rustdoc/jump-to-def/no-body-items.rs rename to tests/rustdoc-html/jump-to-def/no-body-items.rs diff --git a/tests/rustdoc/jump-to-def/non-local-method.rs b/tests/rustdoc-html/jump-to-def/non-local-method.rs similarity index 100% rename from tests/rustdoc/jump-to-def/non-local-method.rs rename to tests/rustdoc-html/jump-to-def/non-local-method.rs diff --git a/tests/rustdoc/jump-to-def/patterns.rs b/tests/rustdoc-html/jump-to-def/patterns.rs similarity index 100% rename from tests/rustdoc/jump-to-def/patterns.rs rename to tests/rustdoc-html/jump-to-def/patterns.rs diff --git a/tests/rustdoc/jump-to-def/prelude-types.rs b/tests/rustdoc-html/jump-to-def/prelude-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def/prelude-types.rs rename to tests/rustdoc-html/jump-to-def/prelude-types.rs diff --git a/tests/rustdoc/jump-to-def/shebang.rs b/tests/rustdoc-html/jump-to-def/shebang.rs similarity index 100% rename from tests/rustdoc/jump-to-def/shebang.rs rename to tests/rustdoc-html/jump-to-def/shebang.rs diff --git a/tests/rustdoc/keyword.rs b/tests/rustdoc-html/keyword.rs similarity index 100% rename from tests/rustdoc/keyword.rs rename to tests/rustdoc-html/keyword.rs diff --git a/tests/rustdoc/lifetime-name.rs b/tests/rustdoc-html/lifetime-name.rs similarity index 100% rename from tests/rustdoc/lifetime-name.rs rename to tests/rustdoc-html/lifetime-name.rs diff --git a/tests/rustdoc/line-breaks.rs b/tests/rustdoc-html/line-breaks.rs similarity index 100% rename from tests/rustdoc/line-breaks.rs rename to tests/rustdoc-html/line-breaks.rs diff --git a/tests/rustdoc/link-on-path-with-generics.rs b/tests/rustdoc-html/link-on-path-with-generics.rs similarity index 100% rename from tests/rustdoc/link-on-path-with-generics.rs rename to tests/rustdoc-html/link-on-path-with-generics.rs diff --git a/tests/rustdoc/link-title-escape.rs b/tests/rustdoc-html/link-title-escape.rs similarity index 100% rename from tests/rustdoc/link-title-escape.rs rename to tests/rustdoc-html/link-title-escape.rs diff --git a/tests/rustdoc/links-in-headings.rs b/tests/rustdoc-html/links-in-headings.rs similarity index 100% rename from tests/rustdoc/links-in-headings.rs rename to tests/rustdoc-html/links-in-headings.rs diff --git a/tests/rustdoc/logo-class-default.rs b/tests/rustdoc-html/logo-class-default.rs similarity index 100% rename from tests/rustdoc/logo-class-default.rs rename to tests/rustdoc-html/logo-class-default.rs diff --git a/tests/rustdoc/logo-class-rust.rs b/tests/rustdoc-html/logo-class-rust.rs similarity index 100% rename from tests/rustdoc/logo-class-rust.rs rename to tests/rustdoc-html/logo-class-rust.rs diff --git a/tests/rustdoc/logo-class.rs b/tests/rustdoc-html/logo-class.rs similarity index 100% rename from tests/rustdoc/logo-class.rs rename to tests/rustdoc-html/logo-class.rs diff --git a/tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs b/tests/rustdoc-html/macro-expansion/field-followed-by-exclamation.rs similarity index 100% rename from tests/rustdoc/macro-expansion/field-followed-by-exclamation.rs rename to tests/rustdoc-html/macro-expansion/field-followed-by-exclamation.rs diff --git a/tests/rustdoc/macro-expansion/type-macro-expansion.rs b/tests/rustdoc-html/macro-expansion/type-macro-expansion.rs similarity index 100% rename from tests/rustdoc/macro-expansion/type-macro-expansion.rs rename to tests/rustdoc-html/macro-expansion/type-macro-expansion.rs diff --git a/tests/rustdoc/macro/auxiliary/external-macro-src.rs b/tests/rustdoc-html/macro/auxiliary/external-macro-src.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/external-macro-src.rs rename to tests/rustdoc-html/macro/auxiliary/external-macro-src.rs diff --git a/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs b/tests/rustdoc-html/macro/auxiliary/issue-99221-aux.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/issue-99221-aux.rs rename to tests/rustdoc-html/macro/auxiliary/issue-99221-aux.rs diff --git a/tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs b/tests/rustdoc-html/macro/auxiliary/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs rename to tests/rustdoc-html/macro/auxiliary/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro/auxiliary/one-line-expand.rs b/tests/rustdoc-html/macro/auxiliary/one-line-expand.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/one-line-expand.rs rename to tests/rustdoc-html/macro/auxiliary/one-line-expand.rs diff --git a/tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs b/tests/rustdoc-html/macro/auxiliary/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs rename to tests/rustdoc-html/macro/auxiliary/pub-use-extern-macros.rs diff --git a/tests/rustdoc/macro/compiler-derive-proc-macro.rs b/tests/rustdoc-html/macro/compiler-derive-proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/compiler-derive-proc-macro.rs rename to tests/rustdoc-html/macro/compiler-derive-proc-macro.rs diff --git a/tests/rustdoc/macro/const-rendering-macros-33302.rs b/tests/rustdoc-html/macro/const-rendering-macros-33302.rs similarity index 100% rename from tests/rustdoc/macro/const-rendering-macros-33302.rs rename to tests/rustdoc-html/macro/const-rendering-macros-33302.rs diff --git a/tests/rustdoc/macro/decl_macro.rs b/tests/rustdoc-html/macro/decl_macro.rs similarity index 100% rename from tests/rustdoc/macro/decl_macro.rs rename to tests/rustdoc-html/macro/decl_macro.rs diff --git a/tests/rustdoc/macro/decl_macro_priv.rs b/tests/rustdoc-html/macro/decl_macro_priv.rs similarity index 100% rename from tests/rustdoc/macro/decl_macro_priv.rs rename to tests/rustdoc-html/macro/decl_macro_priv.rs diff --git a/tests/rustdoc/macro/doc-proc-macro.rs b/tests/rustdoc-html/macro/doc-proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/doc-proc-macro.rs rename to tests/rustdoc-html/macro/doc-proc-macro.rs diff --git a/tests/rustdoc/macro/external-macro-src.rs b/tests/rustdoc-html/macro/external-macro-src.rs similarity index 100% rename from tests/rustdoc/macro/external-macro-src.rs rename to tests/rustdoc-html/macro/external-macro-src.rs diff --git a/tests/rustdoc/macro/macro-const-display-115295.rs b/tests/rustdoc-html/macro/macro-const-display-115295.rs similarity index 100% rename from tests/rustdoc/macro/macro-const-display-115295.rs rename to tests/rustdoc-html/macro/macro-const-display-115295.rs diff --git a/tests/rustdoc/macro/macro-doc-comment-23812.rs b/tests/rustdoc-html/macro/macro-doc-comment-23812.rs similarity index 100% rename from tests/rustdoc/macro/macro-doc-comment-23812.rs rename to tests/rustdoc-html/macro/macro-doc-comment-23812.rs diff --git a/tests/rustdoc/macro/macro-export-crate-root-108231.rs b/tests/rustdoc-html/macro/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/macro/macro-export-crate-root-108231.rs rename to tests/rustdoc-html/macro/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html b/tests/rustdoc-html/macro/macro-generated-macro.macro_linebreak_pre.html similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html rename to tests/rustdoc-html/macro/macro-generated-macro.macro_linebreak_pre.html diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc-html/macro/macro-generated-macro.macro_morestuff_pre.html similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html rename to tests/rustdoc-html/macro/macro-generated-macro.macro_morestuff_pre.html diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc-html/macro/macro-generated-macro.rs similarity index 100% rename from tests/rustdoc/macro/macro-generated-macro.rs rename to tests/rustdoc-html/macro/macro-generated-macro.rs diff --git a/tests/rustdoc/macro/macro-higher-kinded-function.rs b/tests/rustdoc-html/macro/macro-higher-kinded-function.rs similarity index 100% rename from tests/rustdoc/macro/macro-higher-kinded-function.rs rename to tests/rustdoc-html/macro/macro-higher-kinded-function.rs diff --git a/tests/rustdoc/macro/macro-ice-16019.rs b/tests/rustdoc-html/macro/macro-ice-16019.rs similarity index 100% rename from tests/rustdoc/macro/macro-ice-16019.rs rename to tests/rustdoc-html/macro/macro-ice-16019.rs diff --git a/tests/rustdoc/macro/macro-in-async-block.rs b/tests/rustdoc-html/macro/macro-in-async-block.rs similarity index 100% rename from tests/rustdoc/macro/macro-in-async-block.rs rename to tests/rustdoc-html/macro/macro-in-async-block.rs diff --git a/tests/rustdoc/macro/macro-in-closure.rs b/tests/rustdoc-html/macro/macro-in-closure.rs similarity index 100% rename from tests/rustdoc/macro/macro-in-closure.rs rename to tests/rustdoc-html/macro/macro-in-closure.rs diff --git a/tests/rustdoc/macro/macro-indirect-use.rs b/tests/rustdoc-html/macro/macro-indirect-use.rs similarity index 100% rename from tests/rustdoc/macro/macro-indirect-use.rs rename to tests/rustdoc-html/macro/macro-indirect-use.rs diff --git a/tests/rustdoc/macro/macro_expansion.rs b/tests/rustdoc-html/macro/macro_expansion.rs similarity index 100% rename from tests/rustdoc/macro/macro_expansion.rs rename to tests/rustdoc-html/macro/macro_expansion.rs diff --git a/tests/rustdoc/macro/macro_pub_in_module.rs b/tests/rustdoc-html/macro/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro/macro_pub_in_module.rs rename to tests/rustdoc-html/macro/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro/macro_rules-matchers.rs b/tests/rustdoc-html/macro/macro_rules-matchers.rs similarity index 100% rename from tests/rustdoc/macro/macro_rules-matchers.rs rename to tests/rustdoc-html/macro/macro_rules-matchers.rs diff --git a/tests/rustdoc/macro/macros.rs b/tests/rustdoc-html/macro/macros.rs similarity index 100% rename from tests/rustdoc/macro/macros.rs rename to tests/rustdoc-html/macro/macros.rs diff --git a/tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs b/tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs rename to tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-99221.rs diff --git a/tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs b/tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-submodule-99221.rs similarity index 100% rename from tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs rename to tests/rustdoc-html/macro/multiple-macro-rules-w-same-name-submodule-99221.rs diff --git a/tests/rustdoc/macro/one-line-expand.rs b/tests/rustdoc-html/macro/one-line-expand.rs similarity index 100% rename from tests/rustdoc/macro/one-line-expand.rs rename to tests/rustdoc-html/macro/one-line-expand.rs diff --git a/tests/rustdoc/macro/proc-macro.rs b/tests/rustdoc-html/macro/proc-macro.rs similarity index 100% rename from tests/rustdoc/macro/proc-macro.rs rename to tests/rustdoc-html/macro/proc-macro.rs diff --git a/tests/rustdoc/macro/pub-use-extern-macros.rs b/tests/rustdoc-html/macro/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/macro/pub-use-extern-macros.rs rename to tests/rustdoc-html/macro/pub-use-extern-macros.rs diff --git a/tests/rustdoc/macro/rustc-macro-crate.rs b/tests/rustdoc-html/macro/rustc-macro-crate.rs similarity index 100% rename from tests/rustdoc/macro/rustc-macro-crate.rs rename to tests/rustdoc-html/macro/rustc-macro-crate.rs diff --git a/tests/rustdoc/markdown-60482.rs b/tests/rustdoc-html/markdown-60482.rs similarity index 100% rename from tests/rustdoc/markdown-60482.rs rename to tests/rustdoc-html/markdown-60482.rs diff --git a/tests/rustdoc/markdown-table-escape-pipe-27862.rs b/tests/rustdoc-html/markdown-table-escape-pipe-27862.rs similarity index 100% rename from tests/rustdoc/markdown-table-escape-pipe-27862.rs rename to tests/rustdoc-html/markdown-table-escape-pipe-27862.rs diff --git a/tests/rustdoc/masked.rs b/tests/rustdoc-html/masked.rs similarity index 100% rename from tests/rustdoc/masked.rs rename to tests/rustdoc-html/masked.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/cargo-transitive-read-write/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/romeo.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs b/tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs rename to tests/rustdoc-html/merge-cross-crate-info/kitchen-sink-separate-dirs/indigo.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-separate/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-separate/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/no-merge-write-anyway/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/no-merge-write-anyway/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-include/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-include/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite-but-separate/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite-but-separate/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/overwrite/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/overwrite/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/overwrite/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-finalize/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-finalize/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-finalize/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-read-write/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-read-write/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-read-write/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-crate-write-anyway/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-crate-write-anyway/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-crate-write-anyway/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/single-merge-none-useless-write/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-finalize/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-finalize/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-none/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-none/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-merge-read-write/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-merge-read-write/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/quebec.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/auxiliary/tango.rs diff --git a/tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs b/tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/sierra.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/transitive-no-info/sierra.rs rename to tests/rustdoc-html/merge-cross-crate-info/transitive-no-info/sierra.rs diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs b/tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs rename to tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/auxiliary/foxtrot.rs diff --git a/tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs b/tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/echo.rs similarity index 100% rename from tests/rustdoc/merge-cross-crate-info/two-separate-out-dir/echo.rs rename to tests/rustdoc-html/merge-cross-crate-info/two-separate-out-dir/echo.rs diff --git a/tests/rustdoc/method-list.rs b/tests/rustdoc-html/method-list.rs similarity index 100% rename from tests/rustdoc/method-list.rs rename to tests/rustdoc-html/method-list.rs diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S1_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S1_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S2_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S2_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S2_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html b/tests/rustdoc-html/mixing-doc-comments-and-attrs.S3_top-doc.html similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.S3_top-doc.html diff --git a/tests/rustdoc/mixing-doc-comments-and-attrs.rs b/tests/rustdoc-html/mixing-doc-comments-and-attrs.rs similarity index 100% rename from tests/rustdoc/mixing-doc-comments-and-attrs.rs rename to tests/rustdoc-html/mixing-doc-comments-and-attrs.rs diff --git a/tests/rustdoc/mod-stackoverflow.rs b/tests/rustdoc-html/mod-stackoverflow.rs similarity index 100% rename from tests/rustdoc/mod-stackoverflow.rs rename to tests/rustdoc-html/mod-stackoverflow.rs diff --git a/tests/rustdoc/multiple-foreigns-w-same-name-99734.rs b/tests/rustdoc-html/multiple-foreigns-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/multiple-foreigns-w-same-name-99734.rs rename to tests/rustdoc-html/multiple-foreigns-w-same-name-99734.rs diff --git a/tests/rustdoc/multiple-import-levels.rs b/tests/rustdoc-html/multiple-import-levels.rs similarity index 100% rename from tests/rustdoc/multiple-import-levels.rs rename to tests/rustdoc-html/multiple-import-levels.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-99734.rs b/tests/rustdoc-html/multiple-mods-w-same-name-99734.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-99734.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-99734.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs b/tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-83375.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-83375.rs diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs b/tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-last-item-83375.rs similarity index 100% rename from tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs rename to tests/rustdoc-html/multiple-mods-w-same-name-doc-inline-last-item-83375.rs diff --git a/tests/rustdoc/multiple-structs-w-same-name-99221.rs b/tests/rustdoc-html/multiple-structs-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/multiple-structs-w-same-name-99221.rs rename to tests/rustdoc-html/multiple-structs-w-same-name-99221.rs diff --git a/tests/rustdoc/mut-params.rs b/tests/rustdoc-html/mut-params.rs similarity index 100% rename from tests/rustdoc/mut-params.rs rename to tests/rustdoc-html/mut-params.rs diff --git a/tests/rustdoc/namespaces.rs b/tests/rustdoc-html/namespaces.rs similarity index 100% rename from tests/rustdoc/namespaces.rs rename to tests/rustdoc-html/namespaces.rs diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc-html/nested-items-issue-111415.rs similarity index 100% rename from tests/rustdoc/nested-items-issue-111415.rs rename to tests/rustdoc-html/nested-items-issue-111415.rs diff --git a/tests/rustdoc/nested-modules.rs b/tests/rustdoc-html/nested-modules.rs similarity index 100% rename from tests/rustdoc/nested-modules.rs rename to tests/rustdoc-html/nested-modules.rs diff --git a/tests/rustdoc/no-run-still-checks-lints.rs b/tests/rustdoc-html/no-run-still-checks-lints.rs similarity index 100% rename from tests/rustdoc/no-run-still-checks-lints.rs rename to tests/rustdoc-html/no-run-still-checks-lints.rs diff --git a/tests/rustdoc/no-stack-overflow-25295.rs b/tests/rustdoc-html/no-stack-overflow-25295.rs similarity index 100% rename from tests/rustdoc/no-stack-overflow-25295.rs rename to tests/rustdoc-html/no-stack-overflow-25295.rs diff --git a/tests/rustdoc/no-unit-struct-field.rs b/tests/rustdoc-html/no-unit-struct-field.rs similarity index 100% rename from tests/rustdoc/no-unit-struct-field.rs rename to tests/rustdoc-html/no-unit-struct-field.rs diff --git a/tests/rustdoc/non_lifetime_binders.rs b/tests/rustdoc-html/non_lifetime_binders.rs similarity index 100% rename from tests/rustdoc/non_lifetime_binders.rs rename to tests/rustdoc-html/non_lifetime_binders.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.negative.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.negative.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.positive.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.positive.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-negative.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-negative.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-negative.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc-html/notable-trait/doc-notable_trait-slice.bare_fn_matches.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait-slice.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait-slice.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait-slice.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.bare-fn.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.some-struct-new.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html b/tests/rustdoc-html/notable-trait/doc-notable_trait.wrap-me.html similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html rename to tests/rustdoc-html/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc-html/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs similarity index 100% rename from tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs rename to tests/rustdoc-html/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc-html/notable-trait/notable-trait-generics.rs similarity index 100% rename from tests/rustdoc/notable-trait/notable-trait-generics.rs rename to tests/rustdoc-html/notable-trait/notable-trait-generics.rs diff --git a/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html b/tests/rustdoc-html/notable-trait/spotlight-from-dependency.odd.html similarity index 100% rename from tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html rename to tests/rustdoc-html/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/notable-trait/spotlight-from-dependency.rs b/tests/rustdoc-html/notable-trait/spotlight-from-dependency.rs similarity index 100% rename from tests/rustdoc/notable-trait/spotlight-from-dependency.rs rename to tests/rustdoc-html/notable-trait/spotlight-from-dependency.rs diff --git a/tests/rustdoc/nul-error.rs b/tests/rustdoc-html/nul-error.rs similarity index 100% rename from tests/rustdoc/nul-error.rs rename to tests/rustdoc-html/nul-error.rs diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc-html/playground-arg.rs similarity index 100% rename from tests/rustdoc/playground-arg.rs rename to tests/rustdoc-html/playground-arg.rs diff --git a/tests/rustdoc/playground-empty.rs b/tests/rustdoc-html/playground-empty.rs similarity index 100% rename from tests/rustdoc/playground-empty.rs rename to tests/rustdoc-html/playground-empty.rs diff --git a/tests/rustdoc/playground-none.rs b/tests/rustdoc-html/playground-none.rs similarity index 100% rename from tests/rustdoc/playground-none.rs rename to tests/rustdoc-html/playground-none.rs diff --git a/tests/rustdoc/playground-syntax-error.rs b/tests/rustdoc-html/playground-syntax-error.rs similarity index 100% rename from tests/rustdoc/playground-syntax-error.rs rename to tests/rustdoc-html/playground-syntax-error.rs diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc-html/playground.rs similarity index 100% rename from tests/rustdoc/playground.rs rename to tests/rustdoc-html/playground.rs diff --git a/tests/rustdoc/primitive/auxiliary/issue-15318.rs b/tests/rustdoc-html/primitive/auxiliary/issue-15318.rs similarity index 100% rename from tests/rustdoc/primitive/auxiliary/issue-15318.rs rename to tests/rustdoc-html/primitive/auxiliary/issue-15318.rs diff --git a/tests/rustdoc/primitive/auxiliary/primitive-doc.rs b/tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs similarity index 100% rename from tests/rustdoc/primitive/auxiliary/primitive-doc.rs rename to tests/rustdoc-html/primitive/auxiliary/primitive-doc.rs diff --git a/tests/rustdoc/primitive/cross-crate-primitive-doc.rs b/tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs similarity index 100% rename from tests/rustdoc/primitive/cross-crate-primitive-doc.rs rename to tests/rustdoc-html/primitive/cross-crate-primitive-doc.rs diff --git a/tests/rustdoc/primitive/no_std-primitive.rs b/tests/rustdoc-html/primitive/no_std-primitive.rs similarity index 100% rename from tests/rustdoc/primitive/no_std-primitive.rs rename to tests/rustdoc-html/primitive/no_std-primitive.rs diff --git a/tests/rustdoc/primitive/no_std.rs b/tests/rustdoc-html/primitive/no_std.rs similarity index 100% rename from tests/rustdoc/primitive/no_std.rs rename to tests/rustdoc-html/primitive/no_std.rs diff --git a/tests/rustdoc/primitive/primitive-generic-impl.rs b/tests/rustdoc-html/primitive/primitive-generic-impl.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-generic-impl.rs rename to tests/rustdoc-html/primitive/primitive-generic-impl.rs diff --git a/tests/rustdoc/primitive/primitive-link.rs b/tests/rustdoc-html/primitive/primitive-link.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-link.rs rename to tests/rustdoc-html/primitive/primitive-link.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-dox-15318-3.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-15318.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-link-15318.rs diff --git a/tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs b/tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs rename to tests/rustdoc-html/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs diff --git a/tests/rustdoc/primitive/primitive-reference.rs b/tests/rustdoc-html/primitive/primitive-reference.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-reference.rs rename to tests/rustdoc-html/primitive/primitive-reference.rs diff --git a/tests/rustdoc/primitive/primitive-slice-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-slice-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-slice-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive-tuple-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-tuple-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-tuple-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive-tuple-variadic.rs b/tests/rustdoc-html/primitive/primitive-tuple-variadic.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-tuple-variadic.rs rename to tests/rustdoc-html/primitive/primitive-tuple-variadic.rs diff --git a/tests/rustdoc/primitive/primitive-unit-auto-trait.rs b/tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive/primitive-unit-auto-trait.rs rename to tests/rustdoc-html/primitive/primitive-unit-auto-trait.rs diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc-html/primitive/primitive.rs similarity index 100% rename from tests/rustdoc/primitive/primitive.rs rename to tests/rustdoc-html/primitive/primitive.rs diff --git a/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs similarity index 100% rename from tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs rename to tests/rustdoc-html/primitive/search-index-primitive-inherent-method-23511.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-both.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-both.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-both.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-both.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-hidden.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-hidden.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-hidden.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-hidden.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-neither.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-neither.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-neither.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-neither.rs diff --git a/tests/rustdoc/private/doc-hidden-private-67851-private.rs b/tests/rustdoc-html/private/doc-hidden-private-67851-private.rs similarity index 100% rename from tests/rustdoc/private/doc-hidden-private-67851-private.rs rename to tests/rustdoc-html/private/doc-hidden-private-67851-private.rs diff --git a/tests/rustdoc/private/empty-impl-block-private-with-doc.rs b/tests/rustdoc-html/private/empty-impl-block-private-with-doc.rs similarity index 100% rename from tests/rustdoc/private/empty-impl-block-private-with-doc.rs rename to tests/rustdoc-html/private/empty-impl-block-private-with-doc.rs diff --git a/tests/rustdoc/private/empty-impl-block-private.rs b/tests/rustdoc-html/private/empty-impl-block-private.rs similarity index 100% rename from tests/rustdoc/private/empty-impl-block-private.rs rename to tests/rustdoc-html/private/empty-impl-block-private.rs diff --git a/tests/rustdoc/private/empty-mod-private.rs b/tests/rustdoc-html/private/empty-mod-private.rs similarity index 100% rename from tests/rustdoc/private/empty-mod-private.rs rename to tests/rustdoc-html/private/empty-mod-private.rs diff --git a/tests/rustdoc/private/enum-variant-private-46767.rs b/tests/rustdoc-html/private/enum-variant-private-46767.rs similarity index 100% rename from tests/rustdoc/private/enum-variant-private-46767.rs rename to tests/rustdoc-html/private/enum-variant-private-46767.rs diff --git a/tests/rustdoc/private/files-creation-private.rs b/tests/rustdoc-html/private/files-creation-private.rs similarity index 100% rename from tests/rustdoc/private/files-creation-private.rs rename to tests/rustdoc-html/private/files-creation-private.rs diff --git a/tests/rustdoc/private/hidden-private.rs b/tests/rustdoc-html/private/hidden-private.rs similarity index 100% rename from tests/rustdoc/private/hidden-private.rs rename to tests/rustdoc-html/private/hidden-private.rs diff --git a/tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc-html/private/inline-private-with-intermediate-doc-hidden.rs similarity index 100% rename from tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs rename to tests/rustdoc-html/private/inline-private-with-intermediate-doc-hidden.rs diff --git a/tests/rustdoc/private/inner-private-110422.rs b/tests/rustdoc-html/private/inner-private-110422.rs similarity index 100% rename from tests/rustdoc/private/inner-private-110422.rs rename to tests/rustdoc-html/private/inner-private-110422.rs diff --git a/tests/rustdoc/private/macro-document-private-duplicate.rs b/tests/rustdoc-html/private/macro-document-private-duplicate.rs similarity index 100% rename from tests/rustdoc/private/macro-document-private-duplicate.rs rename to tests/rustdoc-html/private/macro-document-private-duplicate.rs diff --git a/tests/rustdoc/private/macro-document-private.rs b/tests/rustdoc-html/private/macro-document-private.rs similarity index 100% rename from tests/rustdoc/private/macro-document-private.rs rename to tests/rustdoc-html/private/macro-document-private.rs diff --git a/tests/rustdoc/private/macro-private-not-documented.rs b/tests/rustdoc-html/private/macro-private-not-documented.rs similarity index 100% rename from tests/rustdoc/private/macro-private-not-documented.rs rename to tests/rustdoc-html/private/macro-private-not-documented.rs diff --git a/tests/rustdoc/private/missing-private-inlining-109258.rs b/tests/rustdoc-html/private/missing-private-inlining-109258.rs similarity index 100% rename from tests/rustdoc/private/missing-private-inlining-109258.rs rename to tests/rustdoc-html/private/missing-private-inlining-109258.rs diff --git a/tests/rustdoc/private/private-fields-tuple-struct.rs b/tests/rustdoc-html/private/private-fields-tuple-struct.rs similarity index 100% rename from tests/rustdoc/private/private-fields-tuple-struct.rs rename to tests/rustdoc-html/private/private-fields-tuple-struct.rs diff --git a/tests/rustdoc/private/private-non-local-fields-2.rs b/tests/rustdoc-html/private/private-non-local-fields-2.rs similarity index 100% rename from tests/rustdoc/private/private-non-local-fields-2.rs rename to tests/rustdoc-html/private/private-non-local-fields-2.rs diff --git a/tests/rustdoc/private/private-non-local-fields.rs b/tests/rustdoc-html/private/private-non-local-fields.rs similarity index 100% rename from tests/rustdoc/private/private-non-local-fields.rs rename to tests/rustdoc-html/private/private-non-local-fields.rs diff --git a/tests/rustdoc/private/private-type-alias.rs b/tests/rustdoc-html/private/private-type-alias.rs similarity index 100% rename from tests/rustdoc/private/private-type-alias.rs rename to tests/rustdoc-html/private/private-type-alias.rs diff --git a/tests/rustdoc/private/private-type-cycle-110629.rs b/tests/rustdoc-html/private/private-type-cycle-110629.rs similarity index 100% rename from tests/rustdoc/private/private-type-cycle-110629.rs rename to tests/rustdoc-html/private/private-type-cycle-110629.rs diff --git a/tests/rustdoc/private/private-use-decl-macro-47038.rs b/tests/rustdoc-html/private/private-use-decl-macro-47038.rs similarity index 100% rename from tests/rustdoc/private/private-use-decl-macro-47038.rs rename to tests/rustdoc-html/private/private-use-decl-macro-47038.rs diff --git a/tests/rustdoc/private/private-use.rs b/tests/rustdoc-html/private/private-use.rs similarity index 100% rename from tests/rustdoc/private/private-use.rs rename to tests/rustdoc-html/private/private-use.rs diff --git a/tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs b/tests/rustdoc-html/private/public-impl-mention-private-generic-46380-2.rs similarity index 100% rename from tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs rename to tests/rustdoc-html/private/public-impl-mention-private-generic-46380-2.rs diff --git a/tests/rustdoc/private/traits-in-bodies-private.rs b/tests/rustdoc-html/private/traits-in-bodies-private.rs similarity index 100% rename from tests/rustdoc/private/traits-in-bodies-private.rs rename to tests/rustdoc-html/private/traits-in-bodies-private.rs diff --git a/tests/rustdoc/process-termination.rs b/tests/rustdoc-html/process-termination.rs similarity index 100% rename from tests/rustdoc/process-termination.rs rename to tests/rustdoc-html/process-termination.rs diff --git a/tests/rustdoc/pub-method.rs b/tests/rustdoc-html/pub-method.rs similarity index 100% rename from tests/rustdoc/pub-method.rs rename to tests/rustdoc-html/pub-method.rs diff --git a/tests/rustdoc/pub-use-loop-107350.rs b/tests/rustdoc-html/pub-use-loop-107350.rs similarity index 100% rename from tests/rustdoc/pub-use-loop-107350.rs rename to tests/rustdoc-html/pub-use-loop-107350.rs diff --git a/tests/rustdoc/pub-use-root-path-95873.rs b/tests/rustdoc-html/pub-use-root-path-95873.rs similarity index 100% rename from tests/rustdoc/pub-use-root-path-95873.rs rename to tests/rustdoc-html/pub-use-root-path-95873.rs diff --git a/tests/rustdoc/range-arg-pattern.rs b/tests/rustdoc-html/range-arg-pattern.rs similarity index 100% rename from tests/rustdoc/range-arg-pattern.rs rename to tests/rustdoc-html/range-arg-pattern.rs diff --git a/tests/rustdoc/raw-ident-eliminate-r-hashtag.rs b/tests/rustdoc-html/raw-ident-eliminate-r-hashtag.rs similarity index 100% rename from tests/rustdoc/raw-ident-eliminate-r-hashtag.rs rename to tests/rustdoc-html/raw-ident-eliminate-r-hashtag.rs diff --git a/tests/rustdoc/read-more-unneeded.rs b/tests/rustdoc-html/read-more-unneeded.rs similarity index 100% rename from tests/rustdoc/read-more-unneeded.rs rename to tests/rustdoc-html/read-more-unneeded.rs diff --git a/tests/rustdoc/recursion1.rs b/tests/rustdoc-html/recursion1.rs similarity index 100% rename from tests/rustdoc/recursion1.rs rename to tests/rustdoc-html/recursion1.rs diff --git a/tests/rustdoc/recursion2.rs b/tests/rustdoc-html/recursion2.rs similarity index 100% rename from tests/rustdoc/recursion2.rs rename to tests/rustdoc-html/recursion2.rs diff --git a/tests/rustdoc/recursion3.rs b/tests/rustdoc-html/recursion3.rs similarity index 100% rename from tests/rustdoc/recursion3.rs rename to tests/rustdoc-html/recursion3.rs diff --git a/tests/rustdoc/redirect-map-empty.rs b/tests/rustdoc-html/redirect-map-empty.rs similarity index 100% rename from tests/rustdoc/redirect-map-empty.rs rename to tests/rustdoc-html/redirect-map-empty.rs diff --git a/tests/rustdoc/redirect-map.rs b/tests/rustdoc-html/redirect-map.rs similarity index 100% rename from tests/rustdoc/redirect-map.rs rename to tests/rustdoc-html/redirect-map.rs diff --git a/tests/rustdoc/redirect-rename.rs b/tests/rustdoc-html/redirect-rename.rs similarity index 100% rename from tests/rustdoc/redirect-rename.rs rename to tests/rustdoc-html/redirect-rename.rs diff --git a/tests/rustdoc/redirect.rs b/tests/rustdoc-html/redirect.rs similarity index 100% rename from tests/rustdoc/redirect.rs rename to tests/rustdoc-html/redirect.rs diff --git a/tests/rustdoc/reexport/alias-reexport.rs b/tests/rustdoc-html/reexport/alias-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/alias-reexport.rs rename to tests/rustdoc-html/reexport/alias-reexport.rs diff --git a/tests/rustdoc/reexport/alias-reexport2.rs b/tests/rustdoc-html/reexport/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/reexport/alias-reexport2.rs rename to tests/rustdoc-html/reexport/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/anonymous-reexport-108931.rs b/tests/rustdoc-html/reexport/anonymous-reexport-108931.rs similarity index 100% rename from tests/rustdoc/reexport/anonymous-reexport-108931.rs rename to tests/rustdoc-html/reexport/anonymous-reexport-108931.rs diff --git a/tests/rustdoc/reexport/anonymous-reexport.rs b/tests/rustdoc-html/reexport/anonymous-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/anonymous-reexport.rs rename to tests/rustdoc-html/reexport/anonymous-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/alias-reexport.rs b/tests/rustdoc-html/reexport/auxiliary/alias-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/alias-reexport.rs rename to tests/rustdoc-html/reexport/auxiliary/alias-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/alias-reexport2.rs b/tests/rustdoc-html/reexport/auxiliary/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/alias-reexport2.rs rename to tests/rustdoc-html/reexport/auxiliary/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/auxiliary/all-item-types.rs b/tests/rustdoc-html/reexport/auxiliary/all-item-types.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/all-item-types.rs rename to tests/rustdoc-html/reexport/auxiliary/all-item-types.rs diff --git a/tests/rustdoc/reexport/auxiliary/issue-28927-1.rs b/tests/rustdoc-html/reexport/auxiliary/issue-28927-1.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/issue-28927-1.rs rename to tests/rustdoc-html/reexport/auxiliary/issue-28927-1.rs diff --git a/tests/rustdoc/reexport/auxiliary/issue-28927-2.rs b/tests/rustdoc-html/reexport/auxiliary/issue-28927-2.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/issue-28927-2.rs rename to tests/rustdoc-html/reexport/auxiliary/issue-28927-2.rs diff --git a/tests/rustdoc/reexport/auxiliary/primitive-reexport.rs b/tests/rustdoc-html/reexport/auxiliary/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/primitive-reexport.rs rename to tests/rustdoc-html/reexport/auxiliary/primitive-reexport.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexport-check.rs b/tests/rustdoc-html/reexport/auxiliary/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexport-check.rs rename to tests/rustdoc-html/reexport/auxiliary/reexport-check.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs b/tests/rustdoc-html/reexport/auxiliary/reexport-doc-aux.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs rename to tests/rustdoc-html/reexport/auxiliary/reexport-doc-aux.rs diff --git a/tests/rustdoc/reexport/auxiliary/reexports.rs b/tests/rustdoc-html/reexport/auxiliary/reexports.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/reexports.rs rename to tests/rustdoc-html/reexport/auxiliary/reexports.rs diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc-html/reexport/auxiliary/wrap-unnamable-type.rs similarity index 100% rename from tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs rename to tests/rustdoc-html/reexport/auxiliary/wrap-unnamable-type.rs diff --git a/tests/rustdoc/reexport/blanket-reexport-item.rs b/tests/rustdoc-html/reexport/blanket-reexport-item.rs similarity index 100% rename from tests/rustdoc/reexport/blanket-reexport-item.rs rename to tests/rustdoc-html/reexport/blanket-reexport-item.rs diff --git a/tests/rustdoc/reexport/cfg_doc_reexport.rs b/tests/rustdoc-html/reexport/cfg_doc_reexport.rs similarity index 100% rename from tests/rustdoc/reexport/cfg_doc_reexport.rs rename to tests/rustdoc-html/reexport/cfg_doc_reexport.rs diff --git a/tests/rustdoc/reexport/doc-hidden-reexports-109449.rs b/tests/rustdoc-html/reexport/doc-hidden-reexports-109449.rs similarity index 100% rename from tests/rustdoc/reexport/doc-hidden-reexports-109449.rs rename to tests/rustdoc-html/reexport/doc-hidden-reexports-109449.rs diff --git a/tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs b/tests/rustdoc-html/reexport/duplicated-glob-reexport-60522.rs similarity index 100% rename from tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs rename to tests/rustdoc-html/reexport/duplicated-glob-reexport-60522.rs diff --git a/tests/rustdoc/reexport/enum-variant-reexport-35488.rs b/tests/rustdoc-html/reexport/enum-variant-reexport-35488.rs similarity index 100% rename from tests/rustdoc/reexport/enum-variant-reexport-35488.rs rename to tests/rustdoc-html/reexport/enum-variant-reexport-35488.rs diff --git a/tests/rustdoc/reexport/enum-variant.rs b/tests/rustdoc-html/reexport/enum-variant.rs similarity index 100% rename from tests/rustdoc/reexport/enum-variant.rs rename to tests/rustdoc-html/reexport/enum-variant.rs diff --git a/tests/rustdoc/reexport/extern-135092.rs b/tests/rustdoc-html/reexport/extern-135092.rs similarity index 100% rename from tests/rustdoc/reexport/extern-135092.rs rename to tests/rustdoc-html/reexport/extern-135092.rs diff --git a/tests/rustdoc/reexport/foreigntype-reexport.rs b/tests/rustdoc-html/reexport/foreigntype-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/foreigntype-reexport.rs rename to tests/rustdoc-html/reexport/foreigntype-reexport.rs diff --git a/tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc-html/reexport/glob-reexport-attribute-merge-120487.rs similarity index 100% rename from tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs rename to tests/rustdoc-html/reexport/glob-reexport-attribute-merge-120487.rs diff --git a/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc-html/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs rename to tests/rustdoc-html/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs diff --git a/tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs b/tests/rustdoc-html/reexport/ice-reexport-crate-root-28927.rs similarity index 100% rename from tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs rename to tests/rustdoc-html/reexport/ice-reexport-crate-root-28927.rs diff --git a/tests/rustdoc/reexport/import_trait_associated_functions.rs b/tests/rustdoc-html/reexport/import_trait_associated_functions.rs similarity index 100% rename from tests/rustdoc/reexport/import_trait_associated_functions.rs rename to tests/rustdoc-html/reexport/import_trait_associated_functions.rs diff --git a/tests/rustdoc/reexport/local-reexport-doc.rs b/tests/rustdoc-html/reexport/local-reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport/local-reexport-doc.rs rename to tests/rustdoc-html/reexport/local-reexport-doc.rs diff --git a/tests/rustdoc/reexport/merge-glob-and-non-glob.rs b/tests/rustdoc-html/reexport/merge-glob-and-non-glob.rs similarity index 100% rename from tests/rustdoc/reexport/merge-glob-and-non-glob.rs rename to tests/rustdoc-html/reexport/merge-glob-and-non-glob.rs diff --git a/tests/rustdoc/reexport/no-compiler-reexport.rs b/tests/rustdoc-html/reexport/no-compiler-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/no-compiler-reexport.rs rename to tests/rustdoc-html/reexport/no-compiler-reexport.rs diff --git a/tests/rustdoc/reexport/overlapping-reexport-105735-2.rs b/tests/rustdoc-html/reexport/overlapping-reexport-105735-2.rs similarity index 100% rename from tests/rustdoc/reexport/overlapping-reexport-105735-2.rs rename to tests/rustdoc-html/reexport/overlapping-reexport-105735-2.rs diff --git a/tests/rustdoc/reexport/overlapping-reexport-105735.rs b/tests/rustdoc-html/reexport/overlapping-reexport-105735.rs similarity index 100% rename from tests/rustdoc/reexport/overlapping-reexport-105735.rs rename to tests/rustdoc-html/reexport/overlapping-reexport-105735.rs diff --git a/tests/rustdoc/reexport/primitive-reexport.rs b/tests/rustdoc-html/reexport/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/primitive-reexport.rs rename to tests/rustdoc-html/reexport/primitive-reexport.rs diff --git a/tests/rustdoc/reexport/private-mod-override-reexport.rs b/tests/rustdoc-html/reexport/private-mod-override-reexport.rs similarity index 100% rename from tests/rustdoc/reexport/private-mod-override-reexport.rs rename to tests/rustdoc-html/reexport/private-mod-override-reexport.rs diff --git a/tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs b/tests/rustdoc-html/reexport/pub-reexport-of-pub-reexport-46506.rs similarity index 100% rename from tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs rename to tests/rustdoc-html/reexport/pub-reexport-of-pub-reexport-46506.rs diff --git a/tests/rustdoc/reexport/reexport-attr-merge.rs b/tests/rustdoc-html/reexport/reexport-attr-merge.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-attr-merge.rs rename to tests/rustdoc-html/reexport/reexport-attr-merge.rs diff --git a/tests/rustdoc/reexport/reexport-cfg.rs b/tests/rustdoc-html/reexport/reexport-cfg.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-cfg.rs rename to tests/rustdoc-html/reexport/reexport-cfg.rs diff --git a/tests/rustdoc/reexport/reexport-check.rs b/tests/rustdoc-html/reexport/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-check.rs rename to tests/rustdoc-html/reexport/reexport-check.rs diff --git a/tests/rustdoc/reexport/reexport-dep-foreign-fn.rs b/tests/rustdoc-html/reexport/reexport-dep-foreign-fn.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-dep-foreign-fn.rs rename to tests/rustdoc-html/reexport/reexport-dep-foreign-fn.rs diff --git a/tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs b/tests/rustdoc-html/reexport/reexport-doc-hidden-inside-private.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs rename to tests/rustdoc-html/reexport/reexport-doc-hidden-inside-private.rs diff --git a/tests/rustdoc/reexport/reexport-doc-hidden.rs b/tests/rustdoc-html/reexport/reexport-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc-hidden.rs rename to tests/rustdoc-html/reexport/reexport-doc-hidden.rs diff --git a/tests/rustdoc/reexport/reexport-doc.rs b/tests/rustdoc-html/reexport/reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-doc.rs rename to tests/rustdoc-html/reexport/reexport-doc.rs diff --git a/tests/rustdoc/reexport/reexport-hidden-macro.rs b/tests/rustdoc-html/reexport/reexport-hidden-macro.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-hidden-macro.rs rename to tests/rustdoc-html/reexport/reexport-hidden-macro.rs diff --git a/tests/rustdoc/reexport/reexport-macro.rs b/tests/rustdoc-html/reexport/reexport-macro.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-macro.rs rename to tests/rustdoc-html/reexport/reexport-macro.rs diff --git a/tests/rustdoc/reexport/reexport-of-doc-hidden.rs b/tests/rustdoc-html/reexport/reexport-of-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-of-doc-hidden.rs rename to tests/rustdoc-html/reexport/reexport-of-doc-hidden.rs diff --git a/tests/rustdoc/reexport/reexport-of-reexport-108679.rs b/tests/rustdoc-html/reexport/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-of-reexport-108679.rs rename to tests/rustdoc-html/reexport/reexport-of-reexport-108679.rs diff --git a/tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs b/tests/rustdoc-html/reexport/reexport-stability-tags-deprecated-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs rename to tests/rustdoc-html/reexport/reexport-stability-tags-deprecated-and-portability.rs diff --git a/tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs b/tests/rustdoc-html/reexport/reexport-stability-tags-unstable-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs rename to tests/rustdoc-html/reexport/reexport-stability-tags-unstable-and-portability.rs diff --git a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs b/tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064-2.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs rename to tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064-2.rs diff --git a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs b/tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064.rs similarity index 100% rename from tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs rename to tests/rustdoc-html/reexport/reexport-trait-from-hidden-111064.rs diff --git a/tests/rustdoc/reexport/reexports-of-same-name.rs b/tests/rustdoc-html/reexport/reexports-of-same-name.rs similarity index 100% rename from tests/rustdoc/reexport/reexports-of-same-name.rs rename to tests/rustdoc-html/reexport/reexports-of-same-name.rs diff --git a/tests/rustdoc/reexport/reexports-priv.rs b/tests/rustdoc-html/reexport/reexports-priv.rs similarity index 100% rename from tests/rustdoc/reexport/reexports-priv.rs rename to tests/rustdoc-html/reexport/reexports-priv.rs diff --git a/tests/rustdoc/reexport/reexports.rs b/tests/rustdoc-html/reexport/reexports.rs similarity index 100% rename from tests/rustdoc/reexport/reexports.rs rename to tests/rustdoc-html/reexport/reexports.rs diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc-html/reexport/wrapped-unnamble-type-143222.rs similarity index 100% rename from tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs rename to tests/rustdoc-html/reexport/wrapped-unnamble-type-143222.rs diff --git a/tests/rustdoc/remove-duplicates.rs b/tests/rustdoc-html/remove-duplicates.rs similarity index 100% rename from tests/rustdoc/remove-duplicates.rs rename to tests/rustdoc-html/remove-duplicates.rs diff --git a/tests/rustdoc/remove-url-from-headings.rs b/tests/rustdoc-html/remove-url-from-headings.rs similarity index 100% rename from tests/rustdoc/remove-url-from-headings.rs rename to tests/rustdoc-html/remove-url-from-headings.rs diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc-html/repr.rs similarity index 100% rename from tests/rustdoc/repr.rs rename to tests/rustdoc-html/repr.rs diff --git a/tests/rustdoc/resolve-ice-124363.rs b/tests/rustdoc-html/resolve-ice-124363.rs similarity index 100% rename from tests/rustdoc/resolve-ice-124363.rs rename to tests/rustdoc-html/resolve-ice-124363.rs diff --git a/tests/rustdoc/return-type-notation.rs b/tests/rustdoc-html/return-type-notation.rs similarity index 100% rename from tests/rustdoc/return-type-notation.rs rename to tests/rustdoc-html/return-type-notation.rs diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc-html/safe-intrinsic.rs similarity index 100% rename from tests/rustdoc/safe-intrinsic.rs rename to tests/rustdoc-html/safe-intrinsic.rs diff --git a/tests/rustdoc/sanitizer-option.rs b/tests/rustdoc-html/sanitizer-option.rs similarity index 100% rename from tests/rustdoc/sanitizer-option.rs rename to tests/rustdoc-html/sanitizer-option.rs diff --git a/tests/rustdoc/search-index-summaries.rs b/tests/rustdoc-html/search-index-summaries.rs similarity index 100% rename from tests/rustdoc/search-index-summaries.rs rename to tests/rustdoc-html/search-index-summaries.rs diff --git a/tests/rustdoc/search-index.rs b/tests/rustdoc-html/search-index.rs similarity index 100% rename from tests/rustdoc/search-index.rs rename to tests/rustdoc-html/search-index.rs diff --git a/tests/rustdoc/short-docblock-codeblock.rs b/tests/rustdoc-html/short-docblock-codeblock.rs similarity index 100% rename from tests/rustdoc/short-docblock-codeblock.rs rename to tests/rustdoc-html/short-docblock-codeblock.rs diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc-html/short-docblock.rs similarity index 100% rename from tests/rustdoc/short-docblock.rs rename to tests/rustdoc-html/short-docblock.rs diff --git a/tests/rustdoc/short-line.md b/tests/rustdoc-html/short-line.md similarity index 100% rename from tests/rustdoc/short-line.md rename to tests/rustdoc-html/short-line.md diff --git a/tests/rustdoc/sidebar/module.rs b/tests/rustdoc-html/sidebar/module.rs similarity index 100% rename from tests/rustdoc/sidebar/module.rs rename to tests/rustdoc-html/sidebar/module.rs diff --git a/tests/rustdoc/sidebar/sidebar-all-page.rs b/tests/rustdoc-html/sidebar/sidebar-all-page.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-all-page.rs rename to tests/rustdoc-html/sidebar/sidebar-all-page.rs diff --git a/tests/rustdoc/sidebar/sidebar-items.rs b/tests/rustdoc-html/sidebar/sidebar-items.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-items.rs rename to tests/rustdoc-html/sidebar/sidebar-items.rs diff --git a/tests/rustdoc/sidebar/sidebar-link-generation.rs b/tests/rustdoc-html/sidebar/sidebar-link-generation.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-link-generation.rs rename to tests/rustdoc-html/sidebar/sidebar-link-generation.rs diff --git a/tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs b/tests/rustdoc-html/sidebar/sidebar-links-to-foreign-impl.rs similarity index 100% rename from tests/rustdoc/sidebar/sidebar-links-to-foreign-impl.rs rename to tests/rustdoc-html/sidebar/sidebar-links-to-foreign-impl.rs diff --git a/tests/rustdoc/sidebar/top-toc-html.rs b/tests/rustdoc-html/sidebar/top-toc-html.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-html.rs rename to tests/rustdoc-html/sidebar/top-toc-html.rs diff --git a/tests/rustdoc/sidebar/top-toc-idmap.rs b/tests/rustdoc-html/sidebar/top-toc-idmap.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-idmap.rs rename to tests/rustdoc-html/sidebar/top-toc-idmap.rs diff --git a/tests/rustdoc/sidebar/top-toc-nil.rs b/tests/rustdoc-html/sidebar/top-toc-nil.rs similarity index 100% rename from tests/rustdoc/sidebar/top-toc-nil.rs rename to tests/rustdoc-html/sidebar/top-toc-nil.rs diff --git a/tests/rustdoc/sized_trait.rs b/tests/rustdoc-html/sized_trait.rs similarity index 100% rename from tests/rustdoc/sized_trait.rs rename to tests/rustdoc-html/sized_trait.rs diff --git a/tests/rustdoc/slice-links.link_box_generic.html b/tests/rustdoc-html/slice-links.link_box_generic.html similarity index 100% rename from tests/rustdoc/slice-links.link_box_generic.html rename to tests/rustdoc-html/slice-links.link_box_generic.html diff --git a/tests/rustdoc/slice-links.link_box_u32.html b/tests/rustdoc-html/slice-links.link_box_u32.html similarity index 100% rename from tests/rustdoc/slice-links.link_box_u32.html rename to tests/rustdoc-html/slice-links.link_box_u32.html diff --git a/tests/rustdoc/slice-links.link_slice_generic.html b/tests/rustdoc-html/slice-links.link_slice_generic.html similarity index 100% rename from tests/rustdoc/slice-links.link_slice_generic.html rename to tests/rustdoc-html/slice-links.link_slice_generic.html diff --git a/tests/rustdoc/slice-links.link_slice_u32.html b/tests/rustdoc-html/slice-links.link_slice_u32.html similarity index 100% rename from tests/rustdoc/slice-links.link_slice_u32.html rename to tests/rustdoc-html/slice-links.link_slice_u32.html diff --git a/tests/rustdoc/slice-links.rs b/tests/rustdoc-html/slice-links.rs similarity index 100% rename from tests/rustdoc/slice-links.rs rename to tests/rustdoc-html/slice-links.rs diff --git a/tests/rustdoc/smart-punct.rs b/tests/rustdoc-html/smart-punct.rs similarity index 100% rename from tests/rustdoc/smart-punct.rs rename to tests/rustdoc-html/smart-punct.rs diff --git a/tests/rustdoc/smoke.rs b/tests/rustdoc-html/smoke.rs similarity index 100% rename from tests/rustdoc/smoke.rs rename to tests/rustdoc-html/smoke.rs diff --git a/tests/rustdoc/sort-53812.rs b/tests/rustdoc-html/sort-53812.rs similarity index 100% rename from tests/rustdoc/sort-53812.rs rename to tests/rustdoc-html/sort-53812.rs diff --git a/tests/rustdoc/sort-modules-by-appearance.rs b/tests/rustdoc-html/sort-modules-by-appearance.rs similarity index 100% rename from tests/rustdoc/sort-modules-by-appearance.rs rename to tests/rustdoc-html/sort-modules-by-appearance.rs diff --git a/tests/rustdoc/source-code-pages/assoc-type-source-link.rs b/tests/rustdoc-html/source-code-pages/assoc-type-source-link.rs similarity index 100% rename from tests/rustdoc/source-code-pages/assoc-type-source-link.rs rename to tests/rustdoc-html/source-code-pages/assoc-type-source-link.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs b/tests/rustdoc-html/source-code-pages/auxiliary/issue-26606-macro.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/issue-26606-macro.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs b/tests/rustdoc-html/source-code-pages/auxiliary/issue-34274.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/issue-34274.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs b/tests/rustdoc-html/source-code-pages/auxiliary/source-code-bar.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/source-code-bar.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/source_code.rs b/tests/rustdoc-html/source-code-pages/auxiliary/source_code.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/source_code.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/source_code.rs diff --git a/tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs b/tests/rustdoc-html/source-code-pages/auxiliary/src-links-external.rs similarity index 100% rename from tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs rename to tests/rustdoc-html/source-code-pages/auxiliary/src-links-external.rs diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def-std.rs similarity index 100% rename from tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs rename to tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def-std.rs diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs similarity index 100% rename from tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs rename to tests/rustdoc-html/source-code-pages/check-source-code-urls-to-def.rs diff --git a/tests/rustdoc/source-code-pages/doc-hidden-source.rs b/tests/rustdoc-html/source-code-pages/doc-hidden-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/doc-hidden-source.rs rename to tests/rustdoc-html/source-code-pages/doc-hidden-source.rs diff --git a/tests/rustdoc/source-code-pages/failing-expansion-on-wrong-macro.rs b/tests/rustdoc-html/source-code-pages/failing-expansion-on-wrong-macro.rs similarity index 100% rename from tests/rustdoc/source-code-pages/failing-expansion-on-wrong-macro.rs rename to tests/rustdoc-html/source-code-pages/failing-expansion-on-wrong-macro.rs diff --git a/tests/rustdoc/source-code-pages/frontmatter.rs b/tests/rustdoc-html/source-code-pages/frontmatter.rs similarity index 100% rename from tests/rustdoc/source-code-pages/frontmatter.rs rename to tests/rustdoc-html/source-code-pages/frontmatter.rs diff --git a/tests/rustdoc/source-code-pages/html-no-source.rs b/tests/rustdoc-html/source-code-pages/html-no-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/html-no-source.rs rename to tests/rustdoc-html/source-code-pages/html-no-source.rs diff --git a/tests/rustdoc/source-code-pages/keyword-macros.rs b/tests/rustdoc-html/source-code-pages/keyword-macros.rs similarity index 100% rename from tests/rustdoc/source-code-pages/keyword-macros.rs rename to tests/rustdoc-html/source-code-pages/keyword-macros.rs diff --git a/tests/rustdoc/source-code-pages/shebang.rs b/tests/rustdoc-html/source-code-pages/shebang.rs similarity index 100% rename from tests/rustdoc/source-code-pages/shebang.rs rename to tests/rustdoc-html/source-code-pages/shebang.rs diff --git a/tests/rustdoc/source-code-pages/source-code-highlight.rs b/tests/rustdoc-html/source-code-pages/source-code-highlight.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-code-highlight.rs rename to tests/rustdoc-html/source-code-pages/source-code-highlight.rs diff --git a/tests/rustdoc/source-code-pages/source-file.rs b/tests/rustdoc-html/source-code-pages/source-file.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-file.rs rename to tests/rustdoc-html/source-code-pages/source-file.rs diff --git a/tests/rustdoc/source-code-pages/source-line-numbers.rs b/tests/rustdoc-html/source-code-pages/source-line-numbers.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-line-numbers.rs rename to tests/rustdoc-html/source-code-pages/source-line-numbers.rs diff --git a/tests/rustdoc/source-code-pages/source-version-separator.rs b/tests/rustdoc-html/source-code-pages/source-version-separator.rs similarity index 100% rename from tests/rustdoc/source-code-pages/source-version-separator.rs rename to tests/rustdoc-html/source-code-pages/source-version-separator.rs diff --git a/tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs b/tests/rustdoc-html/source-code-pages/src-link-external-macro-26606.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs rename to tests/rustdoc-html/source-code-pages/src-link-external-macro-26606.rs diff --git a/tests/rustdoc/source-code-pages/src-links-auto-impls.rs b/tests/rustdoc-html/source-code-pages/src-links-auto-impls.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-auto-impls.rs rename to tests/rustdoc-html/source-code-pages/src-links-auto-impls.rs diff --git a/tests/rustdoc/source-code-pages/src-links-external.rs b/tests/rustdoc-html/source-code-pages/src-links-external.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-external.rs rename to tests/rustdoc-html/source-code-pages/src-links-external.rs diff --git a/tests/rustdoc/source-code-pages/src-links-implementor-43893.rs b/tests/rustdoc-html/source-code-pages/src-links-implementor-43893.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-implementor-43893.rs rename to tests/rustdoc-html/source-code-pages/src-links-implementor-43893.rs diff --git a/tests/rustdoc/source-code-pages/src-links-inlined-34274.rs b/tests/rustdoc-html/source-code-pages/src-links-inlined-34274.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links-inlined-34274.rs rename to tests/rustdoc-html/source-code-pages/src-links-inlined-34274.rs diff --git a/tests/rustdoc/source-code-pages/src-links.rs b/tests/rustdoc-html/source-code-pages/src-links.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links.rs rename to tests/rustdoc-html/source-code-pages/src-links.rs diff --git a/tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir b/tests/rustdoc-html/source-code-pages/src-links/compiletest-ignore-dir similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir rename to tests/rustdoc-html/source-code-pages/src-links/compiletest-ignore-dir diff --git a/tests/rustdoc/source-code-pages/src-links/fizz.rs b/tests/rustdoc-html/source-code-pages/src-links/fizz.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/fizz.rs rename to tests/rustdoc-html/source-code-pages/src-links/fizz.rs diff --git a/tests/rustdoc/source-code-pages/src-links/mod.rs b/tests/rustdoc-html/source-code-pages/src-links/mod.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-links/mod.rs rename to tests/rustdoc-html/source-code-pages/src-links/mod.rs diff --git a/tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs b/tests/rustdoc-html/source-code-pages/src-mod-path-absolute-26995.rs similarity index 100% rename from tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs rename to tests/rustdoc-html/source-code-pages/src-mod-path-absolute-26995.rs diff --git a/tests/rustdoc/source-code-pages/version-separator-without-source.rs b/tests/rustdoc-html/source-code-pages/version-separator-without-source.rs similarity index 100% rename from tests/rustdoc/source-code-pages/version-separator-without-source.rs rename to tests/rustdoc-html/source-code-pages/version-separator-without-source.rs diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc-html/stability.rs similarity index 100% rename from tests/rustdoc/stability.rs rename to tests/rustdoc-html/stability.rs diff --git a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs b/tests/rustdoc-html/staged-api-deprecated-unstable-32374.rs similarity index 100% rename from tests/rustdoc/staged-api-deprecated-unstable-32374.rs rename to tests/rustdoc-html/staged-api-deprecated-unstable-32374.rs diff --git a/tests/rustdoc/staged-api-feature-issue-27759.rs b/tests/rustdoc-html/staged-api-feature-issue-27759.rs similarity index 100% rename from tests/rustdoc/staged-api-feature-issue-27759.rs rename to tests/rustdoc-html/staged-api-feature-issue-27759.rs diff --git a/tests/rustdoc/static-root-path.rs b/tests/rustdoc-html/static-root-path.rs similarity index 100% rename from tests/rustdoc/static-root-path.rs rename to tests/rustdoc-html/static-root-path.rs diff --git a/tests/rustdoc/static.rs b/tests/rustdoc-html/static.rs similarity index 100% rename from tests/rustdoc/static.rs rename to tests/rustdoc-html/static.rs diff --git a/tests/rustdoc/strip-block-doc-comments-stars.docblock.html b/tests/rustdoc-html/strip-block-doc-comments-stars.docblock.html similarity index 100% rename from tests/rustdoc/strip-block-doc-comments-stars.docblock.html rename to tests/rustdoc-html/strip-block-doc-comments-stars.docblock.html diff --git a/tests/rustdoc/strip-block-doc-comments-stars.rs b/tests/rustdoc-html/strip-block-doc-comments-stars.rs similarity index 100% rename from tests/rustdoc/strip-block-doc-comments-stars.rs rename to tests/rustdoc-html/strip-block-doc-comments-stars.rs diff --git a/tests/rustdoc/strip-priv-imports-pass-27104.rs b/tests/rustdoc-html/strip-priv-imports-pass-27104.rs similarity index 100% rename from tests/rustdoc/strip-priv-imports-pass-27104.rs rename to tests/rustdoc-html/strip-priv-imports-pass-27104.rs diff --git a/tests/rustdoc/struct-arg-pattern.rs b/tests/rustdoc-html/struct-arg-pattern.rs similarity index 100% rename from tests/rustdoc/struct-arg-pattern.rs rename to tests/rustdoc-html/struct-arg-pattern.rs diff --git a/tests/rustdoc/struct-field.rs b/tests/rustdoc-html/struct-field.rs similarity index 100% rename from tests/rustdoc/struct-field.rs rename to tests/rustdoc-html/struct-field.rs diff --git a/tests/rustdoc/structfields.rs b/tests/rustdoc-html/structfields.rs similarity index 100% rename from tests/rustdoc/structfields.rs rename to tests/rustdoc-html/structfields.rs diff --git a/tests/rustdoc/summary-codeblock-31899.rs b/tests/rustdoc-html/summary-codeblock-31899.rs similarity index 100% rename from tests/rustdoc/summary-codeblock-31899.rs rename to tests/rustdoc-html/summary-codeblock-31899.rs diff --git a/tests/rustdoc/summary-header-46377.rs b/tests/rustdoc-html/summary-header-46377.rs similarity index 100% rename from tests/rustdoc/summary-header-46377.rs rename to tests/rustdoc-html/summary-header-46377.rs diff --git a/tests/rustdoc/summary-reference-link-30366.rs b/tests/rustdoc-html/summary-reference-link-30366.rs similarity index 100% rename from tests/rustdoc/summary-reference-link-30366.rs rename to tests/rustdoc-html/summary-reference-link-30366.rs diff --git a/tests/rustdoc/synthetic_auto/auto-trait-lifetimes-56822.rs b/tests/rustdoc-html/synthetic_auto/auto-trait-lifetimes-56822.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/auto-trait-lifetimes-56822.rs rename to tests/rustdoc-html/synthetic_auto/auto-trait-lifetimes-56822.rs diff --git a/tests/rustdoc/synthetic_auto/basic.rs b/tests/rustdoc-html/synthetic_auto/basic.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/basic.rs rename to tests/rustdoc-html/synthetic_auto/basic.rs diff --git a/tests/rustdoc/synthetic_auto/bounds.rs b/tests/rustdoc-html/synthetic_auto/bounds.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/bounds.rs rename to tests/rustdoc-html/synthetic_auto/bounds.rs diff --git a/tests/rustdoc/synthetic_auto/complex.rs b/tests/rustdoc-html/synthetic_auto/complex.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/complex.rs rename to tests/rustdoc-html/synthetic_auto/complex.rs diff --git a/tests/rustdoc/synthetic_auto/crate-local.rs b/tests/rustdoc-html/synthetic_auto/crate-local.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/crate-local.rs rename to tests/rustdoc-html/synthetic_auto/crate-local.rs diff --git a/tests/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs b/tests/rustdoc-html/synthetic_auto/issue-72213-projection-lifetime.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/issue-72213-projection-lifetime.rs rename to tests/rustdoc-html/synthetic_auto/issue-72213-projection-lifetime.rs diff --git a/tests/rustdoc/synthetic_auto/lifetimes.rs b/tests/rustdoc-html/synthetic_auto/lifetimes.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/lifetimes.rs rename to tests/rustdoc-html/synthetic_auto/lifetimes.rs diff --git a/tests/rustdoc/synthetic_auto/manual.rs b/tests/rustdoc-html/synthetic_auto/manual.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/manual.rs rename to tests/rustdoc-html/synthetic_auto/manual.rs diff --git a/tests/rustdoc/synthetic_auto/negative.rs b/tests/rustdoc-html/synthetic_auto/negative.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/negative.rs rename to tests/rustdoc-html/synthetic_auto/negative.rs diff --git a/tests/rustdoc/synthetic_auto/nested.rs b/tests/rustdoc-html/synthetic_auto/nested.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/nested.rs rename to tests/rustdoc-html/synthetic_auto/nested.rs diff --git a/tests/rustdoc/synthetic_auto/no-redundancy.rs b/tests/rustdoc-html/synthetic_auto/no-redundancy.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/no-redundancy.rs rename to tests/rustdoc-html/synthetic_auto/no-redundancy.rs diff --git a/tests/rustdoc/synthetic_auto/normalize-auto-trait-80233.rs b/tests/rustdoc-html/synthetic_auto/normalize-auto-trait-80233.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/normalize-auto-trait-80233.rs rename to tests/rustdoc-html/synthetic_auto/normalize-auto-trait-80233.rs diff --git a/tests/rustdoc/synthetic_auto/overflow.rs b/tests/rustdoc-html/synthetic_auto/overflow.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/overflow.rs rename to tests/rustdoc-html/synthetic_auto/overflow.rs diff --git a/tests/rustdoc/synthetic_auto/project.rs b/tests/rustdoc-html/synthetic_auto/project.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/project.rs rename to tests/rustdoc-html/synthetic_auto/project.rs diff --git a/tests/rustdoc/synthetic_auto/self-referential.rs b/tests/rustdoc-html/synthetic_auto/self-referential.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/self-referential.rs rename to tests/rustdoc-html/synthetic_auto/self-referential.rs diff --git a/tests/rustdoc/synthetic_auto/send-impl-conditional-60726.rs b/tests/rustdoc-html/synthetic_auto/send-impl-conditional-60726.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/send-impl-conditional-60726.rs rename to tests/rustdoc-html/synthetic_auto/send-impl-conditional-60726.rs diff --git a/tests/rustdoc/synthetic_auto/static-region.rs b/tests/rustdoc-html/synthetic_auto/static-region.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/static-region.rs rename to tests/rustdoc-html/synthetic_auto/static-region.rs diff --git a/tests/rustdoc/synthetic_auto/supertrait-bounds.rs b/tests/rustdoc-html/synthetic_auto/supertrait-bounds.rs similarity index 100% rename from tests/rustdoc/synthetic_auto/supertrait-bounds.rs rename to tests/rustdoc-html/synthetic_auto/supertrait-bounds.rs diff --git a/tests/rustdoc/tab_title.rs b/tests/rustdoc-html/tab_title.rs similarity index 100% rename from tests/rustdoc/tab_title.rs rename to tests/rustdoc-html/tab_title.rs diff --git a/tests/rustdoc/table-in-docblock.rs b/tests/rustdoc-html/table-in-docblock.rs similarity index 100% rename from tests/rustdoc/table-in-docblock.rs rename to tests/rustdoc-html/table-in-docblock.rs diff --git a/tests/rustdoc/target-feature.rs b/tests/rustdoc-html/target-feature.rs similarity index 100% rename from tests/rustdoc/target-feature.rs rename to tests/rustdoc-html/target-feature.rs diff --git a/tests/rustdoc/task-lists.rs b/tests/rustdoc-html/task-lists.rs similarity index 100% rename from tests/rustdoc/task-lists.rs rename to tests/rustdoc-html/task-lists.rs diff --git a/tests/rustdoc/test-lists.rs b/tests/rustdoc-html/test-lists.rs similarity index 100% rename from tests/rustdoc/test-lists.rs rename to tests/rustdoc-html/test-lists.rs diff --git a/tests/rustdoc/test-parens.rs b/tests/rustdoc-html/test-parens.rs similarity index 100% rename from tests/rustdoc/test-parens.rs rename to tests/rustdoc-html/test-parens.rs diff --git a/tests/rustdoc/test-strikethrough.rs b/tests/rustdoc-html/test-strikethrough.rs similarity index 100% rename from tests/rustdoc/test-strikethrough.rs rename to tests/rustdoc-html/test-strikethrough.rs diff --git a/tests/rustdoc/test_option_check/bar.rs b/tests/rustdoc-html/test_option_check/bar.rs similarity index 100% rename from tests/rustdoc/test_option_check/bar.rs rename to tests/rustdoc-html/test_option_check/bar.rs diff --git a/tests/rustdoc/test_option_check/test.rs b/tests/rustdoc-html/test_option_check/test.rs similarity index 100% rename from tests/rustdoc/test_option_check/test.rs rename to tests/rustdoc-html/test_option_check/test.rs diff --git a/tests/rustdoc/thread-local-src.rs b/tests/rustdoc-html/thread-local-src.rs similarity index 100% rename from tests/rustdoc/thread-local-src.rs rename to tests/rustdoc-html/thread-local-src.rs diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc-html/titles.rs similarity index 100% rename from tests/rustdoc/titles.rs rename to tests/rustdoc-html/titles.rs diff --git a/tests/rustdoc/toggle-item-contents.rs b/tests/rustdoc-html/toggle-item-contents.rs similarity index 100% rename from tests/rustdoc/toggle-item-contents.rs rename to tests/rustdoc-html/toggle-item-contents.rs diff --git a/tests/rustdoc/toggle-method.rs b/tests/rustdoc-html/toggle-method.rs similarity index 100% rename from tests/rustdoc/toggle-method.rs rename to tests/rustdoc-html/toggle-method.rs diff --git a/tests/rustdoc/toggle-trait-fn.rs b/tests/rustdoc-html/toggle-trait-fn.rs similarity index 100% rename from tests/rustdoc/toggle-trait-fn.rs rename to tests/rustdoc-html/toggle-trait-fn.rs diff --git a/tests/rustdoc/trait-aliases.rs b/tests/rustdoc-html/trait-aliases.rs similarity index 100% rename from tests/rustdoc/trait-aliases.rs rename to tests/rustdoc-html/trait-aliases.rs diff --git a/tests/rustdoc/trait-item-info.rs b/tests/rustdoc-html/trait-item-info.rs similarity index 100% rename from tests/rustdoc/trait-item-info.rs rename to tests/rustdoc-html/trait-item-info.rs diff --git a/tests/rustdoc/trait-self-link.rs b/tests/rustdoc-html/trait-self-link.rs similarity index 100% rename from tests/rustdoc/trait-self-link.rs rename to tests/rustdoc-html/trait-self-link.rs diff --git a/tests/rustdoc/trait-src-link.rs b/tests/rustdoc-html/trait-src-link.rs similarity index 100% rename from tests/rustdoc/trait-src-link.rs rename to tests/rustdoc-html/trait-src-link.rs diff --git a/tests/rustdoc/trait-visibility.rs b/tests/rustdoc-html/trait-visibility.rs similarity index 100% rename from tests/rustdoc/trait-visibility.rs rename to tests/rustdoc-html/trait-visibility.rs diff --git a/tests/rustdoc/traits-in-bodies.rs b/tests/rustdoc-html/traits-in-bodies.rs similarity index 100% rename from tests/rustdoc/traits-in-bodies.rs rename to tests/rustdoc-html/traits-in-bodies.rs diff --git a/tests/rustdoc/tuple-struct-fields-doc.rs b/tests/rustdoc-html/tuple-struct-fields-doc.rs similarity index 100% rename from tests/rustdoc/tuple-struct-fields-doc.rs rename to tests/rustdoc-html/tuple-struct-fields-doc.rs diff --git a/tests/rustdoc/tuple-struct-where-clause-34928.rs b/tests/rustdoc-html/tuple-struct-where-clause-34928.rs similarity index 100% rename from tests/rustdoc/tuple-struct-where-clause-34928.rs rename to tests/rustdoc-html/tuple-struct-where-clause-34928.rs diff --git a/tests/rustdoc/tuples.link1_i32.html b/tests/rustdoc-html/tuples.link1_i32.html similarity index 100% rename from tests/rustdoc/tuples.link1_i32.html rename to tests/rustdoc-html/tuples.link1_i32.html diff --git a/tests/rustdoc/tuples.link1_t.html b/tests/rustdoc-html/tuples.link1_t.html similarity index 100% rename from tests/rustdoc/tuples.link1_t.html rename to tests/rustdoc-html/tuples.link1_t.html diff --git a/tests/rustdoc/tuples.link2_i32.html b/tests/rustdoc-html/tuples.link2_i32.html similarity index 100% rename from tests/rustdoc/tuples.link2_i32.html rename to tests/rustdoc-html/tuples.link2_i32.html diff --git a/tests/rustdoc/tuples.link2_t.html b/tests/rustdoc-html/tuples.link2_t.html similarity index 100% rename from tests/rustdoc/tuples.link2_t.html rename to tests/rustdoc-html/tuples.link2_t.html diff --git a/tests/rustdoc/tuples.link2_tu.html b/tests/rustdoc-html/tuples.link2_tu.html similarity index 100% rename from tests/rustdoc/tuples.link2_tu.html rename to tests/rustdoc-html/tuples.link2_tu.html diff --git a/tests/rustdoc/tuples.link_unit.html b/tests/rustdoc-html/tuples.link_unit.html similarity index 100% rename from tests/rustdoc/tuples.link_unit.html rename to tests/rustdoc-html/tuples.link_unit.html diff --git a/tests/rustdoc/tuples.rs b/tests/rustdoc-html/tuples.rs similarity index 100% rename from tests/rustdoc/tuples.rs rename to tests/rustdoc-html/tuples.rs diff --git a/tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs b/tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/auxiliary/parent-crate-115718.rs rename to tests/rustdoc-html/type-alias/auxiliary/parent-crate-115718.rs diff --git a/tests/rustdoc/type-alias/cross-crate-115718.rs b/tests/rustdoc-html/type-alias/cross-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/cross-crate-115718.rs rename to tests/rustdoc-html/type-alias/cross-crate-115718.rs diff --git a/tests/rustdoc/type-alias/deeply-nested-112515.rs b/tests/rustdoc-html/type-alias/deeply-nested-112515.rs similarity index 100% rename from tests/rustdoc/type-alias/deeply-nested-112515.rs rename to tests/rustdoc-html/type-alias/deeply-nested-112515.rs diff --git a/tests/rustdoc/type-alias/deref-32077.rs b/tests/rustdoc-html/type-alias/deref-32077.rs similarity index 100% rename from tests/rustdoc/type-alias/deref-32077.rs rename to tests/rustdoc-html/type-alias/deref-32077.rs diff --git a/tests/rustdoc/type-alias/impl_trait_in_assoc_type.rs b/tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs similarity index 100% rename from tests/rustdoc/type-alias/impl_trait_in_assoc_type.rs rename to tests/rustdoc-html/type-alias/impl_trait_in_assoc_type.rs diff --git a/tests/rustdoc/type-alias/primitive-local-link-121106.rs b/tests/rustdoc-html/type-alias/primitive-local-link-121106.rs similarity index 100% rename from tests/rustdoc/type-alias/primitive-local-link-121106.rs rename to tests/rustdoc-html/type-alias/primitive-local-link-121106.rs diff --git a/tests/rustdoc/type-alias/repr.rs b/tests/rustdoc-html/type-alias/repr.rs similarity index 100% rename from tests/rustdoc/type-alias/repr.rs rename to tests/rustdoc-html/type-alias/repr.rs diff --git a/tests/rustdoc/type-alias/same-crate-115718.rs b/tests/rustdoc-html/type-alias/same-crate-115718.rs similarity index 100% rename from tests/rustdoc/type-alias/same-crate-115718.rs rename to tests/rustdoc-html/type-alias/same-crate-115718.rs diff --git a/tests/rustdoc/type-layout-flag-required.rs b/tests/rustdoc-html/type-layout-flag-required.rs similarity index 100% rename from tests/rustdoc/type-layout-flag-required.rs rename to tests/rustdoc-html/type-layout-flag-required.rs diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc-html/type-layout.rs similarity index 100% rename from tests/rustdoc/type-layout.rs rename to tests/rustdoc-html/type-layout.rs diff --git a/tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs similarity index 100% rename from tests/rustdoc/typedef-inner-variants-lazy_type_alias.rs rename to tests/rustdoc-html/typedef-inner-variants-lazy_type_alias.rs diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc-html/typedef-inner-variants.rs similarity index 100% rename from tests/rustdoc/typedef-inner-variants.rs rename to tests/rustdoc-html/typedef-inner-variants.rs diff --git a/tests/rustdoc/typedef.rs b/tests/rustdoc-html/typedef.rs similarity index 100% rename from tests/rustdoc/typedef.rs rename to tests/rustdoc-html/typedef.rs diff --git a/tests/rustdoc/underscore-import-61592.rs b/tests/rustdoc-html/underscore-import-61592.rs similarity index 100% rename from tests/rustdoc/underscore-import-61592.rs rename to tests/rustdoc-html/underscore-import-61592.rs diff --git a/tests/rustdoc/unindent.md b/tests/rustdoc-html/unindent.md similarity index 100% rename from tests/rustdoc/unindent.md rename to tests/rustdoc-html/unindent.md diff --git a/tests/rustdoc/unindent.rs b/tests/rustdoc-html/unindent.rs similarity index 100% rename from tests/rustdoc/unindent.rs rename to tests/rustdoc-html/unindent.rs diff --git a/tests/rustdoc/union-fields-html.rs b/tests/rustdoc-html/union-fields-html.rs similarity index 100% rename from tests/rustdoc/union-fields-html.rs rename to tests/rustdoc-html/union-fields-html.rs diff --git a/tests/rustdoc/union.rs b/tests/rustdoc-html/union.rs similarity index 100% rename from tests/rustdoc/union.rs rename to tests/rustdoc-html/union.rs diff --git a/tests/rustdoc/unit-return.rs b/tests/rustdoc-html/unit-return.rs similarity index 100% rename from tests/rustdoc/unit-return.rs rename to tests/rustdoc-html/unit-return.rs diff --git a/tests/rustdoc/unsafe-binder.rs b/tests/rustdoc-html/unsafe-binder.rs similarity index 100% rename from tests/rustdoc/unsafe-binder.rs rename to tests/rustdoc-html/unsafe-binder.rs diff --git a/tests/rustdoc/use-attr.rs b/tests/rustdoc-html/use-attr.rs similarity index 100% rename from tests/rustdoc/use-attr.rs rename to tests/rustdoc-html/use-attr.rs diff --git a/tests/rustdoc/useless_lifetime_bound.rs b/tests/rustdoc-html/useless_lifetime_bound.rs similarity index 100% rename from tests/rustdoc/useless_lifetime_bound.rs rename to tests/rustdoc-html/useless_lifetime_bound.rs diff --git a/tests/rustdoc/variadic.rs b/tests/rustdoc-html/variadic.rs similarity index 100% rename from tests/rustdoc/variadic.rs rename to tests/rustdoc-html/variadic.rs diff --git a/tests/rustdoc/viewpath-rename.rs b/tests/rustdoc-html/viewpath-rename.rs similarity index 100% rename from tests/rustdoc/viewpath-rename.rs rename to tests/rustdoc-html/viewpath-rename.rs diff --git a/tests/rustdoc/viewpath-self.rs b/tests/rustdoc-html/viewpath-self.rs similarity index 100% rename from tests/rustdoc/viewpath-self.rs rename to tests/rustdoc-html/viewpath-self.rs diff --git a/tests/rustdoc/visibility.rs b/tests/rustdoc-html/visibility.rs similarity index 100% rename from tests/rustdoc/visibility.rs rename to tests/rustdoc-html/visibility.rs diff --git a/tests/rustdoc/where-clause-order.rs b/tests/rustdoc-html/where-clause-order.rs similarity index 100% rename from tests/rustdoc/where-clause-order.rs rename to tests/rustdoc-html/where-clause-order.rs diff --git a/tests/rustdoc/where-sized.rs b/tests/rustdoc-html/where-sized.rs similarity index 100% rename from tests/rustdoc/where-sized.rs rename to tests/rustdoc-html/where-sized.rs diff --git a/tests/rustdoc/where.SWhere_Echo_impl.html b/tests/rustdoc-html/where.SWhere_Echo_impl.html similarity index 100% rename from tests/rustdoc/where.SWhere_Echo_impl.html rename to tests/rustdoc-html/where.SWhere_Echo_impl.html diff --git a/tests/rustdoc/where.SWhere_Simd_item-decl.html b/tests/rustdoc-html/where.SWhere_Simd_item-decl.html similarity index 100% rename from tests/rustdoc/where.SWhere_Simd_item-decl.html rename to tests/rustdoc-html/where.SWhere_Simd_item-decl.html diff --git a/tests/rustdoc/where.SWhere_TraitWhere_item-decl.html b/tests/rustdoc-html/where.SWhere_TraitWhere_item-decl.html similarity index 100% rename from tests/rustdoc/where.SWhere_TraitWhere_item-decl.html rename to tests/rustdoc-html/where.SWhere_TraitWhere_item-decl.html diff --git a/tests/rustdoc/where.alpha_trait_decl.html b/tests/rustdoc-html/where.alpha_trait_decl.html similarity index 100% rename from tests/rustdoc/where.alpha_trait_decl.html rename to tests/rustdoc-html/where.alpha_trait_decl.html diff --git a/tests/rustdoc/where.bravo_trait_decl.html b/tests/rustdoc-html/where.bravo_trait_decl.html similarity index 100% rename from tests/rustdoc/where.bravo_trait_decl.html rename to tests/rustdoc-html/where.bravo_trait_decl.html diff --git a/tests/rustdoc/where.charlie_fn_decl.html b/tests/rustdoc-html/where.charlie_fn_decl.html similarity index 100% rename from tests/rustdoc/where.charlie_fn_decl.html rename to tests/rustdoc-html/where.charlie_fn_decl.html diff --git a/tests/rustdoc/where.golf_type_alias_decl.html b/tests/rustdoc-html/where.golf_type_alias_decl.html similarity index 100% rename from tests/rustdoc/where.golf_type_alias_decl.html rename to tests/rustdoc-html/where.golf_type_alias_decl.html diff --git a/tests/rustdoc/where.rs b/tests/rustdoc-html/where.rs similarity index 100% rename from tests/rustdoc/where.rs rename to tests/rustdoc-html/where.rs diff --git a/tests/rustdoc/whitespace-after-where-clause.enum.html b/tests/rustdoc-html/whitespace-after-where-clause.enum.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.enum.html rename to tests/rustdoc-html/whitespace-after-where-clause.enum.html diff --git a/tests/rustdoc/whitespace-after-where-clause.enum2.html b/tests/rustdoc-html/whitespace-after-where-clause.enum2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.enum2.html rename to tests/rustdoc-html/whitespace-after-where-clause.enum2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.rs b/tests/rustdoc-html/whitespace-after-where-clause.rs similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.rs rename to tests/rustdoc-html/whitespace-after-where-clause.rs diff --git a/tests/rustdoc/whitespace-after-where-clause.struct.html b/tests/rustdoc-html/whitespace-after-where-clause.struct.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.struct.html rename to tests/rustdoc-html/whitespace-after-where-clause.struct.html diff --git a/tests/rustdoc/whitespace-after-where-clause.struct2.html b/tests/rustdoc-html/whitespace-after-where-clause.struct2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.struct2.html rename to tests/rustdoc-html/whitespace-after-where-clause.struct2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.trait.html b/tests/rustdoc-html/whitespace-after-where-clause.trait.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.trait.html rename to tests/rustdoc-html/whitespace-after-where-clause.trait.html diff --git a/tests/rustdoc/whitespace-after-where-clause.trait2.html b/tests/rustdoc-html/whitespace-after-where-clause.trait2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.trait2.html rename to tests/rustdoc-html/whitespace-after-where-clause.trait2.html diff --git a/tests/rustdoc/whitespace-after-where-clause.union.html b/tests/rustdoc-html/whitespace-after-where-clause.union.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.union.html rename to tests/rustdoc-html/whitespace-after-where-clause.union.html diff --git a/tests/rustdoc/whitespace-after-where-clause.union2.html b/tests/rustdoc-html/whitespace-after-where-clause.union2.html similarity index 100% rename from tests/rustdoc/whitespace-after-where-clause.union2.html rename to tests/rustdoc-html/whitespace-after-where-clause.union2.html diff --git a/tests/rustdoc/without-redirect.rs b/tests/rustdoc-html/without-redirect.rs similarity index 100% rename from tests/rustdoc/without-redirect.rs rename to tests/rustdoc-html/without-redirect.rs diff --git a/tests/rustdoc/wrapping.rs b/tests/rustdoc-html/wrapping.rs similarity index 100% rename from tests/rustdoc/wrapping.rs rename to tests/rustdoc-html/wrapping.rs diff --git a/triagebot.toml b/triagebot.toml index fbb2bac2267b..4c3e5c2a5931 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -240,7 +240,7 @@ trigger_files = [ "src/rustdoc-json-types", # Tests - "tests/rustdoc", + "tests/rustdoc-html", "tests/rustdoc-ui", "tests/rustdoc-gui", "tests/rustdoc-js/", @@ -315,7 +315,7 @@ trigger_labels = [ ] trigger_files = [ "src/librustdoc/html/", - "tests/rustdoc/", + "tests/rustdoc-html/", "tests/rustdoc-gui/", "tests/rustdoc-js/", "tests/rustdoc-js-std/", @@ -1638,7 +1638,7 @@ dep-bumps = [ "/src/stage0" = ["bootstrap"] "/tests/run-make" = ["compiler"] "/tests/run-make-cargo" = ["compiler"] -"/tests/rustdoc" = ["rustdoc"] +"/tests/rustdoc-html" = ["rustdoc"] "/tests/rustdoc-gui" = ["rustdoc"] "/tests/rustdoc-js-std" = ["rustdoc"] "/tests/rustdoc-js/" = ["rustdoc"] From 8256623ab478ff8d79f3b0305e002acdb6cbb76d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 3 Jan 2026 16:06:28 +0100 Subject: [PATCH 206/340] Update `rustc-dev-guide` about `tests/rustdoc` renamed into `tests/rustdoc-html` --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- .../{rustdoc-test-suite.md => rustdoc-html-test-suite.md} | 4 ++-- .../src/rustdoc-internals/rustdoc-json-test-suite.md | 2 +- src/doc/rustc-dev-guide/src/tests/compiletest.md | 4 ++-- src/doc/rustc-dev-guide/src/tests/directives.md | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) rename src/doc/rustc-dev-guide/src/rustdoc-internals/{rustdoc-test-suite.md => rustdoc-html-test-suite.md} (98%) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index e80ee6a5137d..2dd07144a78c 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -100,7 +100,7 @@ - [Parallel compilation](./parallel-rustc.md) - [Rustdoc internals](./rustdoc-internals.md) - [Search](./rustdoc-internals/search.md) - - [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md) + - [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md) - [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md) - [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md) - [GPU offload internals](./offload/internals.md) diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md similarity index 98% rename from src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md rename to src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md index 9516968df803..b74405d310eb 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-html-test-suite.md @@ -1,6 +1,6 @@ -# The `rustdoc` test suite +# The `rustdoc-html` test suite -This page is about the test suite named `rustdoc` used to test the HTML output of `rustdoc`. +This page is about the test suite named `rustdoc-html` used to test the HTML output of `rustdoc`. For other rustdoc-specific test suites, see [Rustdoc test suites]. Each test file in this test suite is simply a Rust source file `file.rs` sprinkled with diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md index 5781a12ca44c..7a846b711326 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md @@ -24,7 +24,7 @@ Also, talk about how it works ## jsondocck [jsondocck] processes directives given in comments, to assert that the values in the output are expected. -It's a lot like [htmldocck](./rustdoc-test-suite.md) in that way. +It's a lot like [htmldocck](./rustdoc-html-test-suite.md) in that way. It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to. diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index e0924f8538ef..d69e0a5ce988 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -82,7 +82,7 @@ The following test suites are available, with links for more information: | Test suite | Purpose | |--------------------------------------|--------------------------------------------------------------------------| -| [`rustdoc`][rustdoc-html-tests] | Check HTML output of `rustdoc` | +| [`rustdoc-html`][rustdoc-html-tests] | Check HTML output of `rustdoc` | | [`rustdoc-gui`][rustdoc-gui-tests] | Check `rustdoc`'s GUI using a web browser | | [`rustdoc-js`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index | | [`rustdoc-js-std`][rustdoc-js-tests] | Check `rustdoc`'s search engine and index on the std library docs | @@ -94,7 +94,7 @@ These tests ensure that certain lints that are emitted as part of executing rust are also run when executing rustc. Run-make tests pertaining to rustdoc are typically named `run-make/rustdoc-*/`. -[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md +[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-gui-tests]: ../rustdoc-internals/rustdoc-gui-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.md#testing-the-search-engine [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4852c3623b05..52e1f09dca0f 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -308,12 +308,12 @@ Asked in #### Test-suite-specific directives -The test suites [`rustdoc`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] +The test suites [`rustdoc-html`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests] and [`rustdoc-json`][rustdoc-json-tests] each feature an additional set of directives whose basic syntax resembles the one of compiletest directives but which are ultimately read and checked by separate tools. For more information, please read their respective chapters as linked above. -[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-test-suite.md +[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md [rustdoc-js-tests]: ../rustdoc-internals/search.html#testing-the-search-engine [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md From 3d965bdc282a4a45cf2d5f83794cbe68a316bf60 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 7 Jan 2026 13:15:17 +0000 Subject: [PATCH 207/340] Convert static lifetime to an nll var --- compiler/rustc_borrowck/src/type_check/mod.rs | 10 ++++++++-- ...-to-ptr-unsized-adt-tail-with-static-region.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 097416b4f280..e5aad4cdbd06 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1581,12 +1581,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { .unwrap(); } (None, None) => { + // `struct_tail` returns regions which haven't been mapped + // to nll vars yet so we do it here as `outlives_constraints` + // expects nll vars. + let src_lt = self.universal_regions.to_region_vid(src_lt); + let dst_lt = self.universal_regions.to_region_vid(dst_lt); + // The principalless (no non-auto traits) case: // You can only cast `dyn Send + 'long` to `dyn Send + 'short`. self.constraints.outlives_constraints.push( OutlivesConstraint { - sup: src_lt.as_var(), - sub: dst_lt.as_var(), + sup: src_lt, + sub: dst_lt, locations: location.to_locations(), span: location.to_locations().span(self.body), category: ConstraintCategory::Cast { diff --git a/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs b/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs new file mode 100644 index 000000000000..7319a670c881 --- /dev/null +++ b/tests/ui/cast/ptr-to-ptr-unsized-adt-tail-with-static-region.rs @@ -0,0 +1,15 @@ +//@ check-pass + +// During MIR typeck when casting `*mut dyn Sync + '?x` to +// `*mut Wrap` we compute the tail of `Wrap` as `dyn Sync + 'static`. +// +// This test ensures that we first convert the `'static` lifetime to +// the nll var `'?0` before introducing the region constraint `'?x: 'static`. + +struct Wrap(dyn Sync + 'static); + +fn cast(x: *mut (dyn Sync + 'static)) { + x as *mut Wrap; +} + +fn main() {} From 87195e7a2a5046153ad6b718aa562a862d562ed6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Jan 2026 23:30:40 +0300 Subject: [PATCH 208/340] resolve: Do not query edition too eagerly in `visit_scopes` --- compiler/rustc_resolve/src/ident.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0acf043ffcf..cc05f35b327f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -50,7 +50,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { mut self: CmResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - ctxt: SyntaxContext, + orig_ctxt: SyntaxContext, derive_fallback_lint_id: Option, mut visitor: impl FnMut( &mut CmResolver<'r, 'ra, 'tcx>, @@ -100,7 +100,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 4c. Standard library prelude (de-facto closed, controlled). // 6. Language prelude: builtin attributes (closed, controlled). - let rust_2015 = ctxt.edition().is_rust_2015(); let (ns, macro_kind) = match scope_set { ScopeSet::All(ns) | ScopeSet::Module(ns, _) @@ -123,7 +122,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; - let mut ctxt = ctxt.normalize_to_macros_2_0(); + let mut ctxt = orig_ctxt.normalize_to_macros_2_0(); let mut use_prelude = !module.no_implicit_prelude; loop { @@ -148,7 +147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true } Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..) => true, - Scope::MacroUsePrelude => use_prelude || rust_2015, + Scope::MacroUsePrelude => use_prelude || orig_ctxt.edition().is_rust_2015(), Scope::BuiltinAttrs => true, Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { use_prelude || module_and_extern_prelude || extern_prelude From 12007736ac5dc0a4020464ace43409ec6280f2b6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 00:08:18 +0300 Subject: [PATCH 209/340] resolve: Use `Macros20NormalizedIdent` in more interfaces It allows to avoid expensive double normalization in some cases --- .../rustc_resolve/src/build_reduced_graph.rs | 26 ++++++++-------- compiler/rustc_resolve/src/diagnostics.rs | 6 ++-- compiler/rustc_resolve/src/ident.rs | 26 ++++++++-------- compiler/rustc_resolve/src/imports.rs | 20 ++++++------- compiler/rustc_resolve/src/late.rs | 8 +++-- compiler/rustc_resolve/src/lib.rs | 30 +++++++++++-------- compiler/rustc_resolve/src/macros.rs | 17 +++++------ 7 files changed, 69 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d56ca7c079cb..ac0f388009d6 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -49,13 +49,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn plant_decl_into_local_module( &mut self, parent: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, ) { if let Err(old_decl) = self.try_plant_decl_into_local_module(parent, ident, ns, decl, false) { - self.report_conflict(parent, ident, ns, old_decl, decl); + self.report_conflict(parent, ident.0, ns, old_decl, decl); } } @@ -71,6 +71,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expn_id: LocalExpnId, ) { let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id); + let ident = Macros20NormalizedIdent::new(ident); self.plant_decl_into_local_module(parent, ident, ns, decl); } @@ -78,7 +79,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn define_extern( &self, parent: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, child_index: usize, res: Res, @@ -280,6 +281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) }; let ModChild { ident, res, vis, ref reexport_chain } = *child; + let ident = Macros20NormalizedIdent::new(ident); let span = child_span(self, reexport_chain, res); let res = res.expect_non_local(); let expansion = parent_scope.expansion; @@ -532,7 +534,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if target.name != kw::Underscore { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(target), ns); this.resolution_or_default(current_module, key) .borrow_mut(this) .single_imports @@ -1023,11 +1025,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.potentially_unused_imports.push(import); let import_decl = self.r.new_import_decl(decl, import); + let ident = Macros20NormalizedIdent::new(ident); if ident.name != kw::Underscore && parent == self.r.graph_root { - let norm_ident = Macros20NormalizedIdent::new(ident); // FIXME: this error is technically unnecessary now when extern prelude is split into // two scopes, remove it with lang team approval. - if let Some(entry) = self.r.extern_prelude.get(&norm_ident) + if let Some(entry) = self.r.extern_prelude.get(&ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() && entry.item_decl.is_none() @@ -1038,7 +1040,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } use indexmap::map::Entry; - match self.r.extern_prelude.entry(norm_ident) { + match self.r.extern_prelude.entry(ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); if entry.item_decl.is_some() { @@ -1290,8 +1292,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); if macro_rules { - let ident = ident.normalize_to_macros_2_0(); - self.r.macro_names.insert(ident); + let ident = Macros20NormalizedIdent::new(ident); + self.r.macro_names.insert(ident.0); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { Visibility::Public @@ -1320,8 +1322,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let import_decl = self.r.new_import_decl(decl, import); self.r.plant_decl_into_local_module(self.r.graph_root, ident, MacroNS, import_decl); } else { - self.r.check_reserved_macro_name(ident, res); - self.insert_unused_macro(ident, def_id, item.id); + self.r.check_reserved_macro_name(ident.0, res); + self.insert_unused_macro(ident.0, def_id, item.id); } self.r.feed_visibility(feed, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def( @@ -1488,7 +1490,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { { // Don't add underscore names, they cannot be looked up anyway. let impl_def_id = self.r.tcx.local_parent(local_def_id); - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7c86ed91a07a..71444770ae37 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1187,7 +1187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .get(&expn_id) .into_iter() .flatten() - .map(|(ident, _)| TypoSuggestion::typo_from_ident(*ident, res)), + .map(|(ident, _)| TypoSuggestion::typo_from_ident(ident.0, res)), ); } } @@ -1199,7 +1199,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = macro_rules_def.decl.res(); if filter_fn(res) { suggestions - .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident, res)) + .push(TypoSuggestion::typo_from_ident(macro_rules_def.ident.0, res)) } } } @@ -2892,7 +2892,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } - let binding_key = BindingKey::new(ident, MacroNS); + let binding_key = BindingKey::new(Macros20NormalizedIdent::new(ident), MacroNS); let binding = self.resolution(crate_module, binding_key)?.binding()?; let Res::Def(DefKind::Macro(kinds), _) = binding.res() else { return None; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index cc05f35b327f..811f48925f51 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -519,7 +519,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { - let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let unnorm_ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + let ident = Macros20NormalizedIdent::new(unnorm_ident); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(decl) = self @@ -602,7 +603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors::ProcMacroDeriveResolutionFallback { span: orig_ident.span, ns_descr: ns.descr(), - ident, + ident: unnorm_ident, }, ); } @@ -652,7 +653,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { errors::ProcMacroDeriveResolutionFallback { span: orig_ident.span, ns_descr: ns.descr(), - ident, + ident: unnorm_ident, }, ); } @@ -698,7 +699,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( - ident, + unnorm_ident, ScopeSet::Module(ns, prelude), parent_scope, None, @@ -982,7 +983,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_module_non_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, parent_scope: &ParentScope<'ra>, shadowing: Shadowing, @@ -1005,7 +1006,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( - ident, + ident.0, binding, parent_scope, module, @@ -1045,7 +1046,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_module_globs_unadjusted<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, parent_scope: &ParentScope<'ra>, shadowing: Shadowing, @@ -1066,7 +1067,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(finalize) = finalize { return self.get_mut().finalize_module_binding( - ident, + ident.0, binding, parent_scope, module, @@ -1135,9 +1136,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => return Err(ControlFlow::Continue(Undetermined)), }; let tmp_parent_scope; - let (mut adjusted_parent_scope, mut ident) = - (parent_scope, ident.normalize_to_macros_2_0()); - match ident.span.glob_adjust(module.expansion, glob_import.span) { + let (mut adjusted_parent_scope, mut ident) = (parent_scope, ident); + match ident.0.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => { tmp_parent_scope = ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; @@ -1147,7 +1147,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => continue, }; let result = self.reborrow().resolve_ident_in_scope_set( - ident, + ident.0, ScopeSet::Module(ns, module), adjusted_parent_scope, None, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a8bb53cc7f27..30e980afadec 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -20,7 +20,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use tracing::debug; use crate::Namespace::{self, *}; @@ -330,13 +330,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn try_plant_decl_into_local_module( &mut self, module: Module<'ra>, - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, decl: Decl<'ra>, warn_ambiguity: bool, ) -> Result<(), Decl<'ra>> { let res = decl.res(); - self.check_reserved_macro_name(ident, res); + self.check_reserved_macro_name(ident.0, res); self.set_decl_parent_module(decl, module); // 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 @@ -474,7 +474,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_decl = self.new_import_decl(binding, *import); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, - ident.0, + ident, key.ns, import_decl, warn_ambiguity, @@ -496,11 +496,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let dummy_decl = self.new_import_decl(dummy_decl, import); self.per_ns(|this, ns| { let module = import.parent_scope.module; - let _ = - this.try_plant_decl_into_local_module(module, target, ns, dummy_decl, false); + let ident = Macros20NormalizedIdent::new(target); + let _ = this.try_plant_decl_into_local_module(module, ident, ns, dummy_decl, false); // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(ident, ns); this.update_local_resolution(module, key, false, |_, resolution| { resolution.single_imports.swap_remove(&import); }) @@ -879,7 +879,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let import_decl = this.new_import_decl(binding, import); this.get_mut_unchecked().plant_decl_into_local_module( parent, - target, + Macros20NormalizedIdent::new(target), ns, import_decl, ); @@ -888,7 +888,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(Determinacy::Determined) => { // Don't remove underscores from `single_imports`, they were never added. if target.name != kw::Underscore { - let key = BindingKey::new(target, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(target), ns); this.get_mut_unchecked().update_local_resolution( parent, key, @@ -1504,7 +1504,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, - key.ident.0, + key.ident, key.ns, import_decl, warn_ambiguity, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b4941a6f5b99..33344c64ebc7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -37,7 +37,9 @@ use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym}; +use rustc_span::{ + BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, +}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -3629,7 +3631,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); debug!(?decl); if decl.is_none() { @@ -3640,7 +3642,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { TypeNS => ValueNS, _ => ns, }; - let key = BindingKey::new(ident, ns); + let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns); decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); debug!(?decl); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 063b6b4058f0..36afcb455f23 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -572,17 +572,17 @@ struct BindingKey { } impl BindingKey { - fn new(ident: Ident, ns: Namespace) -> Self { - BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator: 0 } + fn new(ident: Macros20NormalizedIdent, ns: Namespace) -> Self { + BindingKey { ident, ns, disambiguator: 0 } } fn new_disambiguated( - ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, disambiguator: impl FnOnce() -> u32, ) -> BindingKey { let disambiguator = if ident.name == kw::Underscore { disambiguator() } else { 0 }; - BindingKey { ident: Macros20NormalizedIdent::new(ident), ns, disambiguator } + BindingKey { ident, ns, disambiguator } } } @@ -1076,7 +1076,7 @@ impl ExternPreludeEntry<'_> { struct DeriveData { resolutions: Vec, - helper_attrs: Vec<(usize, Ident)>, + helper_attrs: Vec<(usize, Macros20NormalizedIdent)>, has_derive_copy: bool, } @@ -1241,7 +1241,7 @@ pub struct Resolver<'ra, 'tcx> { /// `macro_rules` scopes produced by `macro_rules` item definitions. macro_rules_scopes: FxHashMap>, /// Helper attributes that are in scope for the given expansion. - helper_attrs: FxHashMap)>>, + helper_attrs: FxHashMap)>>, /// Ready or in-progress results of resolving paths inside the `#[derive(...)]` attribute /// with the given `ExpnId`. derive_data: FxHashMap, @@ -2251,20 +2251,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_item<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - ident: Ident, + ident: Macros20NormalizedIdent, finalize: bool, ) -> Option> { - let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_decl).map(|(binding, _)| { + let entry = self.extern_prelude.get(&ident); + entry.and_then(|entry| entry.item_decl).map(|(decl, _)| { if finalize { - self.get_mut().record_use(ident, binding, Used::Scope); + self.get_mut().record_use(ident.0, decl, Used::Scope); } - binding + decl }) } - fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { - let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + fn extern_prelude_get_flag( + &self, + ident: Macros20NormalizedIdent, + finalize: bool, + ) -> Option> { + let entry = self.extern_prelude.get(&ident); entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { let (pending_decl, finalized) = flag_decl.get(); let decl = match pending_decl { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index c9c754374c87..32d686d4f702 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -29,7 +29,7 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use crate::Namespace::*; use crate::errors::{ @@ -52,7 +52,7 @@ pub(crate) struct MacroRulesDecl<'ra> { pub(crate) decl: Decl<'ra>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'ra>, - pub(crate) ident: Ident, + pub(crate) ident: Macros20NormalizedIdent, } /// The scope introduced by a `macro_rules!` macro. @@ -403,13 +403,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { - let last_seg = resolution.path.segments.last().unwrap(); - let span = last_seg.ident.span.normalize_to_macros_2_0(); - entry.helper_attrs.extend( - ext.helper_attrs - .iter() - .map(|name| (i, Ident::new(*name, span))), - ); + let span = resolution.path.segments.last().unwrap().ident.span; + entry.helper_attrs.extend(ext.helper_attrs.iter().map(|name| { + (i, Macros20NormalizedIdent::new(Ident::new(*name, span))) + })); } entry.has_derive_copy |= ext.builtin_name == Some(sym::Copy); ext @@ -530,7 +527,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { target_trait.for_each_child(self, |this, ident, ns, _binding| { // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) - && overriding_keys.contains(&BindingKey::new(ident.0, ns)) + && overriding_keys.contains(&BindingKey::new(ident, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { From 888e28b41b05e2b27f7ba530e1f330dbe852de92 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 01:17:11 +0300 Subject: [PATCH 210/340] resolve: Pass a normalized ident to `resolve_ident_in_scope` In practice it was already normalized because `visit_scopes` normalized it --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++------------- tests/ui/proc-macro/generate-mod.stderr | 10 ---------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 811f48925f51..8baf194e4a06 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -433,12 +433,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { orig_ident.span.ctxt(), derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { + let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); + // The passed `ctxt` is already normalized, so avoid expensive double normalization. + let ident = Macros20NormalizedIdent(ident); let res = match this.reborrow().resolve_ident_in_scope( - orig_ident, + ident, ns, scope, use_prelude, - ctxt, scope_set, parent_scope, // Shadowed decls don't need to be marked as used or non-speculatively loaded. @@ -507,11 +509,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_ident_in_scope<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - orig_ident: Ident, + ident: Macros20NormalizedIdent, ns: Namespace, scope: Scope<'ra>, use_prelude: UsePrelude, - ctxt: SyntaxContext, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, finalize: Option, @@ -519,8 +520,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_decl: Option>, ignore_import: Option>, ) -> Result, ControlFlow> { - let unnorm_ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); - let ident = Macros20NormalizedIdent::new(unnorm_ident); let ret = match scope { Scope::DeriveHelpers(expn_id) => { if let Some(decl) = self @@ -599,11 +598,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, - orig_ident.span, + ident.span, errors::ProcMacroDeriveResolutionFallback { - span: orig_ident.span, + span: ident.span, ns_descr: ns.descr(), - ident: unnorm_ident, + ident: ident.0, }, ); } @@ -649,11 +648,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.get_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, - orig_ident.span, + ident.span, errors::ProcMacroDeriveResolutionFallback { - span: orig_ident.span, + span: ident.span, ns_descr: ns.descr(), - ident: unnorm_ident, + ident: ident.0, }, ); } @@ -699,7 +698,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); if let Some(prelude) = self.prelude && let Ok(decl) = self.reborrow().resolve_ident_in_scope_set( - unnorm_ident, + ident.0, ScopeSet::Module(ns, prelude), parent_scope, None, diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr index af90df2c3dc3..371fd73e507b 100644 --- a/tests/ui/proc-macro/generate-mod.stderr +++ b/tests/ui/proc-macro/generate-mod.stderr @@ -47,7 +47,6 @@ LL | #[derive(generate_mod::CheckDerive)] = 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 #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:18:10 @@ -57,7 +56,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = 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 #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:25:14 @@ -67,7 +65,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = 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 #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:25:14 @@ -77,7 +74,6 @@ LL | #[derive(generate_mod::CheckDerive)] | = 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 #83583 - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors @@ -92,7 +88,6 @@ LL | #[derive(generate_mod::CheckDerive)] = 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 #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope @@ -104,7 +99,6 @@ LL | #[derive(generate_mod::CheckDerive)] = 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 #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `FromOutside` in this scope @@ -116,7 +110,6 @@ LL | #[derive(generate_mod::CheckDerive)] = 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 #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: error: cannot find type `OuterDerive` in this scope @@ -128,7 +121,6 @@ LL | #[derive(generate_mod::CheckDerive)] = 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 #83583 = note: `#[deny(proc_macro_derive_resolution_fallback)]` (part of `#[deny(future_incompatible)]`) on by default - = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: warning: cannot find type `FromOutside` in this scope @@ -139,7 +131,6 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | = 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 #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) Future breakage diagnostic: warning: cannot find type `OuterDeriveLint` in this scope @@ -150,5 +141,4 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed | = 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 #83583 - = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) From 99a7d285d46474e10bb854dccee73484916e3fb7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 7 Jan 2026 17:10:57 +0300 Subject: [PATCH 211/340] resolve: Avoid most allocations in `resolve_ident_in_scope_set` Also evaluate one cheap and often-false condition first --- compiler/rustc_resolve/src/ident.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 8baf194e4a06..6ed99042a43f 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -10,6 +10,7 @@ use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; +use smallvec::SmallVec; use tracing::{debug, instrument}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -396,7 +397,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert!(force || finalize.is_none()); // `finalize` implies `force` // Make sure `self`, `super` etc produce an error when passed to here. - if orig_ident.is_path_segment_keyword() && !matches!(scope_set, ScopeSet::Module(..)) { + if !matches!(scope_set, ScopeSet::Module(..)) && orig_ident.is_path_segment_keyword() { return Err(Determinacy::Determined); } @@ -423,7 +424,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // } // So we have to save the innermost solution and continue searching in outer scopes // to detect potential ambiguities. - let mut innermost_results: Vec<(Decl<'_>, Scope<'_>)> = Vec::new(); + let mut innermost_results: SmallVec<[(Decl<'_>, Scope<'_>); 2]> = SmallVec::new(); let mut determinacy = Determinacy::Determined; // Go through all the scopes and try to resolve the name. From bbdba48aeb9029b0cf95ce3d6b7d417ce2be3860 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 7 Jan 2026 00:03:46 +0100 Subject: [PATCH 212/340] Update tidy check for triagebot path mentions with glob support --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/triagebot.rs | 35 ++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 470b38d5a91c..427e93e56cd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5658,6 +5658,7 @@ dependencies = [ "build_helper", "cargo_metadata 0.21.0", "fluent-syntax", + "globset", "ignore", "miropt-test-tools", "regex", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 47b59543c59c..cbf27ea87a07 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -8,6 +8,7 @@ autobins = false build_helper = { path = "../../build_helper" } cargo_metadata = "0.21" regex = "1" +globset = "0.4.18" miropt-test-tools = { path = "../miropt-test-tools" } walkdir = "2" ignore = "0.4.18" diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 01401c94d730..59cd9d80b07a 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -1,5 +1,6 @@ //! Tidy check to ensure paths mentioned in triagebot.toml exist in the project. +use std::collections::HashSet; use std::path::Path; use toml::Value; @@ -22,6 +23,9 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"] if let Some(Value::Table(mentions)) = config.get("mentions") { + let mut builder = globset::GlobSetBuilder::new(); + let mut glob_entries = Vec::new(); + for (entry_key, entry_val) in mentions.iter() { // If the type is set to something other than "filename", then this is not a path. if entry_val.get("type").is_some_and(|t| t.as_str().unwrap_or_default() != "filename") { @@ -33,8 +37,37 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { let full_path = path.join(clean_path); if !full_path.exists() { + // The full-path doesn't exists, maybe it's a glob, let's add it to the glob set builder + // to be checked against all the file and directories in the repository. + builder.add(globset::Glob::new(&format!("{clean_path}*")).unwrap()); + glob_entries.push(clean_path.to_string()); + } + } + + let gs = builder.build().unwrap(); + + let mut found = HashSet::new(); + let mut matches = Vec::new(); + + // Walk the entire repository and match any entry against the remaining paths + for entry in ignore::WalkBuilder::new(path).build().flatten() { + // Strip the prefix as mentions entries are always relative to the repo + let entry_path = entry.path().strip_prefix(path).unwrap(); + + // Find the matches and add them to the found set + gs.matches_into(entry_path, &mut matches); + found.extend(matches.iter().copied()); + + // Early-exist if all the globs have been matched + if found.len() == glob_entries.len() { + break; + } + } + + for (i, clean_path) in glob_entries.iter().enumerate() { + if !found.contains(&i) { check.error(format!( - "triagebot.toml [mentions.*] contains path '{clean_path}' which doesn't exist" + "triagebot.toml [mentions.*] contains '{clean_path}' which doesn't match any file or directory in the repository" )); } } From f36b249f3fdca81c227075b7dafe61f3014ad508 Mon Sep 17 00:00:00 2001 From: Sergio Giro Date: Wed, 7 Jan 2026 17:29:11 +0000 Subject: [PATCH 213/340] missing_enforced_import_rename: Do not enforce for underscores --- clippy_lints/src/missing_enforced_import_rename.rs | 3 ++- tests/ui-toml/missing_enforced_import_rename/clippy.toml | 3 ++- .../conf_missing_enforced_import_rename.fixed | 1 + .../conf_missing_enforced_import_rename.rs | 1 + .../conf_missing_enforced_import_rename.stderr | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index eeea6dfd5f4b..5dd38cf059c2 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -82,7 +82,8 @@ impl LateLintPass<'_> for ImportRename { && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { - if rename.trim() == name.as_str() { + let trimmed_rename = rename.trim(); + if trimmed_rename == "_" || trimmed_rename == name.as_str() { None } else { Some(import.trim()) diff --git a/tests/ui-toml/missing_enforced_import_rename/clippy.toml b/tests/ui-toml/missing_enforced_import_rename/clippy.toml index 05ba822874d5..11af5b0a3306 100644 --- a/tests/ui-toml/missing_enforced_import_rename/clippy.toml +++ b/tests/ui-toml/missing_enforced_import_rename/clippy.toml @@ -6,5 +6,6 @@ enforced-import-renames = [ { path = "std::clone", rename = "foo" }, { path = "std::thread::sleep", rename = "thread_sleep" }, { path = "std::any::type_name", rename = "ident" }, - { path = "std::sync::Mutex", rename = "StdMutie" } + { path = "std::sync::Mutex", rename = "StdMutie" }, + { path = "std::io::Write", rename = "to_test_rename_as_underscore" } ] diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index 3e882f496985..c96df2884b8d 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -15,6 +15,7 @@ use std::{ sync :: Mutex as StdMutie, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as Map; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index 32255af5117f..662e89157675 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -15,6 +15,7 @@ use std::{ sync :: Mutex, //~^ missing_enforced_import_renames }; +use std::io::Write as _; fn main() { use std::collections::BTreeMap as OopsWrongRename; diff --git a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index 982b144eb872..139331d17619 100644 --- a/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -32,7 +32,7 @@ LL | sync :: Mutex, | ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:20:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:5 | LL | use std::collections::BTreeMap as OopsWrongRename; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map` From ebd0151c81a39b358c6e6e17caf9458b0a4f78b4 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Wed, 7 Jan 2026 10:42:00 -0700 Subject: [PATCH 214/340] Fix the connect_error test on FreeBSD 15+ On FreeBSD 15, the error code returned in this situation changed. It's now ENETUNREACH. I think that error code is reasonable, and it's documented for connect(2), so we should expect that it might be returned. --- library/std/src/net/tcp/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 7c7ef7b2f701..e4a30b80e3df 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -37,7 +37,8 @@ fn connect_error() { e.kind() == ErrorKind::ConnectionRefused || e.kind() == ErrorKind::InvalidInput || e.kind() == ErrorKind::AddrInUse - || e.kind() == ErrorKind::AddrNotAvailable, + || e.kind() == ErrorKind::AddrNotAvailable + || e.kind() == ErrorKind::NetworkUnreachable, "bad error: {} {:?}", e, e.kind() From 870626a390f267fc1a21e0712b6639bde3091c71 Mon Sep 17 00:00:00 2001 From: Immad Mir Date: Wed, 7 Jan 2026 23:10:44 +0530 Subject: [PATCH 215/340] Move issue-12660 to 'ui/cross-crate/ with a descriptive name Author: Immad Mir --- .../issue-12660-aux.rs => cross-crate/auxiliary/aux-12660.rs} | 0 .../cross-crate-unit-struct-reexport.rs} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/ui/{issues/auxiliary/issue-12660-aux.rs => cross-crate/auxiliary/aux-12660.rs} (100%) rename tests/ui/{issues/issue-12660.rs => cross-crate/cross-crate-unit-struct-reexport.rs} (82%) diff --git a/tests/ui/issues/auxiliary/issue-12660-aux.rs b/tests/ui/cross-crate/auxiliary/aux-12660.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-12660-aux.rs rename to tests/ui/cross-crate/auxiliary/aux-12660.rs diff --git a/tests/ui/issues/issue-12660.rs b/tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs similarity index 82% rename from tests/ui/issues/issue-12660.rs rename to tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs index 3aa3426519af..2d4e0c654ef3 100644 --- a/tests/ui/issues/issue-12660.rs +++ b/tests/ui/cross-crate/cross-crate-unit-struct-reexport.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ aux-build:issue-12660-aux.rs +//@ aux-build:aux-12660.rs extern crate issue12660aux; From 5548a84c87c61697454c04b4762a5e55e5bab815 Mon Sep 17 00:00:00 2001 From: wr7 Date: Wed, 7 Jan 2026 10:57:20 -0700 Subject: [PATCH 216/340] Stabilize `slice::element_offset` --- library/core/src/slice/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 889fd4cd65df..1bca13b14ed4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4809,8 +4809,6 @@ impl [T] { /// # Examples /// Basic usage: /// ``` - /// #![feature(substr_range)] - /// /// let nums: &[u32] = &[1, 7, 1, 1]; /// let num = &nums[2]; /// @@ -4819,8 +4817,6 @@ impl [T] { /// ``` /// Returning `None` with an unaligned element: /// ``` - /// #![feature(substr_range)] - /// /// let arr: &[[u32; 2]] = &[[0, 1], [2, 3]]; /// let flat_arr: &[u32] = arr.as_flattened(); /// @@ -4834,7 +4830,7 @@ impl [T] { /// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1 /// ``` #[must_use] - #[unstable(feature = "substr_range", issue = "126769")] + #[stable(feature = "element_offset", since = "CURRENT_RUSTC_VERSION")] pub fn element_offset(&self, element: &T) -> Option { if T::IS_ZST { panic!("elements are zero-sized"); From ac505cc2cb98e625844f7c49b00c58dd90193d7c Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 20 Dec 2025 18:53:58 +0000 Subject: [PATCH 217/340] fix: `str_to_string` wrongly unmangled macros --- clippy_lints/src/strings.rs | 5 +++-- tests/ui/str_to_string.fixed | 14 ++++++++++++++ tests/ui/str_to_string.rs | 14 ++++++++++++++ tests/ui/str_to_string.stderr | 8 +++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 1d0efa46a14c..609504ffc233 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::{MaybeDef, MaybeQPath}; -use clippy_utils::source::{snippet, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::{ SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym, }; @@ -404,7 +404,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { "`to_string()` called on a `&str`", |diag| { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + let (snippet, _) = + snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability); diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability); }, ); diff --git a/tests/ui/str_to_string.fixed b/tests/ui/str_to_string.fixed index 2941c4dbd33d..8713c4f9bc86 100644 --- a/tests/ui/str_to_string.fixed +++ b/tests/ui/str_to_string.fixed @@ -8,3 +8,17 @@ fn main() { msg.to_owned(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_owned(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs index 4c4d2bb18062..b81759e1037b 100644 --- a/tests/ui/str_to_string.rs +++ b/tests/ui/str_to_string.rs @@ -8,3 +8,17 @@ fn main() { msg.to_string(); //~^ str_to_string } + +fn issue16271(key: &[u8]) { + macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + } + + let _value = t!(str::from_utf8(key)).to_string(); + //~^ str_to_string +} diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr index cb7b6b48843a..c0a38c8ebe46 100644 --- a/tests/ui/str_to_string.stderr +++ b/tests/ui/str_to_string.stderr @@ -13,5 +13,11 @@ error: `to_string()` called on a `&str` LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` -error: aborting due to 2 previous errors +error: `to_string()` called on a `&str` + --> tests/ui/str_to_string.rs:22:18 + | +LL | let _value = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` + +error: aborting due to 3 previous errors From 15fc6cfd1ca770891a10ea1eb2ddf2fe05bc2428 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 05:20:23 +0000 Subject: [PATCH 218/340] fix: `string_from_utf8_as_bytes` wrongly unmangled macros --- clippy_lints/src/strings.rs | 3 ++- tests/ui/string_from_utf8_as_bytes.fixed | 10 ++++++++++ tests/ui/string_from_utf8_as_bytes.rs | 10 ++++++++++ tests/ui/string_from_utf8_as_bytes.stderr | 10 ++++++++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 609504ffc233..c0be724bcdee 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -273,6 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { let string_expression = &expressions[0].0; let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability); + let (right_snip, _) = snippet_with_context(cx, right.span, e.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, @@ -280,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", "try", - format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")), + format!("Some(&{snippet_app}[{right_snip}])"), applicability, ); } diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed index 193217114d88..98fa3a4fcf70 100644 --- a/tests/ui/string_from_utf8_as_bytes.fixed +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = Some(&"Hello World!"[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = Some(&s[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs index 49beb19ee40f..6354d5376ad6 100644 --- a/tests/ui/string_from_utf8_as_bytes.rs +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -1,6 +1,16 @@ #![warn(clippy::string_from_utf8_as_bytes)] +macro_rules! test_range { + ($start:expr, $end:expr) => { + $start..$end + }; +} + fn main() { let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); //~^ string_from_utf8_as_bytes + + let s = "Hello World!"; + let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + //~^ string_from_utf8_as_bytes } diff --git a/tests/ui/string_from_utf8_as_bytes.stderr b/tests/ui/string_from_utf8_as_bytes.stderr index 99c8d8ae4eab..bba9ec0caf19 100644 --- a/tests/ui/string_from_utf8_as_bytes.stderr +++ b/tests/ui/string_from_utf8_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary - --> tests/ui/string_from_utf8_as_bytes.rs:4:13 + --> tests/ui/string_from_utf8_as_bytes.rs:10:13 | LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` @@ -7,5 +7,11 @@ LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::string_from_utf8_as_bytes)]` -error: aborting due to 1 previous error +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> tests/ui/string_from_utf8_as_bytes.rs:14:13 + | +LL | let _ = std::str::from_utf8(&s.as_bytes()[test_range!(6, 11)]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&s[test_range!(6, 11)])` + +error: aborting due to 2 previous errors From 2617622015f7294eead28ad6793ba04a3c16a643 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 22:41:03 +0000 Subject: [PATCH 219/340] fix: `redundant_pattern_matching` wrongly unmangled macros --- .../src/matches/redundant_pattern_match.rs | 9 +++---- .../redundant_pattern_matching_result.fixed | 20 ++++++++++++++++ tests/ui/redundant_pattern_matching_result.rs | 24 +++++++++++++++++++ .../redundant_pattern_matching_result.stderr | 19 ++++++++++++++- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 897e7da5a967..bf0c0c4aec3c 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -267,13 +267,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized && let Some((good_method, maybe_guard)) = found_good_method(cx, arms) { - let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span)); + let expr_span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span); + let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, _ => op, }; let mut app = Applicability::MachineApplicable; - let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren(); + let receiver_sugg = Sugg::hir_with_context(cx, result_expr, expr_span.ctxt(), "_", &mut app).maybe_paren(); let mut sugg = format!("{receiver_sugg}.{good_method}"); if let Some(guard) = maybe_guard { @@ -296,14 +297,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op return; } - let guard = Sugg::hir(cx, guard, ".."); + let guard = Sugg::hir_with_context(cx, guard, expr_span.ctxt(), "..", &mut app); let _ = write!(sugg, " && {}", guard.maybe_paren()); } span_lint_and_sugg( cx, REDUNDANT_PATTERN_MATCHING, - span, + expr_span, format!("redundant pattern matching, consider using `{good_method}`"), "try", sugg, diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index 261d82fc35c8..8754d71aa629 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -165,3 +165,23 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).is_ok(); + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = x.is_ok() && test_guard!(42); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index 6cae4cc4b6b0..b83b02588fb6 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -205,3 +205,27 @@ fn issue10803() { // Don't lint let _ = matches!(x, Err(16)); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ redundant_pattern_matching + Ok(_) => true, + Err(_) => false, + }; + + macro_rules! test_guard { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x: Result = Ok(42); + let _ = matches!(x, Ok(_) if test_guard!(42)); + //~^ redundant_pattern_matching +} diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index 7e7d27d07a7f..dda203b753c3 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -209,5 +209,22 @@ error: redundant pattern matching, consider using `is_err()` LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` -error: aborting due to 28 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:216:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(_) => true, +LL | | Err(_) => false, +LL | | }; + | |_____^ help: try: `test_expr!(42).is_ok()` + +error: redundant pattern matching, consider using `is_ok()` + --> tests/ui/redundant_pattern_matching_result.rs:229:13 + | +LL | let _ = matches!(x, Ok(_) if test_guard!(42)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok() && test_guard!(42)` + +error: aborting due to 30 previous errors From 02e4f853efb393887dea4f481352e107e8d07998 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 22:58:07 +0000 Subject: [PATCH 220/340] fix: `unnecessary_fold` wrongly unmangled macros --- clippy_lints/src/methods/unnecessary_fold.rs | 7 ++++--- tests/ui/unnecessary_fold.fixed | 11 +++++++++++ tests/ui/unnecessary_fold.rs | 11 +++++++++++ tests/ui/unnecessary_fold.stderr | 10 +++++++++- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 7802763ef74a..c3f031edff2e 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs}; use rustc_ast::ast; use rustc_data_structures::packed::Pu128; @@ -124,11 +124,12 @@ fn check_fold_with_op( let mut applicability = replacement.default_applicability(); let turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); + let (r_snippet, _) = + snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability); let sugg = if replacement.has_args { format!( - "{method}{turbofish}(|{second_arg_ident}| {r})", + "{method}{turbofish}(|{second_arg_ident}| {r_snippet})", method = replacement.method_name, - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!("{method}{turbofish}()", method = replacement.method_name) diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index c3eeafbc39cd..d51359349cb9 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).any(|x| test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index 6ab41a942625..c6eb7157ab12 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -178,4 +178,15 @@ fn issue10000() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($e:expr) => { + ($e + 1) > 2 + }; + } + + let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + //~^ unnecessary_fold +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index 025a2bd0048b..560427a681a9 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -203,5 +203,13 @@ error: this `.fold` can be written more succinctly using another method LL | (0..3).fold(1, |acc, x| acc * x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` -error: aborting due to 32 previous errors +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:188:20 + | +LL | let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| test_expr!(x))` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects + +error: aborting due to 33 previous errors From 0cfbe56d0497f2210314c4101adff6bc74ea97f7 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:07:31 +0000 Subject: [PATCH 221/340] fix: `match_as_ref` wrongly unmangled macros --- clippy_lints/src/matches/match_as_ref.rs | 5 +++-- tests/ui/match_as_ref.fixed | 10 ++++++++++ tests/ui/match_as_ref.rs | 14 ++++++++++++++ tests/ui/match_as_ref.stderr | 23 ++++++++++++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index 795355f25f9e..12fe44ef2f13 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -46,6 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: let cast = if input_ty == output_ty { "" } else { ".map(|x| x as _)" }; let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); span_lint_and_then( cx, MATCH_AS_REF, @@ -59,7 +60,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: "use `Option::as_ref()`", format!( "{}.as_ref(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); @@ -69,7 +70,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: format!("use `Option::{method}()` directly"), format!( "{}.{method}(){cast}", - Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(), + Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(), ), applicability, ); diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 09a6ed169390..b1b8ffb885f5 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -90,3 +90,13 @@ fn issue15932() { let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = test_expr!(42).as_ref(); +} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 347b6d186887..3113167957d4 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -114,3 +114,17 @@ fn issue15932() { Some(ref mut v) => Some(v), }; } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let _: Option<&u32> = match test_expr!(42) { + //~^ match_as_ref + None => None, + Some(ref v) => Some(v), + }; +} diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index df06e358f296..3eab499fe409 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -127,5 +127,26 @@ LL - }; LL + let _: Option<&dyn std::fmt::Debug> = Some(0).as_ref().map(|x| x as _); | -error: aborting due to 6 previous errors +error: manual implementation of `Option::as_ref` + --> tests/ui/match_as_ref.rs:125:27 + | +LL | let _: Option<&u32> = match test_expr!(42) { + | ___________________________^ +LL | | +LL | | None => None, +LL | | Some(ref v) => Some(v), +LL | | }; + | |_____^ + | +help: use `Option::as_ref()` directly + | +LL - let _: Option<&u32> = match test_expr!(42) { +LL - +LL - None => None, +LL - Some(ref v) => Some(v), +LL - }; +LL + let _: Option<&u32> = test_expr!(42).as_ref(); + | + +error: aborting due to 7 previous errors From 9d08eb487bdac4927386bbfaaba71ef6bfd73ff1 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:13:18 +0000 Subject: [PATCH 222/340] fix: `match_bool` wrongly unmangled macros --- clippy_lints/src/matches/match_bool.rs | 5 +++-- tests/ui/match_bool.fixed | 11 +++++++++++ tests/ui/match_bool.rs | 15 +++++++++++++++ tests/ui/match_bool.stderr | 12 +++++++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs index dc3457aa7a46..3e76231b6ef1 100644 --- a/clippy_lints/src/matches/match_bool.rs +++ b/clippy_lints/src/matches/match_bool.rs @@ -25,8 +25,9 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] "`match` on a boolean expression", move |diag| { let mut app = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind { - let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app); + let test = Sugg::hir_with_context(cx, scrutinee, ctxt, "_", &mut app); if let PatExprKind::Lit { lit, .. } = arm_bool.kind { match &lit.node { LitKind::Bool(true) => Some(test), @@ -36,7 +37,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] .map(|test| { if let Some(guard) = &arms[0] .guard - .map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app)) + .map(|g| Sugg::hir_with_context(cx, g, ctxt, "_", &mut app)) { test.and(guard) } else { diff --git a/tests/ui/match_bool.fixed b/tests/ui/match_bool.fixed index 876ae935afde..3d5d0a0d532c 100644 --- a/tests/ui/match_bool.fixed +++ b/tests/ui/match_bool.fixed @@ -74,4 +74,15 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + if test_expr!(x) { 1 } else { 0 }; +} + fn main() {} diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs index a134ad8346e2..4db0aedf3260 100644 --- a/tests/ui/match_bool.rs +++ b/tests/ui/match_bool.rs @@ -126,4 +126,19 @@ fn issue15351() { } } +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val + 1) > 0 + }; + } + + let x = 5; + match test_expr!(x) { + //~^ match_bool + true => 1, + false => 0, + }; +} + fn main() {} diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr index c05742e56339..223acd17aead 100644 --- a/tests/ui/match_bool.stderr +++ b/tests/ui/match_bool.stderr @@ -183,5 +183,15 @@ LL + break 'a; LL + } } | -error: aborting due to 13 previous errors +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:137:5 + | +LL | / match test_expr!(x) { +LL | | +LL | | true => 1, +LL | | false => 0, +LL | | }; + | |_____^ help: consider using an `if`/`else` expression: `if test_expr!(x) { 1 } else { 0 }` + +error: aborting due to 14 previous errors From 908860ed106e1540741bf7d2cbd5877bc62ef3ea Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Fri, 2 Jan 2026 23:20:24 +0000 Subject: [PATCH 223/340] fix: `match_ok_err` wrongly unmangled macros --- clippy_lints/src/matches/manual_ok_err.rs | 2 +- tests/ui/manual_ok_err.fixed | 10 ++++++++++ tests/ui/manual_ok_err.rs | 14 ++++++++++++++ tests/ui/manual_ok_err.stderr | 13 ++++++++++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/manual_ok_err.rs b/clippy_lints/src/matches/manual_ok_err.rs index c35c3d1f62e6..1fc8bb9acce2 100644 --- a/clippy_lints/src/matches/manual_ok_err.rs +++ b/clippy_lints/src/matches/manual_ok_err.rs @@ -135,7 +135,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok } else { Applicability::MachineApplicable }; - let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren(); + let scrut = Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_paren(); let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee); let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty); diff --git a/tests/ui/manual_ok_err.fixed b/tests/ui/manual_ok_err.fixed index 9b70ce0df43a..e22f91a0155f 100644 --- a/tests/ui/manual_ok_err.fixed +++ b/tests/ui/manual_ok_err.fixed @@ -127,3 +127,13 @@ mod issue15051 { result_with_ref_mut(x).as_mut().ok() } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = test_expr!(42).ok(); +} diff --git a/tests/ui/manual_ok_err.rs b/tests/ui/manual_ok_err.rs index dee904638245..c1355f0d4096 100644 --- a/tests/ui/manual_ok_err.rs +++ b/tests/ui/manual_ok_err.rs @@ -177,3 +177,17 @@ mod issue15051 { } } } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + Ok::($val) + }; + } + + let _ = match test_expr!(42) { + //~^ manual_ok_err + Ok(v) => Some(v), + Err(_) => None, + }; +} diff --git a/tests/ui/manual_ok_err.stderr b/tests/ui/manual_ok_err.stderr index 448fbffc0509..0c2ed368eb97 100644 --- a/tests/ui/manual_ok_err.stderr +++ b/tests/ui/manual_ok_err.stderr @@ -141,5 +141,16 @@ LL | | Err(_) => None, LL | | } | |_________^ help: replace with: `result_with_ref_mut(x).as_mut().ok()` -error: aborting due to 12 previous errors +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:188:13 + | +LL | let _ = match test_expr!(42) { + | _____________^ +LL | | +LL | | Ok(v) => Some(v), +LL | | Err(_) => None, +LL | | }; + | |_____^ help: replace with: `test_expr!(42).ok()` + +error: aborting due to 13 previous errors From 8ccfc833a03dec7f84a01abc54b8e8a7d24bd09b Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 3 Jan 2026 01:59:18 +0000 Subject: [PATCH 224/340] fix: `for_kv_map` wrongly unmangled macros --- clippy_lints/src/loops/for_kv_map.rs | 24 +++++++++++++++++------- clippy_lints/src/loops/mod.rs | 2 +- tests/ui/for_kv_map.fixed | 17 +++++++++++++++++ tests/ui/for_kv_map.rs | 17 +++++++++++++++++ tests/ui/for_kv_map.stderr | 14 +++++++++++++- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 39b2391c98ec..7fb8e51377a2 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,16 +1,22 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; use clippy_utils::{pat_is_wild, sugg}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Span, sym}; /// Checks for the `FOR_KV_MAP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, +) { let pat_span = pat.span; if let PatKind::Tuple(pat, _) = pat.kind @@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) + && let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt()) + { span_lint_and_then( cx, FOR_KV_MAP, arg_span, format!("you seem to want to iterate on a map's {kind}s"), |diag| { - let map = sugg::Sugg::hir(cx, arg, "map"); + let mut applicability = Applicability::MachineApplicable; + let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability); + let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability); diag.multipart_suggestion( "use the corresponding method", vec![ - (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (pat_span, pat.to_string()), (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())), ], - Applicability::MachineApplicable, + applicability, ); }, ); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index ddc783069385..83574cab6b67 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -943,7 +943,7 @@ impl Loops { explicit_counter_loop::check(cx, pat, arg, body, expr, label); } self.check_for_loop_arg(cx, pat, arg); - for_kv_map::check(cx, pat, arg, body); + for_kv_map::check(cx, pat, arg, body, span); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr, self.msrv); diff --git a/tests/ui/for_kv_map.fixed b/tests/ui/for_kv_map.fixed index 2a68b7443fbf..6ec4cb01ffd1 100644 --- a/tests/ui/for_kv_map.fixed +++ b/tests/ui/for_kv_map.fixed @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for v in test_map!(wrapped).values() { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs index 485a97815e3c..19e907ff10a6 100644 --- a/tests/ui/for_kv_map.rs +++ b/tests/ui/for_kv_map.rs @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for (_, v) in test_map!(wrapped) { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr index 0bd474a10682..5436592f2ab6 100644 --- a/tests/ui/for_kv_map.stderr +++ b/tests/ui/for_kv_map.stderr @@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm { LL + 'label: for k in rm.keys() { | -error: aborting due to 6 previous errors +error: you seem to want to iterate on a map's values + --> tests/ui/for_kv_map.rs:84:19 + | +LL | for (_, v) in test_map!(wrapped) { + | ^^^^^^^^^^^^^^^^^^ + | +help: use the corresponding method + | +LL - for (_, v) in test_map!(wrapped) { +LL + for v in test_map!(wrapped).values() { + | + +error: aborting due to 7 previous errors From 209e4d7d853950574dab187d360d71a479ce2402 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sat, 3 Jan 2026 02:40:38 +0000 Subject: [PATCH 225/340] fix: `question_mark` wrongly unmangled macros --- clippy_lints/src/question_mark.rs | 7 ++++--- tests/ui/question_mark.fixed | 17 ++++++++++++++++- tests/ui/question_mark.rs | 22 +++++++++++++++++++++- tests/ui/question_mark.stderr | 19 ++++++++++++++++++- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 59d31f782bc3..e5fb3c0fa431 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -5,7 +5,7 @@ use clippy_config::types::MatchLintBehaviour; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::usage::local_used_after_expr; @@ -147,7 +147,8 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && !span_contains_cfg(cx, els.span) { let mut applicability = Applicability::MaybeIncorrect; - let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren(); + let init_expr_str = + Sugg::hir_with_context(cx, init_expr, stmt.span.ctxt(), "..", &mut applicability).maybe_paren(); // Take care when binding is `ref` let sugg = if let PatKind::Binding( BindingMode(ByRef::Yes(_, ref_mutability), binding_mutability), @@ -295,7 +296,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex && (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block)) { let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let receiver_str = snippet_with_context(cx, caller.span, expr.span.ctxt(), "..", &mut applicability).0; let by_ref = !cx.type_is_copy_modulo_regions(caller_ty) && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 2c5ee0245038..b8072932c4ea 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -500,3 +500,18 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let x = test_expr!(42)?; + //~^^^ question_mark + Some(x); + + test_expr!(42)?; + test_expr!(42) +} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index b9ff9d1565b2..b320dcd4b0bc 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,5 +1,5 @@ #![feature(try_blocks)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::no_effect)] use std::sync::MutexGuard; @@ -615,3 +615,23 @@ mod issue14894 { Ok(()) } } + +fn wrongly_unmangled_macros() -> Option { + macro_rules! test_expr { + ($val:expr) => { + Some($val) + }; + } + + let Some(x) = test_expr!(42) else { + return None; + }; + //~^^^ question_mark + Some(x); + + if test_expr!(42).is_none() { + //~^ question_mark + return None; + } + test_expr!(42) +} diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 9b2896328e66..d645c8830adc 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -333,5 +333,22 @@ LL | | return Err(reason); LL | | } | |_________^ help: replace it with: `result?;` -error: aborting due to 35 previous errors +error: this `let...else` may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:626:5 + | +LL | / let Some(x) = test_expr!(42) else { +LL | | return None; +LL | | }; + | |______^ help: replace it with: `let x = test_expr!(42)?;` + +error: this block may be rewritten with the `?` operator + --> tests/ui/question_mark.rs:632:5 + | +LL | / if test_expr!(42).is_none() { +LL | | +LL | | return None; +LL | | } + | |_____^ help: replace it with: `test_expr!(42)?;` + +error: aborting due to 37 previous errors From 108436c6f98acc83b2a281465bc96ed505bbcb95 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Sun, 4 Jan 2026 20:57:16 +0000 Subject: [PATCH 226/340] fix: `iter_kv_map` wrongly unmangled macros --- clippy_lints/src/methods/iter_kv_map.rs | 7 ++++--- tests/ui/iter_kv_map.fixed | 6 ++++++ tests/ui/iter_kv_map.rs | 6 ++++++ tests/ui/iter_kv_map.stderr | 8 +++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index 16db8663941e..366bfaed73d4 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -2,7 +2,7 @@ use super::ITER_KV_MAP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::{pat_is_wild, sym}; use rustc_hir::{Body, Expr, ExprKind, PatKind}; use rustc_lint::LateContext; @@ -58,6 +58,8 @@ pub(super) fn check<'tcx>( applicability, ); } else { + let (body_snippet, _) = + snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability); span_lint_and_sugg( cx, ITER_KV_MAP, @@ -65,9 +67,8 @@ pub(super) fn check<'tcx>( format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})", annotation.prefix_str(), - snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) ), applicability, ); diff --git a/tests/ui/iter_kv_map.fixed b/tests/ui/iter_kv_map.fixed index b18dda358877..189d76bc9431 100644 --- a/tests/ui/iter_kv_map.fixed +++ b/tests/ui/iter_kv_map.fixed @@ -189,3 +189,9 @@ fn issue14595() { let _ = map.as_ref().values().copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.keys().map(|key| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.rs b/tests/ui/iter_kv_map.rs index 729e4e8a266c..cfc303447004 100644 --- a/tests/ui/iter_kv_map.rs +++ b/tests/ui/iter_kv_map.rs @@ -193,3 +193,9 @@ fn issue14595() { let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); //~^ iter_kv_map } + +fn issue16340() { + let hm: HashMap<&str, &str> = HashMap::new(); + let _ = hm.iter().map(|(key, _)| vec![key]); + //~^ iter_kv_map +} diff --git a/tests/ui/iter_kv_map.stderr b/tests/ui/iter_kv_map.stderr index 8f73541f5033..866e69ea1922 100644 --- a/tests/ui/iter_kv_map.stderr +++ b/tests/ui/iter_kv_map.stderr @@ -269,5 +269,11 @@ error: iterating on a map's values LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` -error: aborting due to 39 previous errors +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:199:13 + | +LL | let _ = hm.iter().map(|(key, _)| vec![key]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])` + +error: aborting due to 40 previous errors From 8c129e4219c21a0aafd2c8446ab57f0d76154ec7 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Mon, 5 Jan 2026 17:50:50 +0000 Subject: [PATCH 227/340] fix: `mutex_atomic` wrongly unmangled macros --- clippy_lints/src/mutex_atomic.rs | 2 +- tests/ui/mutex_atomic.fixed | 12 ++++++++++++ tests/ui/mutex_atomic.rs | 12 ++++++++++++ tests/ui/mutex_atomic.stderr | 10 +++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 2fef8404f824..ad44d65b4d66 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -143,7 +143,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T && new.ident.name == sym::new { let mut applicability = Applicability::MaybeIncorrect; - let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability); + let arg = Sugg::hir_with_context(cx, arg, expr.span.ctxt(), "_", &mut applicability); let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))]; match ty_ascription { TypeAscriptionKind::Required(ty_ascription) => { diff --git a/tests/ui/mutex_atomic.fixed b/tests/ui/mutex_atomic.fixed index e4218726019f..dc05d8a2c61f 100644 --- a/tests/ui/mutex_atomic.fixed +++ b/tests/ui/mutex_atomic.fixed @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = std::sync::atomic::AtomicBool::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index 95f2b135903f..33745f8fc5e1 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -65,3 +65,15 @@ fn issue13378() { let (funky_mtx): Mutex = Mutex::new(0); //~^ mutex_integer } + +fn wrongly_unmangled_macros() { + macro_rules! test_expr { + ($val:expr) => { + ($val > 0 && true) + }; + } + + let _ = Mutex::new(test_expr!(1)); + //~^ mutex_atomic + // The suggestion should preserve the macro call: `AtomicBool::new(test_expr!(true))` +} diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 0afc6d541dea..56d94035583c 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -130,5 +130,13 @@ LL - let (funky_mtx): Mutex = Mutex::new(0); LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0); | -error: aborting due to 14 previous errors +error: using a `Mutex` where an atomic would do + --> tests/ui/mutex_atomic.rs:76:13 + | +LL | let _ = Mutex::new(test_expr!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(test_expr!(1))` + | + = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>` + +error: aborting due to 15 previous errors From f82dd820a51b5b7ea20b257bce7d891269e2d2e6 Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Wed, 7 Jan 2026 22:31:33 +0200 Subject: [PATCH 228/340] Use `rand` crate more idiomatically --- library/alloctests/benches/btree/map.rs | 4 +++- library/alloctests/tests/sort/patterns.rs | 15 +++++++-------- library/coretests/benches/num/int_bits/mod.rs | 7 ++++--- library/coretests/benches/num/int_sqrt/mod.rs | 17 +++++++++++------ 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/library/alloctests/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs index 778065fd9657..c2bf43caf131 100644 --- a/library/alloctests/benches/btree/map.rs +++ b/library/alloctests/benches/btree/map.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::ops::RangeBounds; use rand::Rng; +use rand::distr::{Distribution, Uniform}; use rand::seq::SliceRandom; use test::{Bencher, black_box}; @@ -106,7 +107,8 @@ macro_rules! map_find_rand_bench { // setup let mut rng = crate::bench_rng(); - let mut keys: Vec<_> = (0..n).map(|_| rng.random::() % n).collect(); + let mut keys: Vec<_> = + Uniform::new(0, n).unwrap().sample_iter(&mut rng).take(n as usize).collect(); for &k in &keys { map.insert(k, k); diff --git a/library/alloctests/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs index 0f1ec664d3d4..1ed645cf99dc 100644 --- a/library/alloctests/tests/sort/patterns.rs +++ b/library/alloctests/tests/sort/patterns.rs @@ -27,21 +27,20 @@ where { // :.:.:.:: - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); // Abstracting over ranges in Rust :( let dist = Uniform::try_from(range).unwrap(); - (0..len).map(|_| dist.sample(&mut rng)).collect() + rng.sample_iter(dist).take(len).collect() } pub fn random_zipf(len: usize, exponent: f64) -> Vec { // https://en.wikipedia.org/wiki/Zipf's_law - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - // Abstracting over ranges in Rust :( let dist = ZipfDistribution::new(len, exponent).unwrap(); - (0..len).map(|_| dist.sample(&mut rng) as i32).collect() + rng.sample_iter(dist).map(|val| val as i32).take(len).collect() } pub fn random_sorted(len: usize, sorted_percent: f64) -> Vec { @@ -68,7 +67,7 @@ pub fn all_equal(len: usize) -> Vec { // ...... // :::::: - (0..len).map(|_| 66).collect::>() + vec![66; len] } pub fn ascending(len: usize) -> Vec { @@ -206,6 +205,6 @@ fn rand_root_seed() -> u64 { } fn random_vec(len: usize) -> Vec { - let mut rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); - (0..len).map(|_| rng.random::()).collect() + let rng: XorShiftRng = rand::SeedableRng::seed_from_u64(get_or_init_rand_seed()); + rng.random_iter().take(len).collect() } diff --git a/library/coretests/benches/num/int_bits/mod.rs b/library/coretests/benches/num/int_bits/mod.rs index 43531b0b5de9..c6ec51f248ba 100644 --- a/library/coretests/benches/num/int_bits/mod.rs +++ b/library/coretests/benches/num/int_bits/mod.rs @@ -4,11 +4,12 @@ macro_rules! bench_template { ($op:path, $name:ident, $mask:expr) => { #[bench] fn $name(bench: &mut ::test::Bencher) { - use ::rand::Rng; + use ::rand::distr::{Distribution, Uniform}; 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(); + let distr = &Uniform::try_from(0..=U::MAX).unwrap(); + let src1: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); + let mut src2: Vec = distr.sample_iter(&mut rng).take(ITERATIONS).collect(); // Fix the loop invariant mask src2[0] = U::MAX / 3; let dst = dst.first_chunk_mut().unwrap(); diff --git a/library/coretests/benches/num/int_sqrt/mod.rs b/library/coretests/benches/num/int_sqrt/mod.rs index 05cb3c5383b2..56172f71dd88 100644 --- a/library/coretests/benches/num/int_sqrt/mod.rs +++ b/library/coretests/benches/num/int_sqrt/mod.rs @@ -1,3 +1,5 @@ +use std::iter; + use rand::Rng; use test::{Bencher, black_box}; @@ -20,7 +22,9 @@ macro_rules! int_sqrt_bench { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ let numbers: Vec<$t> = - (0..256).map(|_| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)).collect(); + iter::repeat_with(|| rng.random::<$t>() >> rng.random_range(0..<$t>::BITS)) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -32,9 +36,10 @@ macro_rules! int_sqrt_bench { fn $random_small(bench: &mut Bencher) { let mut rng = crate::bench_rng(); /* Exponentially distributed random numbers from the range 0..256. */ - let numbers: Vec<$t> = (0..256) - .map(|_| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) - .collect(); + let numbers: Vec<$t> = + iter::repeat_with(|| (rng.random::() >> rng.random_range(0..u8::BITS)) as $t) + .take(256) + .collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); @@ -44,9 +49,9 @@ macro_rules! int_sqrt_bench { #[bench] fn $random_uniform(bench: &mut Bencher) { - let mut rng = crate::bench_rng(); + let rng = crate::bench_rng(); /* Exponentially distributed random numbers from the whole range of the type. */ - let numbers: Vec<$t> = (0..256).map(|_| rng.random::<$t>()).collect(); + let numbers: Vec<$t> = rng.random_iter().take(256).collect(); bench.iter(|| { for x in &numbers { black_box(black_box(x).isqrt()); From 138cc27f490aac4f98325a27853c3b0d7d25ae77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 22:45:41 +0100 Subject: [PATCH 229/340] Update bors e-mail lookup --- .github/workflows/post-merge.yml | 2 +- src/build_helper/src/git.rs | 24 ++++++++++++++++++++++-- src/stage0 | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index d38cc0e8a17f..51e0a40d46f2 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -29,7 +29,7 @@ jobs: sleep 60 # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 42d9b00f004a..1fdc2ddb4cfc 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -152,6 +152,14 @@ pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool { }) } +const LEGACY_BORS_EMAIL: &str = "bors@rust-lang.org"; + +/// Escape characters from the git user e-mail, so that git commands do not interpret it as regex +/// special characters. +fn escape_email_git_regex(text: &str) -> String { + text.replace("[", "\\[").replace("]", "\\]").replace(".", "\\.") +} + /// Returns the latest upstream commit that modified `target_paths`, or `None` if no such commit /// was found. fn get_latest_upstream_commit_that_modified_files( @@ -182,9 +190,15 @@ fn get_latest_upstream_commit_that_modified_files( "-n1", &upstream, "--author", - git_config.git_merge_commit_email, + &escape_email_git_regex(git_config.git_merge_commit_email), ]); + // Also search for legacy bors account, before we accrue enough commits to + // have changes to all relevant file paths done by new bors. + if git_config.git_merge_commit_email != LEGACY_BORS_EMAIL { + git.args(["--author", LEGACY_BORS_EMAIL]); + } + if !target_paths.is_empty() { git.arg("--").args(target_paths); } @@ -229,11 +243,17 @@ pub fn get_closest_upstream_commit( git.args([ "rev-list", "--author-date-order", - &format!("--author={}", config.git_merge_commit_email), + &format!("--author={}", &escape_email_git_regex(config.git_merge_commit_email),), "-n1", base, ]); + // Also search for legacy bors account, before we accrue enough commits to + // have changes to all relevant file paths done by new bors. + if config.git_merge_commit_email != LEGACY_BORS_EMAIL { + git.args(["--author", LEGACY_BORS_EMAIL]); + } + let output = output_result(&mut git)?.trim().to_owned(); if output.is_empty() { Ok(None) } else { Ok(Some(output)) } } diff --git a/src/stage0 b/src/stage0 index 66b652a844f3..226f1d6f645e 100644 --- a/src/stage0 +++ b/src/stage0 @@ -1,7 +1,7 @@ dist_server=https://static.rust-lang.org artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt -git_merge_commit_email=bors@rust-lang.org +git_merge_commit_email=122020455+rust-bors[bot]@users.noreply.github.com nightly_branch=main # The configuration above this comment is editable, and can be changed From f2d0d52c2fe5c6719480b422578038000fcfa00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Jan 2026 22:50:35 +0100 Subject: [PATCH 230/340] Remove unused environment variable Its last use was removed in https://github.com/rust-lang/rust/pull/142827. --- src/ci/docker/run.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 044f5a8fff32..691b8b8deb81 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -312,16 +312,6 @@ else command=(/checkout/src/ci/run.sh) fi -if isCI; then - # Get some needed information for $BASE_COMMIT - # - # This command gets the last merge commit which we'll use as base to list - # deleted files since then. - BASE_COMMIT="$(git log --author=bors@rust-lang.org -n 2 --pretty=format:%H | tail -n 1)" -else - BASE_COMMIT="" -fi - SUMMARY_FILE=github-summary.md touch $objdir/${SUMMARY_FILE} @@ -359,7 +349,6 @@ docker \ --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \ --env CI_JOB_NAME="${CI_JOB_NAME-$image}" \ --env CI_JOB_DOC_URL="${CI_JOB_DOC_URL}" \ - --env BASE_COMMIT="$BASE_COMMIT" \ --env DIST_TRY_BUILD \ --env PR_CI_JOB \ --env OBJDIR_ON_HOST="$objdir" \ From ac0b17bcf94517c301d4abd9c0278ab180c3248d Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Wed, 7 Jan 2026 22:32:16 +0000 Subject: [PATCH 231/340] fix: `unnecessary_to_owned` wrongly unmangled macros --- .../src/methods/unnecessary_to_owned.rs | 22 +++++++++++-------- tests/ui/unnecessary_to_owned.fixed | 9 ++++++++ tests/ui/unnecessary_to_owned.rs | 9 ++++++++ tests/ui/unnecessary_to_owned.stderr | 8 ++++++- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index a6a39cb6ab30..74e8dbc15a6c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_context}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; @@ -131,8 +131,10 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_parent_id)) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( cx, @@ -145,7 +147,7 @@ fn check_addr_of_expr( "", width = n_target_refs - n_receiver_refs ), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -165,8 +167,8 @@ fn check_addr_of_expr( parent.span, format!("unnecessary use of `{method_name}`"), "use", - receiver_snippet.to_owned(), - Applicability::MachineApplicable, + receiver_snippet.to_string(), + applicability, ); } else { span_lint_and_sugg( @@ -176,7 +178,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "remove this", String::new(), - Applicability::MachineApplicable, + applicability, ); } return true; @@ -191,7 +193,7 @@ fn check_addr_of_expr( format!("unnecessary use of `{method_name}`"), "use", format!("{receiver_snippet}.as_ref()"), - Applicability::MachineApplicable, + applicability, ); return true; } @@ -409,8 +411,10 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { + let mut applicability = Applicability::MachineApplicable; + let (receiver_snippet, _) = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut applicability); + span_lint_and_sugg( cx, UNNECESSARY_TO_OWNED, @@ -418,7 +422,7 @@ fn check_other_call_arg<'tcx>( format!("unnecessary use of `{method_name}`"), "use", format!("{:&>n_refs$}{receiver_snippet}", ""), - Applicability::MachineApplicable, + applicability, ); return true; } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 316eac0b58b7..590359bc1ad2 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(&format!("ouch{dot}")); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index f2dbd1db3c9f..d1e3e6497c0a 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -681,3 +681,12 @@ fn issue14833() { let mut s = HashSet::<&String>::new(); s.remove(&"hello".to_owned()); } + +#[allow(clippy::redundant_clone)] +fn issue16351() { + fn take(_: impl AsRef) {} + + let dot = "."; + take(format!("ouch{dot}").to_string()); + //~^ unnecessary_to_owned +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 6c52be839301..50e3d5eb2195 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -550,5 +550,11 @@ error: unnecessary use of `to_vec` LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` -error: aborting due to 82 previous errors +error: unnecessary use of `to_string` + --> tests/ui/unnecessary_to_owned.rs:690:10 + | +LL | take(format!("ouch{dot}").to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `&format!("ouch{dot}")` + +error: aborting due to 83 previous errors From b0e65da2af8f3e12015d78a1828fceed6360642a Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Wed, 7 Jan 2026 19:01:19 +0530 Subject: [PATCH 232/340] rustc_parse_format: improve error for missing `:` before `?` in format args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detect the `{ident?}` pattern where `?` is immediately followed by `}` and emit a clearer diagnostic explaining that `:` is required for Debug formatting. This avoids falling back to a generic “invalid format string” error and adds a targeted UI test for the case. Signed-off-by: Usman Akinyemi --- compiler/rustc_builtin_macros/messages.ftl | 2 ++ compiler/rustc_builtin_macros/src/errors.rs | 9 +++++++ compiler/rustc_builtin_macros/src/format.rs | 4 +++ compiler/rustc_parse_format/src/lib.rs | 29 ++++++++++++++++++--- tests/ui/fmt/format-string-error-2.rs | 3 +++ tests/ui/fmt/format-string-error-2.stderr | 13 ++++++++- 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index f0f6f2dcf82c..e4fded0cb01e 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -182,6 +182,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm -> builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently +builtin_macros_format_add_missing_colon = add a colon before the format specifier + builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}` .label1 = previously here .label2 = duplicate argument diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ad31eae10f60..e673ad3f8a64 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -643,6 +643,15 @@ pub(crate) enum InvalidFormatStringSuggestion { span: Span, replacement: String, }, + #[suggestion( + builtin_macros_format_add_missing_colon, + code = ":?", + applicability = "machine-applicable" + )] + AddMissingColon { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a0ee7ac19899..12cb2cd00694 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -329,6 +329,10 @@ fn make_format_args( replacement, }); } + parse::Suggestion::AddMissingColon(span) => { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span }); + } } let guar = ecx.dcx().emit_err(e); return ExpandResult::Ready(Err(guar)); diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 86326fc6536c..143fd0c4436c 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -184,6 +184,9 @@ pub enum Suggestion { /// `format!("{foo:?x}")` -> `format!("{foo:x?}")` /// `format!("{foo:?X}")` -> `format!("{foo:X?}")` ReorderFormatParameter(Range, String), + /// Add missing colon: + /// `format!("{foo?}")` -> `format!("{foo:?}")` + AddMissingColon(Range), } /// The parser structure for interpreting the input format string. This is @@ -453,10 +456,11 @@ impl<'input> Parser<'input> { suggestion: Suggestion::None, }); - if let Some((_, _, c)) = self.peek() { - match c { - '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(c), + if let (Some((_, _, c)), Some((_, _, nc))) = (self.peek(), self.peek_ahead()) { + match (c, nc) { + ('?', '}') => self.missing_colon_before_debug_formatter(), + ('?', _) => self.suggest_format_debug(), + ('<' | '^' | '>', _) => self.suggest_format_align(c), _ => self.suggest_positional_arg_instead_of_captured_arg(arg), } } @@ -849,6 +853,23 @@ impl<'input> Parser<'input> { } } + fn missing_colon_before_debug_formatter(&mut self) { + if let Some((range, _)) = self.consume_pos('?') { + let span = range.clone(); + self.errors.insert( + 0, + ParseError { + description: "expected `}`, found `?`".to_owned(), + note: Some(format!("to print `{{`, you can escape it using `{{{{`",)), + label: "expected `:` before `?` to format with `Debug`".to_owned(), + span: range, + secondary_label: None, + suggestion: Suggestion::AddMissingColon(span), + }, + ); + } + } + fn suggest_format_align(&mut self, alignment: char) { if let Some((range, _)) = self.consume_pos(alignment) { self.errors.insert( diff --git a/tests/ui/fmt/format-string-error-2.rs b/tests/ui/fmt/format-string-error-2.rs index 357dd7b10a3e..e14a4064aa83 100644 --- a/tests/ui/fmt/format-string-error-2.rs +++ b/tests/ui/fmt/format-string-error-2.rs @@ -83,4 +83,7 @@ raw { \n println!(r#"\x7B}\u8 {"#, 1); //~^ ERROR invalid format string: unmatched `}` found + + println!("{x?}, world!",); + //~^ ERROR invalid format string: expected `}`, found `?` } diff --git a/tests/ui/fmt/format-string-error-2.stderr b/tests/ui/fmt/format-string-error-2.stderr index 6d8c34fdb709..b117fb57cf07 100644 --- a/tests/ui/fmt/format-string-error-2.stderr +++ b/tests/ui/fmt/format-string-error-2.stderr @@ -177,5 +177,16 @@ LL | println!(r#"\x7B}\u8 {"#, 1); | = note: if you intended to print `}`, you can escape it using `}}` -error: aborting due to 18 previous errors +error: invalid format string: expected `}`, found `?` + --> $DIR/format-string-error-2.rs:87:17 + | +LL | println!("{x?}, world!",); + | ^ + | | + | expected `:` before `?` to format with `Debug` in format string + | help: add a colon before the format specifier: `:?` + | + = note: to print `{`, you can escape it using `{{` + +error: aborting due to 19 previous errors From 600102c09b4e2a65969b1a1c1e857552fe1b83c2 Mon Sep 17 00:00:00 2001 From: Aelin Reidel Date: Thu, 8 Jan 2026 02:12:49 +0100 Subject: [PATCH 233/340] Add myself as co-maintainer for s390x-unknown-linux-musl Having two dedicated target maintainers is a prerequisite for promoting this target to tier 2. I've been in contact with Ulrich and he's agreed to having me as a co-maintainer in preparation for a MCP to promote it to tier 2. --- src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md index b8bee11055fe..cb7d05515453 100644 --- a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md +++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md @@ -7,6 +7,7 @@ IBM z/Architecture (s390x) targets (including IBM Z and LinuxONE) running Linux. ## Target maintainers [@uweigand](https://github.com/uweigand) +[@Gelbpunkt](https://github.com/Gelbpunkt) ## Requirements From a3b72d3de584a524d677bbaedf440f9223d439c0 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Thu, 8 Jan 2026 02:06:20 +0000 Subject: [PATCH 234/340] Fix copy-n-paste error in `vtable_for` docs This is a safe function, which doesn't take a `ptr` parameter. --- library/core/src/intrinsics/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 0ae8d3d4a4ce..27e1673c51de 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2738,10 +2738,6 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; /// Determining whether `T` can be coerced to the trait object type `U` requires trait resolution by the compiler. /// In some cases, that resolution can exceed the recursion limit, /// and compilation will fail instead of this function returning `None`. -/// -/// # Safety -/// -/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] From a4da8e8cefd95b8b5e7c0cea97a9f6331e578276 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 11:23:48 +1100 Subject: [PATCH 235/340] Remove some unnecessary braces in patterns. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 9162284422d0..289538a6163b 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -417,7 +417,7 @@ impl, I: Interner> TypeFolder for Canonicaliz // We don't canonicalize `ReStatic` in the `param_env` as we use it // when checking whether a `ParamEnv` candidate is global. ty::ReStatic => match self.canonicalize_mode { - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { CanonicalVarKind::Region(ty::UniverseIndex::ROOT) } CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) @@ -545,7 +545,7 @@ impl, I: Interner> TypeFolder for Canonicaliz match self.canonicalize_mode { CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv) | CanonicalizeMode::Response { max_input_universe: _ } => {} - CanonicalizeMode::Input(CanonicalizeInputKind::Predicate { .. }) => { + CanonicalizeMode::Input(CanonicalizeInputKind::Predicate) => { panic!("erasing 'static in env") } } From 5ca112fb9712d260d1aa5214a116663971fc770d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Jan 2026 17:48:51 +1100 Subject: [PATCH 236/340] Factor out duplicated code in `Canonicalizer::finalize`. --- .../src/canonical/canonicalizer.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 289538a6163b..6c114d601157 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -109,6 +109,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let (max_universe, variables) = canonicalizer.finalize(); Canonical { max_universe, variables, value } } + fn canonicalize_param_env( delegate: &'a D, variables: &'a mut Vec, @@ -280,15 +281,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. - match self.canonicalize_mode { + let max_universe = match self.canonicalize_mode { // All placeholders and vars are canonicalized in the root universe. CanonicalizeMode::Input { .. } => { debug_assert!( var_kinds.iter().all(|var| var.universe() == ty::UniverseIndex::ROOT), "expected all vars to be canonicalized in root universe: {var_kinds:#?}" ); - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (ty::UniverseIndex::ROOT, var_kinds) + ty::UniverseIndex::ROOT } // When canonicalizing a response we map a universes already entered // by the caller to the root universe and only return useful universe @@ -302,15 +302,15 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ); *var = var.with_updated_universe(new_uv); } - let max_universe = var_kinds + var_kinds .iter() .map(|kind| kind.universe()) .max() - .unwrap_or(ty::UniverseIndex::ROOT); - let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (max_universe, var_kinds) + .unwrap_or(ty::UniverseIndex::ROOT) } - } + }; + let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); + (max_universe, var_kinds) } fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { From 0ad7701b04f03602ef1cd86ebbae09d4a0f5a2b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Jan 2026 16:34:41 +1100 Subject: [PATCH 237/340] Remove `variables` arg from `Canonicalizer::canonicalize_response`. It's an empty `Vec` at both call sites, and so is unnecessary. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 4 ++-- compiler/rustc_next_trait_solver/src/canonical/mod.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 6c114d601157..c2a7414911ff 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -84,14 +84,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { pub(super) fn canonicalize_response>( delegate: &'a D, max_input_universe: ty::UniverseIndex, - variables: &'a mut Vec, value: T, ) -> ty::Canonical { + let mut variables = Vec::new(); let mut canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, - variables, + variables: &mut variables, variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b4cea8701d82..d562b8fac4c4 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -82,10 +82,7 @@ where I: Interner, T: TypeFoldable, { - let mut orig_values = Default::default(); - let canonical = - Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut orig_values, value); - canonical + Canonicalizer::canonicalize_response(delegate, max_input_universe, value) } /// After calling a canonical query, we apply the constraints returned @@ -308,7 +305,7 @@ where let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = eager_resolve_vars(delegate, state); - Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut vec![], state) + Canonicalizer::canonicalize_response(delegate, max_input_universe, state) } // FIXME: needs to be pub to be accessed by downstream From 4ae3c85a5ef8597aa11d1a547581312ebf56e3b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 13:10:22 +1100 Subject: [PATCH 238/340] Use the name `var_kinds` more. Variables that are collections of `CanonicalVarKind` are sometimes called `var_kinds` and sometimes called `variables`. The former is much better, because `variables` is (a) non-descript, and (b) often used nearby for collections of `I::GenericArg`. I found the inconsistency made the canonicalization code harder to understand. This commit renames various `variables` things as `var_kinds`. --- .../src/infer/canonical/canonicalizer.rs | 38 ++++++------ .../src/infer/canonical/instantiate.rs | 2 +- .../rustc_infer/src/infer/canonical/mod.rs | 2 +- .../src/infer/canonical/query_response.rs | 8 +-- compiler/rustc_middle/src/infer/canonical.rs | 2 +- .../src/canonical/canonicalizer.rs | 8 +-- .../src/canonical/mod.rs | 12 ++-- .../src/solve/eval_ctxt/mod.rs | 8 +-- .../src/solve/eval_ctxt/probe.rs | 2 +- .../src/solve/search_graph.rs | 2 +- compiler/rustc_type_ir/src/canonical.rs | 24 ++++---- ..._of_reborrow.SimplifyCfg-initial.after.mir | 60 +++++++++---------- ...ignment.main.SimplifyCfg-initial.after.mir | 4 +- .../issue_101867.main.built.after.mir | 4 +- ...ceiver_ptr_mutability.main.built.after.mir | 8 +-- ..._type_annotations.let_else.built.after.mir | 4 +- ...otations.let_else_bindless.built.after.mir | 4 +- ..._type_annotations.let_init.built.after.mir | 4 +- ...otations.let_init_bindless.built.after.mir | 4 +- ...ype_annotations.let_uninit.built.after.mir | 2 +- ...ations.let_uninit_bindless.built.after.mir | 2 +- ...otations.match_assoc_const.built.after.mir | 4 +- ...ns.match_assoc_const_range.built.after.mir | 8 +-- .../issue_72181_1.main.built.after.mir | 4 +- .../issue_99325.main.built.after.32bit.mir | 4 +- .../issue_99325.main.built.after.64bit.mir | 4 +- 26 files changed, 114 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index c07b41b56caa..23f6fee406a5 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -289,7 +289,7 @@ struct Canonicalizer<'cx, 'tcx> { /// Set to `None` to disable the resolution of inference variables. infcx: Option<&'cx InferCtxt<'tcx>>, tcx: TyCtxt<'tcx>, - variables: SmallVec<[CanonicalVarKind<'tcx>; 8]>, + var_kinds: SmallVec<[CanonicalVarKind<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. @@ -507,7 +507,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { { let base = Canonical { max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), + var_kinds: List::empty(), value: (), }; Canonicalizer::canonicalize_with_base( @@ -548,7 +548,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { tcx, canonicalize_mode: canonicalize_region_mode, needs_canonical_flags, - variables: SmallVec::from_slice(base.variables), + var_kinds: SmallVec::from_slice(base.var_kinds), query_state, indices: FxHashMap::default(), sub_root_lookup_table: Default::default(), @@ -569,16 +569,16 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // anymore. debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); - let canonical_variables = - tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_variables()); + let canonical_var_kinds = + tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_var_kinds()); - let max_universe = canonical_variables + let max_universe = canonical_var_kinds .iter() .map(|cvar| cvar.universe()) .max() .unwrap_or(ty::UniverseIndex::ROOT); - Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) } + Canonical { max_universe, var_kinds: canonical_var_kinds, value: (base.value, out_value) } } /// Creates a canonical variable replacing `kind` from the input, @@ -590,7 +590,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { var_kind: CanonicalVarKind<'tcx>, value: GenericArg<'tcx>, ) -> BoundVar { - let Canonicalizer { variables, query_state, indices, .. } = self; + let Canonicalizer { var_kinds, query_state, indices, .. } = self; let var_values = &mut query_state.var_values; @@ -607,7 +607,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } } - // This code is hot. `variables` and `var_values` are usually small + // This code is hot. `var_kinds` and `var_values` are usually small // (fewer than 8 elements ~95% of the time). They are SmallVec's to // avoid allocations in those cases. We also don't use `indices` to // determine if a kind has been seen before until the limit of 8 has @@ -620,10 +620,10 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { BoundVar::new(idx) } else { // `kind` isn't present in `var_values`. Append it. Likewise - // for `var_kind` and `variables`. - variables.push(var_kind); + // for `var_kind` and `var_kinds`. + var_kinds.push(var_kind); var_values.push(value); - assert_eq!(variables.len(), var_values.len()); + assert_eq!(var_kinds.len(), var_values.len()); // If `var_values` has become big enough to be heap-allocated, // fill up `indices` to facilitate subsequent lookups. @@ -641,10 +641,10 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } else { // `var_values` is large. Do a hashmap search via `indices`. *indices.entry(value).or_insert_with(|| { - variables.push(var_kind); + var_kinds.push(var_kind); var_values.push(value); - assert_eq!(variables.len(), var_values.len()); - BoundVar::new(variables.len() - 1) + assert_eq!(var_kinds.len(), var_values.len()); + BoundVar::new(var_kinds.len() - 1) }) } } @@ -652,16 +652,16 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar { let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid); let idx = - *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len()); + *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.var_kinds.len()); ty::BoundVar::from(idx) } /// Replaces the universe indexes used in `var_values` with their index in /// `query_state.universe_map`. This minimizes the maximum universe used in /// the canonicalized value. - fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> { + fn universe_canonicalized_var_kinds(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> { if self.query_state.universe_map.len() == 1 { - return self.variables; + return self.var_kinds; } let reverse_universe_map: FxHashMap = self @@ -672,7 +672,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx))) .collect(); - self.variables + self.var_kinds .iter() .map(|&kind| match kind { CanonicalVarKind::Int | CanonicalVarKind::Float => { diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index c215a9db2a0a..66a7bd2fc636 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -43,7 +43,7 @@ impl<'tcx, V> Canonical<'tcx, V> { where T: TypeFoldable>, { - assert_eq!(self.variables.len(), var_values.len()); + assert_eq!(self.var_kinds.len(), var_values.len()); let value = projection_fn(&self.value); instantiate_value(tcx, var_values, value) } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 9af0e17be4e2..c6826d774216 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -68,7 +68,7 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); let var_values = - CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| { + CanonicalVarValues::instantiate(self.tcx, &canonical.var_kinds, |var_values, info| { self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui]) }); let result = canonical.instantiate(self.tcx, &var_values); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index b4952e7bfe15..65b0f8211432 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -430,7 +430,7 @@ impl<'tcx> InferCtxt<'tcx> { // result, then we can type the corresponding value from the // input. See the example above. let mut opt_values: IndexVec>> = - IndexVec::from_elem_n(None, query_response.variables.len()); + IndexVec::from_elem_n(None, query_response.var_kinds.len()); for (original_value, result_value) in iter::zip(&original_values.var_values, result_values) { @@ -442,7 +442,7 @@ impl<'tcx> InferCtxt<'tcx> { // more involved. They are also a lot rarer than region variables. if let ty::Bound(index_kind, b) = *result_value.kind() && !matches!( - query_response.variables[b.var.as_usize()], + query_response.var_kinds[b.var.as_usize()], CanonicalVarKind::Ty { .. } ) { @@ -472,8 +472,8 @@ impl<'tcx> InferCtxt<'tcx> { // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. let tcx = self.tcx; - let variables = query_response.variables; - let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| { + let var_kinds = query_response.var_kinds; + let var_values = CanonicalVarValues::instantiate(tcx, var_kinds, |var_values, kind| { if kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all, we have to deal with them for now. diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 153605ee7f81..32c6b6e9c0ba 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -169,7 +169,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { ) { return Canonical { max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), + var_kinds: List::empty(), value: key, }; } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index c2a7414911ff..5349b5657d51 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -106,8 +106,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, variables) = canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let (max_universe, var_kinds) = canonicalizer.finalize(); + Canonical { max_universe, var_kinds, value } } fn canonicalize_param_env( @@ -235,8 +235,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, variables) = rest_canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let (max_universe, var_kinds) = rest_canonicalizer.finalize(); + Canonical { max_universe, var_kinds, value } } fn get_or_insert_bound_var( diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index d562b8fac4c4..ffc666e36179 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -154,7 +154,7 @@ where // // We therefore instantiate the existential variable in the canonical response with the // inference variable of the input right away, which is more performant. - let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); + let mut opt_values = IndexVec::from_elem_n(None, response.var_kinds.len()); for (original_value, result_value) in iter::zip(original_values, var_values.var_values.iter()) { match result_value.kind() { ty::GenericArgKind::Type(t) => { @@ -164,7 +164,7 @@ where // more involved. They are also a lot rarer than region variables. if let ty::Bound(index_kind, b) = t.kind() && !matches!( - response.variables.get(b.var().as_usize()).unwrap(), + response.var_kinds.get(b.var().as_usize()).unwrap(), CanonicalVarKind::Ty { .. } ) { @@ -186,7 +186,7 @@ where } } } - CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| { + CanonicalVarValues::instantiate(delegate.cx(), response.var_kinds, |var_values, kind| { if kind.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with @@ -342,14 +342,14 @@ where pub fn response_no_constraints_raw( cx: I, max_universe: ty::UniverseIndex, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, certainty: Certainty, ) -> CanonicalResponse { ty::Canonical { max_universe, - variables, + var_kinds, value: Response { - var_values: ty::CanonicalVarValues::make_identity(cx, variables), + var_values: ty::CanonicalVarValues::make_identity(cx, var_kinds), // FIXME: maybe we should store the "no response" version in cx, like // we do for cx.types and stuff. external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), 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..2fd79f593a5f 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 @@ -97,7 +97,7 @@ where /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, /// What kind of goal we're currently computing, see the enum definition /// for more info. @@ -325,7 +325,7 @@ where // which we don't do within this evaluation context. max_input_universe: ty::UniverseIndex::ROOT, initial_opaque_types_storage_num_entries: Default::default(), - variables: Default::default(), + var_kinds: Default::default(), var_values: CanonicalVarValues::dummy(), current_goal_kind: CurrentGoalKind::Misc, origin_span, @@ -376,7 +376,7 @@ where let initial_opaque_types_storage_num_entries = delegate.opaque_types_storage_num_entries(); let mut ecx = EvalCtxt { delegate, - variables: canonical_input.canonical.variables, + var_kinds: canonical_input.canonical.var_kinds, var_values, current_goal_kind: CurrentGoalKind::from_query_input(cx, input), max_input_universe: canonical_input.canonical.max_universe, @@ -1323,7 +1323,7 @@ where response_no_constraints_raw( self.cx(), self.max_input_universe, - self.variables, + self.var_kinds, Certainty::Maybe { cause, opaque_types_jank }, ) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index e5658ba32ff6..edf2a5d1ba8d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -47,7 +47,7 @@ where let max_input_universe = outer.max_input_universe; let mut nested = EvalCtxt { delegate, - variables: outer.variables, + var_kinds: outer.var_kinds, var_values: outer.var_values, current_goal_kind: outer.current_goal_kind, max_input_universe, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index ea45d5096990..73044b7943ae 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -143,7 +143,7 @@ fn response_no_constraints( Ok(response_no_constraints_raw( cx, input.canonical.max_universe, - input.canonical.variables, + input.canonical.var_kinds, certainty, )) } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 47e753d78731..12d222258b0c 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -38,7 +38,7 @@ impl Eq for CanonicalQueryInput {} pub struct Canonical { pub value: V, pub max_universe: UniverseIndex, - pub variables: I::CanonicalVarKinds, + pub var_kinds: I::CanonicalVarKinds, } impl Eq for Canonical {} @@ -68,17 +68,17 @@ impl Canonical { /// let b: Canonical)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } + let Canonical { max_universe, var_kinds, value } = self; + Canonical { max_universe, var_kinds, value: map_op(value) } } } impl fmt::Display for Canonical { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { value, max_universe, variables } = self; + let Self { value, max_universe, var_kinds } = self; write!( f, - "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?} }}", + "Canonical {{ value: {value}, max_universe: {max_universe:?}, var_kinds: {var_kinds:?} }}", ) } } @@ -311,30 +311,30 @@ impl CanonicalVarValues { pub fn instantiate( cx: I, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind) -> I::GenericArg, ) -> CanonicalVarValues { // Instantiating `CanonicalVarValues` is really hot, but limited to less than // 4 most of the time. Avoid creating a `Vec` here. - if variables.len() <= 4 { + if var_kinds.len() <= 4 { let mut var_values = ArrayVec::<_, 4>::new(); - for info in variables.iter() { + for info in var_kinds.iter() { var_values.push(f(&var_values, info)); } CanonicalVarValues { var_values: cx.mk_args(&var_values) } } else { - CanonicalVarValues::instantiate_cold(cx, variables, f) + CanonicalVarValues::instantiate_cold(cx, var_kinds, f) } } #[cold] fn instantiate_cold( cx: I, - variables: I::CanonicalVarKinds, + var_kinds: I::CanonicalVarKinds, mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind) -> I::GenericArg, ) -> CanonicalVarValues { - let mut var_values = Vec::with_capacity(variables.len()); - for info in variables.iter() { + let mut var_values = Vec::with_capacity(var_kinds.len()); + for info in var_kinds.iter() { var_values.push(f(&var_values, info)); } CanonicalVarValues { var_values: cx.mk_args(&var_values) } diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index a1fe278c6520..40527446e5dd 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,36 +1,36 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] -| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] -| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] -| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] -| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] +| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send +| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] +| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send +| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] +| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send +| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, var_kinds: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, var_kinds: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, var_kinds: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | fn address_of_reborrow() -> () { let mut _0: (); diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index b9d26c67538e..aa7d75242b40 100644 --- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> -| 1: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> +| 0: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, var_kinds: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> +| 1: user_ty: Canonical { value: Ty(std::option::Option>), max_universe: U0, var_kinds: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index fa35658a16d4..83281dea44db 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option -| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 0: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, var_kinds: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option +| 1: user_ty: Canonical { value: Ty(std::option::Option), max_universe: U0, var_kinds: [] }, span: $DIR/issue_101867.rs:5:12: 5:22, inferred_ty: std::option::Option | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index 5cf182c21c31..0c73bd8ac654 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -1,10 +1,10 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test -| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test +| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, var_kinds: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, var_kinds: [] }, span: $DIR/receiver_ptr_mutability.rs:16:14: 16:23, inferred_ty: *mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, var_kinds: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, var_kinds: [Region(U0), Region(U0), Region(U0), Region(U0)] }, span: $DIR/receiver_ptr_mutability.rs:20:18: 20:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir index bbf504d311f6..4b6aa46129a4 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:36:20: 36:45, inferred_ty: (u32, u64, &char) | fn let_else() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir index 7bf2551e99f2..3814980b4306 100644 --- a/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_else_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_else_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:41:20: 41:45, inferred_ty: (u32, u64, &char) | fn let_else_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir index 0cf681d8ab2c..dd05ef37de3c 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:26:20: 26:45, inferred_ty: (u32, u64, &char) | fn let_init() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir index 968813c826e4..d949e1945339 100644 --- a/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_init_bindless.built.after.mir @@ -1,8 +1,8 @@ // MIR for `let_init_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) -| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) +| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:31:20: 31:45, inferred_ty: (u32, u64, &char) | fn let_init_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir index b6fdc4ff46dc..22bf17bd7898 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:16:20: 16:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:16:20: 16:45, inferred_ty: (u32, u64, &char) | fn let_uninit() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir index 472dbfb63043..aad2de0e7d6e 100644 --- a/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.let_uninit_bindless.built.after.mir @@ -1,7 +1,7 @@ // MIR for `let_uninit_bindless` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:21:20: 21:45, inferred_ty: (u32, u64, &char) +| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:21:20: 21:45, inferred_ty: (u32, u64, &char) | fn let_uninit_bindless() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir index ff4b0bf7600d..8ec5028250b0 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const.built.after.mir @@ -1,8 +1,8 @@ // MIR for `match_assoc_const` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:55:9: 55:44, inferred_ty: u32 | fn match_assoc_const() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir index 4cc433f475f6..61e5d9b459d0 100644 --- a/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir +++ b/tests/mir-opt/building/user_type_annotations.match_assoc_const_range.built.after.mir @@ -1,10 +1,10 @@ // MIR for `match_assoc_const_range` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 -| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 -| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 -| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 +| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:63:11: 63:46, inferred_ty: u32 +| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 +| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/user_type_annotations.rs:64:9: 64:44, inferred_ty: u32 | fn match_assoc_const_range() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir index 79eaf9668330..398a4bcb3ab3 100644 --- a/tests/mir-opt/issue_72181_1.main.built.after.mir +++ b/tests/mir-opt/issue_72181_1.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void -| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, var_kinds: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, var_kinds: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 48a399eb39ce..9e48cf038bf2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 48a399eb39ce..9e48cf038bf2 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, var_kinds: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); From 65756bed80e0ce759cb5b6fa9fe80578e18d6981 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Jan 2026 14:54:26 +1100 Subject: [PATCH 239/340] Remove out of date FIXME comment. In #127273 I added a test and a FIXME comment pointing out how it does the wrong thing. In the next commit I fixed the problem but forgot to remove the FIXME comment, whoops. --- compiler/rustc_parse/src/parser/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a46fcd30fef4..62e97c0c308c 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2666,7 +2666,6 @@ fn look_ahead_non_outermost_stream() { }); } -// FIXME(nnethercote) All the output is currently wrong. #[test] fn debug_lookahead() { create_default_session_globals_then(|| { From f8240839704855d24823c5b2daf398144bcc7f43 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 13:14:23 +1100 Subject: [PATCH 240/340] Make `Canonicalizer::variables` owned. Currently it's a mutable reference, but it doesn't need to be, because what's passed in is always a mutable reference to an empty `Vec`. This requires returning variables in a few extra places, which is fine. It makes the handling of `variables` the same as the handling of `var_kinds` and `variable_lookup_table`. --- .../src/canonical/canonicalizer.rs | 48 +++++++++---------- .../src/canonical/mod.rs | 4 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 5349b5657d51..f71c8b122007 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -64,7 +64,7 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner canonicalize_mode: CanonicalizeMode, // Mutable fields. - variables: &'a mut Vec, + variables: Vec, var_kinds: Vec>, variable_lookup_table: HashMap, /// Maps each `sub_unification_table_root_var` to the index of the first @@ -86,12 +86,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { max_input_universe: ty::UniverseIndex, value: T, ) -> ty::Canonical { - let mut variables = Vec::new(); let mut canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, - variables: &mut variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -106,17 +105,17 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, var_kinds) = canonicalizer.finalize(); + let (max_universe, _variables, var_kinds) = canonicalizer.finalize(); Canonical { max_universe, var_kinds, value } } fn canonicalize_param_env( delegate: &'a D, - variables: &'a mut Vec, param_env: I::ParamEnv, - ) -> (I::ParamEnv, HashMap, Vec>) { + ) -> (I::ParamEnv, Vec, Vec>, HashMap) + { if !param_env.has_type_flags(NEEDS_CANONICAL) { - return (param_env, Default::default(), Vec::new()); + return (param_env, Vec::new(), Vec::new(), Default::default()); } // Check whether we can use the global cache for this param_env. As we only use @@ -130,12 +129,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate.cx().canonical_param_env_cache_get_or_insert( param_env, || { - let mut variables = Vec::new(); let mut env_canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables: &mut variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -148,18 +146,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { param_env, variable_lookup_table: env_canonicalizer.variable_lookup_table, var_kinds: env_canonicalizer.var_kinds, - variables, + variables: env_canonicalizer.variables, } }, |&CanonicalParamEnvCacheEntry { param_env, - variables: ref cache_variables, + ref variables, ref variable_lookup_table, ref var_kinds, }| { - debug_assert!(variables.is_empty()); - variables.extend(cache_variables.iter().copied()); - (param_env, variable_lookup_table.clone(), var_kinds.clone()) + (param_env, variables.clone(), var_kinds.clone(), variable_lookup_table.clone()) }, ) } else { @@ -167,7 +163,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables, + variables: Vec::new(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), @@ -176,7 +172,12 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }; let param_env = param_env.fold_with(&mut env_canonicalizer); debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); - (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) + ( + param_env, + env_canonicalizer.variables, + env_canonicalizer.var_kinds, + env_canonicalizer.variable_lookup_table, + ) } } @@ -190,12 +191,11 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { /// variable in the future by changing the way we detect global where-bounds. pub(super) fn canonicalize_input>( delegate: &'a D, - variables: &'a mut Vec, input: QueryInput, - ) -> ty::Canonical> { + ) -> (Vec, ty::Canonical>) { // First canonicalize the `param_env` while keeping `'static` - let (param_env, variable_lookup_table, var_kinds) = - Canonicalizer::canonicalize_param_env(delegate, variables, input.goal.param_env); + let (param_env, variables, var_kinds, variable_lookup_table) = + Canonicalizer::canonicalize_param_env(delegate, input.goal.param_env); // Then canonicalize the rest of the input without keeping `'static` // while *mostly* reusing the canonicalizer from above. let mut rest_canonicalizer = Canonicalizer { @@ -235,8 +235,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { debug_assert!(!value.has_infer(), "unexpected infer in {value:?}"); debug_assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); - let (max_universe, var_kinds) = rest_canonicalizer.finalize(); - Canonical { max_universe, var_kinds, value } + let (max_universe, variables, var_kinds) = rest_canonicalizer.finalize(); + (variables, Canonical { max_universe, var_kinds, value }) } fn get_or_insert_bound_var( @@ -277,7 +277,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ty::BoundVar::from(idx) } - fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) { + fn finalize(self) -> (ty::UniverseIndex, Vec, I::CanonicalVarKinds) { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. @@ -310,7 +310,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } }; let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds); - (max_universe, var_kinds) + (max_universe, self.variables, var_kinds) } fn inner_fold_ty(&mut self, t: I::Ty) -> I::Ty { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index ffc666e36179..96fea09013a1 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -59,10 +59,8 @@ where D: SolverDelegate, I: Interner, { - let mut orig_values = Default::default(); - let canonical = Canonicalizer::canonicalize_input( + let (orig_values, canonical) = Canonicalizer::canonicalize_input( delegate, - &mut orig_values, QueryInput { goal, predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types), From e4bbfe88566c5e06066809558ae655455777d151 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 14:00:04 +1100 Subject: [PATCH 241/340] Avoid using `to_vec` to clone `Vec`s. It's weird. `clone` is better. --- compiler/rustc_trait_selection/src/solve/inspect/analyse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index cdbf2b0aeb83..944d57bf95d1 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.to_vec(); + let mut orig_values = self.goal.orig_values.clone(); let mut instantiated_goals = vec![]; for step in &self.steps { @@ -186,7 +186,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; - let mut orig_values = self.goal.orig_values.to_vec(); + let mut orig_values = self.goal.orig_values.clone(); for step in &self.steps { match **step { From eb1645653b0993fa699c23bfbab94249be15bf1d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 15:05:53 +1100 Subject: [PATCH 242/340] Update a comment. I did some measurements. The current choice of 16 is fine. --- .../rustc_next_trait_solver/src/canonical/canonicalizer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index f71c8b122007..f6ec0dd09c57 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -244,8 +244,9 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { arg: impl Into, kind: CanonicalVarKind, ) -> ty::BoundVar { - // FIXME: 16 is made up and arbitrary. We should look at some - // perf data here. + // The exact value of 16 here doesn't matter that much (8 and 32 give extremely similar + // results). So long as we have protection against the rare cases where the length reaches + // 1000+ (e.g. `wg-grammar`). let arg = arg.into(); let idx = if self.variables.len() > 16 { if self.variable_lookup_table.is_empty() { From a07f71704adc575d56c353f5f08febda4af7fc3b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 7 Jan 2026 17:19:36 +1100 Subject: [PATCH 243/340] Add comments about predicate folding. This explains why the predicate folding code looks different to the ty/const folding code, something I was wondering. --- compiler/rustc_middle/src/ty/structural_impls.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1a5a3f3965fa..314d2ba39632 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -586,11 +586,18 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { self, folder: &mut F, ) -> Result { + // This method looks different to `Ty::try_super_fold_with` and `Const::super_fold_with`. + // Why is that? `PredicateKind` provides little scope for optimized folding, unlike + // `TyKind` and `ConstKind` (which have common variants that don't require recursive + // `fold_with` calls on their fields). So we just derive the `TypeFoldable` impl for + // `PredicateKind` and call it here because the derived code is as fast as hand-written + // code would be. let new = self.kind().try_fold_with(folder)?; Ok(folder.cx().reuse_or_mk_predicate(self, new)) } fn super_fold_with>>(self, folder: &mut F) -> Self { + // See comment in `Predicate::try_super_fold_with`. let new = self.kind().fold_with(folder); folder.cx().reuse_or_mk_predicate(self, new) } @@ -598,6 +605,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Predicate<'tcx> { impl<'tcx> TypeSuperVisitable> for ty::Predicate<'tcx> { fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { + // See comment in `Predicate::try_super_fold_with`. self.kind().visit_with(visitor) } } From b222cf3874eb8d3c1a881206f037f0aad1befede Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Jan 2026 15:03:41 +1100 Subject: [PATCH 244/340] Tweak variable cloning. --- .../src/canonical/canonicalizer.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index f6ec0dd09c57..8dfa875ca6f9 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -151,11 +151,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { }, |&CanonicalParamEnvCacheEntry { param_env, - ref variables, + variables: ref cache_variables, ref variable_lookup_table, ref var_kinds, }| { - (param_env, variables.clone(), var_kinds.clone(), variable_lookup_table.clone()) + // FIXME(nnethercote): for reasons I don't understand, this `new`+`extend` + // combination is faster than `variables.clone()`, because it somehow avoids + // some allocations. + let mut variables = Vec::new(); + variables.extend(cache_variables.iter().copied()); + (param_env, variables, var_kinds.clone(), variable_lookup_table.clone()) }, ) } else { From e454835eef0df5c920377bba45b115e896f3bff9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 8 Jan 2026 10:25:58 +0300 Subject: [PATCH 245/340] resolve: Factor out and document the glob binding overwriting logic --- compiler/rustc_resolve/src/imports.rs | 116 ++++++++++++++++++-------- 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a8bb53cc7f27..3f998b8c8aa0 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -295,6 +295,24 @@ fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> O } } +/// Removes identical import layers from two declarations. +fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra>) { + if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind + && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind + && import1 == import2 + && d1.ambiguity == d2.ambiguity + { + assert!(d1.ambiguity.is_none()); + assert_eq!(d1.warn_ambiguity, d2.warn_ambiguity); + assert_eq!(d1.expansion, d2.expansion); + assert_eq!(d1.span, d2.span); + assert_eq!(d1.vis, d2.vis); + remove_same_import(d1_next, d2_next) + } else { + (d1, d2) + } +} + impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Given an import and the declaration that it points to, /// create the corresponding import declaration. @@ -325,6 +343,61 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } + /// If `glob_decl` attempts to overwrite `old_glob_decl` in a module, + /// decide which one to keep. + fn select_glob_decl( + &self, + glob_decl: Decl<'ra>, + old_glob_decl: Decl<'ra>, + warn_ambiguity: bool, + ) -> Decl<'ra> { + assert!(glob_decl.is_glob_import()); + assert!(old_glob_decl.is_glob_import()); + assert_ne!(glob_decl, old_glob_decl); + // `best_decl` with a given key in a module may be overwritten in a + // number of cases (all of them can be seen below in the `match` in `try_define_local`), + // all these overwrites will be re-fetched by glob imports importing + // from that module without generating new ambiguities. + // - A glob decl is overwritten by a non-glob decl arriving later. + // - A glob decl is overwritten by an ambiguous glob decl. + // FIXME: avoid this by putting `DeclData::ambiguity` under a + // cell and updating it in place. + // - A glob decl is overwritten by the same decl with `warn_ambiguity == true`. + // FIXME: avoid this by putting `DeclData::warn_ambiguity` under a + // cell and updating it in place. + // - A glob decl is overwritten by a glob decl with larger visibility. + // FIXME: avoid this by putting `DeclData::vis` under a cell + // and updating it in place. + // - A glob decl is overwritten by a glob decl re-fetching an + // overwritten decl from other module (the recursive case). + // Here we are detecting all such re-fetches and overwrite old decls + // with the re-fetched decls. + // This is probably incorrect in corner cases, and the outdated decls still get + // propagated to other places and get stuck there, but that's what we have at the moment. + let (deep_decl, old_deep_decl) = remove_same_import(glob_decl, old_glob_decl); + if deep_decl != glob_decl { + // Some import layers have been removed, need to overwrite. + assert_ne!(old_deep_decl, old_glob_decl); + assert_ne!(old_deep_decl, deep_decl); + assert!(old_deep_decl.is_glob_import()); + if glob_decl.is_ambiguity_recursive() { + self.new_decl_with_warn_ambiguity(glob_decl) + } else { + glob_decl + } + } else if glob_decl.res() != old_glob_decl.res() { + self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) + } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { + // We are glob-importing the same item but with greater visibility. + glob_decl + } else if glob_decl.is_ambiguity_recursive() { + // Overwriting with an ambiguous glob import. + self.new_decl_with_warn_ambiguity(glob_decl) + } else { + old_glob_decl + } + } + /// Attempt to put the declaration with the given name and namespace into the module, /// and return existing declaration if there is a collision. pub(crate) fn try_plant_decl_into_local_module( @@ -347,52 +420,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_decl) = resolution.best_decl() { + assert_ne!(decl, old_decl); if res == Res::Err && old_decl.res() != Res::Err { // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); } match (old_decl.is_glob_import(), decl.is_glob_import()) { (true, true) => { - let (glob_decl, old_glob_decl) = (decl, old_decl); - // FIXME: remove `!decl.is_ambiguity_recursive()` after delete the warning ambiguity. - if !decl.is_ambiguity_recursive() - && let DeclKind::Import { import: old_import, .. } = old_glob_decl.kind - && let DeclKind::Import { import, .. } = glob_decl.kind - && old_import == import - { - // When imported from the same glob-import statement, we should replace - // `old_glob_decl` with `glob_decl`, regardless of whether - // they have the same resolution or not. - resolution.glob_decl = Some(glob_decl); - } else if res != old_glob_decl.res() { - resolution.glob_decl = Some(this.new_decl_with_ambiguity( - old_glob_decl, - glob_decl, - warn_ambiguity, - )); - } else if !old_decl.vis.is_at_least(decl.vis, this.tcx) { - // We are glob-importing the same item but with greater visibility. - resolution.glob_decl = Some(glob_decl); - } else if decl.is_ambiguity_recursive() { - resolution.glob_decl = - Some(this.new_decl_with_warn_ambiguity(glob_decl)); - } + resolution.glob_decl = + Some(this.select_glob_decl(decl, old_decl, warn_ambiguity)); } (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_decl, non_glob_decl) = if old_glob { (old_decl, decl) } else { (decl, old_decl) }; resolution.non_glob_decl = Some(non_glob_decl); - if let Some(old_glob_decl) = resolution.glob_decl { - assert!(old_glob_decl.is_glob_import()); - if glob_decl.res() != old_glob_decl.res() { - resolution.glob_decl = Some(this.new_decl_with_ambiguity( - old_glob_decl, - glob_decl, - false, - )); - } else if !old_glob_decl.vis.is_at_least(decl.vis, this.tcx) { - resolution.glob_decl = Some(glob_decl); - } + if let Some(old_glob_decl) = resolution.glob_decl + && old_glob_decl != glob_decl + { + resolution.glob_decl = + Some(this.select_glob_decl(glob_decl, old_glob_decl, false)); } else { resolution.glob_decl = Some(glob_decl); } From 32cf3a96d7d2695f16f00e594e291ae18c00dc32 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 29 Dec 2025 22:12:56 +0300 Subject: [PATCH 246/340] resolve: Update `NameBindingData::warn_ambiguity` in place instead of creating fresh bindings. --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- .../src/effective_visibilities.rs | 4 ++-- compiler/rustc_resolve/src/imports.rs | 21 +++++++------------ compiler/rustc_resolve/src/lib.rs | 12 +++++------ 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d56ca7c079cb..0159e9c9eda4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -91,7 +91,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind: DeclKind::Def(res), ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. - warn_ambiguity: true, + warn_ambiguity: CmCell::new(true), vis, span, expansion, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index e5144332f2b7..eee12922e511 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -127,7 +127,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // lint. For all bindings added to the table this way `is_ambiguity` returns true. let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = decl.warn_ambiguity; + let mut warn_ambiguity = decl.warn_ambiguity.get(); while let DeclKind::Import { source_decl, .. } = decl.kind { self.update_import(decl, parent_id); @@ -140,7 +140,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { parent_id = ParentId::Import(decl); decl = source_decl; - warn_ambiguity |= source_decl.warn_ambiguity; + warn_ambiguity |= source_decl.warn_ambiguity.get(); } if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f998b8c8aa0..7f28ac29ac1d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -303,7 +303,7 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra && d1.ambiguity == d2.ambiguity { assert!(d1.ambiguity.is_none()); - assert_eq!(d1.warn_ambiguity, d2.warn_ambiguity); + assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); assert_eq!(d1.vis, d2.vis); @@ -336,7 +336,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { source_decl: decl, import }, ambiguity: None, - warn_ambiguity: false, + warn_ambiguity: CmCell::new(false), span: import.span, vis, expansion: import.parent_scope.expansion, @@ -362,9 +362,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // - A glob decl is overwritten by an ambiguous glob decl. // FIXME: avoid this by putting `DeclData::ambiguity` under a // cell and updating it in place. - // - A glob decl is overwritten by the same decl with `warn_ambiguity == true`. - // FIXME: avoid this by putting `DeclData::warn_ambiguity` under a - // cell and updating it in place. // - A glob decl is overwritten by a glob decl with larger visibility. // FIXME: avoid this by putting `DeclData::vis` under a cell // and updating it in place. @@ -381,10 +378,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert_ne!(old_deep_decl, deep_decl); assert!(old_deep_decl.is_glob_import()); if glob_decl.is_ambiguity_recursive() { - self.new_decl_with_warn_ambiguity(glob_decl) - } else { - glob_decl + glob_decl.warn_ambiguity.set_unchecked(true); } + glob_decl } else if glob_decl.res() != old_glob_decl.res() { self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { @@ -392,7 +388,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_decl } else if glob_decl.is_ambiguity_recursive() { // Overwriting with an ambiguous glob import. - self.new_decl_with_warn_ambiguity(glob_decl) + glob_decl.warn_ambiguity.set_unchecked(true); + glob_decl } else { old_glob_decl } @@ -466,15 +463,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { warn_ambiguity: bool, ) -> Decl<'ra> { let ambiguity = Some(secondary_decl); + let warn_ambiguity = CmCell::new(warn_ambiguity); let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; self.arenas.alloc_decl(data) } - fn new_decl_with_warn_ambiguity(&self, decl: Decl<'ra>) -> Decl<'ra> { - assert!(decl.is_ambiguity_recursive()); - self.arenas.alloc_decl(DeclData { warn_ambiguity: true, ..*decl }) - } - // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_local_resolution( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 063b6b4058f0..cf8d1952d4a0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -802,13 +802,13 @@ impl<'ra> fmt::Debug for Module<'ra> { } /// Data associated with any name declaration. -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] struct DeclData<'ra> { kind: DeclKind<'ra>, ambiguity: Option>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. - warn_ambiguity: bool, + warn_ambiguity: CmCell, expansion: LocalExpnId, span: Span, vis: Visibility, @@ -956,7 +956,7 @@ impl<'ra> DeclData<'ra> { } fn warn_ambiguity_recursive(&self) -> bool { - self.warn_ambiguity + self.warn_ambiguity.get() || match self.kind { DeclKind::Import { source_decl, .. } => source_decl.warn_ambiguity_recursive(), _ => false, @@ -1343,7 +1343,7 @@ impl<'ra> ResolverArenas<'ra> { self.alloc_decl(DeclData { kind: DeclKind::Def(res), ambiguity: None, - warn_ambiguity: false, + warn_ambiguity: CmCell::new(false), vis, span, expansion, @@ -2041,7 +2041,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn record_use(&mut self, ident: Ident, used_decl: Decl<'ra>, used: Used) { - self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity); + self.record_use_inner(ident, used_decl, used, used_decl.warn_ambiguity.get()); } fn record_use_inner( @@ -2112,7 +2112,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, source_decl, Used::Other, - warn_ambiguity || source_decl.warn_ambiguity, + warn_ambiguity || source_decl.warn_ambiguity.get(), ); } } From 227e7bd48b5a7f3479bc4b231cf042e092fadd89 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 01:47:50 +0300 Subject: [PATCH 247/340] resolve: Update `NameBindingData::vis` in place instead of overwriting bindings in modules. --- .../rustc_resolve/src/build_reduced_graph.rs | 26 +++++++------- compiler/rustc_resolve/src/diagnostics.rs | 8 ++--- .../src/effective_visibilities.rs | 4 +-- compiler/rustc_resolve/src/ident.rs | 11 +++--- compiler/rustc_resolve/src/imports.rs | 35 +++++++++---------- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 8 +++-- 7 files changed, 49 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0159e9c9eda4..0167b8038649 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -92,7 +92,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ambiguity, // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: CmCell::new(true), - vis, + vis: CmCell::new(vis), span, expansion, }); @@ -1158,18 +1158,18 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.potentially_unused_imports.push(import); module.for_each_child_mut(self, |this, ident, ns, binding| { if ns == MacroNS { - let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) - { - import - } else { - // FIXME: This branch is used for reporting the `private_macro_use` lint - // and should eventually be removed. - if this.r.macro_use_prelude.contains_key(&ident.name) { - // Do not override already existing entries with compatibility entries. - return; - } - macro_use_import(this, span, true) - }; + let import = + if this.r.is_accessible_from(binding.vis(), this.parent_scope.module) { + import + } else { + // FIXME: This branch is used for reporting the `private_macro_use` lint + // and should eventually be removed. + if this.r.macro_use_prelude.contains_key(&ident.name) { + // Do not override already existing entries with compatibility entries. + return; + } + macro_use_import(this, span, true) + }; let import_decl = this.r.new_import_decl(binding, import); this.add_macro_use_decl(ident.name, import_decl, span, allow_shadowing); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7c86ed91a07a..d704280f3fa2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1338,7 +1338,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let child_accessible = - accessible && this.is_accessible_from(name_binding.vis, parent_scope.module); + accessible && this.is_accessible_from(name_binding.vis(), parent_scope.module); // do not venture inside inaccessible items of other crates if in_module_is_extern && !child_accessible { @@ -1358,8 +1358,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // #90113: Do not count an inaccessible reexported item as a candidate. if let DeclKind::Import { source_decl, .. } = name_binding.kind - && this.is_accessible_from(source_decl.vis, parent_scope.module) - && !this.is_accessible_from(name_binding.vis, parent_scope.module) + && this.is_accessible_from(source_decl.vis(), parent_scope.module) + && !this.is_accessible_from(name_binding.vis(), parent_scope.module) { return; } @@ -2243,7 +2243,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); - if !first && binding.vis.is_public() { + if !first && binding.vis().is_public() { let desc = match binding.kind { DeclKind::Import { .. } => "re-export", _ => "directly", diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index eee12922e511..7272314b9aa7 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -145,7 +145,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { if !is_ambiguity(decl, warn_ambiguity) && let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) { - self.update_def(def_id, decl.vis.expect_local(), parent_id); + self.update_def(def_id, decl.vis().expect_local(), parent_id); } } } @@ -188,7 +188,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { } fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>) { - let nominal_vis = decl.vis.expect_local(); + let nominal_vis = decl.vis().expect_local(); let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return }; let inherited_eff_vis = self.effective_vis_or_private(parent_id); let tcx = self.r.tcx; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0acf043ffcf..f47bb28d3fa1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1017,7 +1017,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Items and single imports are not shadowable, if we have one, then it's determined. if let Some(binding) = binding { - let accessible = self.is_accessible_from(binding.vis, parent_scope.module); + let accessible = self.is_accessible_from(binding.vis(), parent_scope.module); return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; } @@ -1103,7 +1103,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // shadowing is enabled, see `macro_expanded_macro_export_errors`). if let Some(binding) = binding { return if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { - let accessible = self.is_accessible_from(binding.vis, parent_scope.module); + let accessible = self.is_accessible_from(binding.vis(), parent_scope.module); if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) } } else { Err(ControlFlow::Break(Undetermined)) @@ -1160,7 +1160,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match result { Err(Determined) => continue, Ok(binding) - if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) => + if !self.is_accessible_from(binding.vis(), glob_import.parent_scope.module) => { continue; } @@ -1187,7 +1187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Err(ControlFlow::Continue(Determined)); }; - if !self.is_accessible_from(binding.vis, parent_scope.module) { + if !self.is_accessible_from(binding.vis(), parent_scope.module) { if report_private { self.privacy_errors.push(PrivacyError { ident, @@ -1304,7 +1304,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Err(Determined) => continue, Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + if !self + .is_accessible_from(binding.vis(), single_import.parent_scope.module) => { continue; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7f28ac29ac1d..5b0755dbde25 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -306,7 +306,7 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); - assert_eq!(d1.vis, d2.vis); + assert_eq!(d1.vis(), d2.vis()); remove_same_import(d1_next, d2_next) } else { (d1, d2) @@ -318,12 +318,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// create the corresponding import declaration. pub(crate) fn new_import_decl(&self, decl: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> { let import_vis = import.vis.to_def_id(); - let vis = if decl.vis.is_at_least(import_vis, self.tcx) + let vis = if decl.vis().is_at_least(import_vis, self.tcx) || pub_use_of_private_extern_crate_hack(import, decl).is_some() { import_vis } else { - decl.vis + decl.vis() }; if let ImportKind::Glob { ref max_vis, .. } = import.kind @@ -338,7 +338,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ambiguity: None, warn_ambiguity: CmCell::new(false), span: import.span, - vis, + vis: CmCell::new(vis), expansion: import.parent_scope.expansion, }) } @@ -362,9 +362,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // - A glob decl is overwritten by an ambiguous glob decl. // FIXME: avoid this by putting `DeclData::ambiguity` under a // cell and updating it in place. - // - A glob decl is overwritten by a glob decl with larger visibility. - // FIXME: avoid this by putting `DeclData::vis` under a cell - // and updating it in place. // - A glob decl is overwritten by a glob decl re-fetching an // overwritten decl from other module (the recursive case). // Here we are detecting all such re-fetches and overwrite old decls @@ -383,9 +380,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_decl } else if glob_decl.res() != old_glob_decl.res() { self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) - } else if !old_glob_decl.vis.is_at_least(glob_decl.vis, self.tcx) { + } else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) { // We are glob-importing the same item but with greater visibility. - glob_decl + old_glob_decl.vis.set_unchecked(glob_decl.vis()); + old_glob_decl } else if glob_decl.is_ambiguity_recursive() { // Overwriting with an ambiguous glob import. glob_decl.warn_ambiguity.set_unchecked(true); @@ -464,7 +462,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Decl<'ra> { let ambiguity = Some(secondary_decl); let warn_ambiguity = CmCell::new(warn_ambiguity); - let data = DeclData { ambiguity, warn_ambiguity, ..*primary_decl }; + let vis = primary_decl.vis.clone(); + let data = DeclData { ambiguity, warn_ambiguity, vis, ..*primary_decl }; self.arenas.alloc_decl(data) } @@ -509,7 +508,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => import.parent_scope.module, None => continue, }; - if self.is_accessible_from(binding.vis, scope) { + if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, *import); let _ = self.try_plant_decl_into_local_module( import.parent_scope.module, @@ -699,8 +698,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_decl.vis.is_public() - && !binding.vis.is_public() + && glob_decl.vis().is_public() + && !binding.vis().is_public() { let binding_id = match binding.kind { DeclKind::Def(res) => { @@ -1330,9 +1329,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; }; - if !binding.vis.is_at_least(import.vis, this.tcx) { + if !binding.vis().is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis() && binding_def_id.is_top_level_module() { crate_private_reexport = true; @@ -1535,7 +1534,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => import.parent_scope.module, None => continue, }; - if self.is_accessible_from(binding.vis, scope) { + if self.is_accessible_from(binding.vis(), scope) { let import_decl = self.new_import_decl(binding, import); let warn_ambiguity = self .resolution(import.parent_scope.module, key) @@ -1577,7 +1576,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let child = |reexport_chain| ModChild { ident: ident.0, res, - vis: binding.vis, + vis: binding.vis(), reexport_chain, }; if let Some((ambig_binding1, ambig_binding2)) = binding.descent_to_ambiguity() { @@ -1585,7 +1584,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let second = ModChild { ident: ident.0, res: ambig_binding2.res().expect_non_local(), - vis: ambig_binding2.vis, + vis: ambig_binding2.vis(), reexport_chain: ambig_binding2.reexport_chain(this), }; ambig_children.push(AmbigModChild { main, second }) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 73e1a8f0c3bc..a2805497e796 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2793,7 +2793,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { in_module.for_each_child(self.r, |r, ident, _, name_binding| { // abort if the module is already found or if name_binding is private external - if result.is_some() || !name_binding.vis.is_visible_locally() { + if result.is_some() || !name_binding.vis().is_visible_locally() { return; } if let Some(module_def_id) = name_binding.res().module_like_def_id() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cf8d1952d4a0..bce14f5376d7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -811,7 +811,7 @@ struct DeclData<'ra> { warn_ambiguity: CmCell, expansion: LocalExpnId, span: Span, - vis: Visibility, + vis: CmCell>, } /// All name declarations are unique and allocated on a same arena, @@ -923,6 +923,10 @@ struct AmbiguityError<'ra> { } impl<'ra> DeclData<'ra> { + fn vis(&self) -> Visibility { + self.vis.get() + } + fn res(&self) -> Res { match self.kind { DeclKind::Def(res) => res, @@ -1344,7 +1348,7 @@ impl<'ra> ResolverArenas<'ra> { kind: DeclKind::Def(res), ambiguity: None, warn_ambiguity: CmCell::new(false), - vis, + vis: CmCell::new(vis), span, expansion, }) From c2379717a2e9f2befdbea2795fea696d7c86d82c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 02:49:14 +0300 Subject: [PATCH 248/340] resolve: Tweak overwriting with ambiguous globs Do not overwrite unless necessary, and combine both globs instead of losing the first one. --- compiler/rustc_resolve/src/imports.rs | 7 +++---- tests/ui/imports/ambiguous-14.stderr | 12 ++++++------ tests/ui/imports/duplicate.stderr | 12 ++++++------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5b0755dbde25..76aeb7ba85b8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -384,10 +384,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We are glob-importing the same item but with greater visibility. old_glob_decl.vis.set_unchecked(glob_decl.vis()); old_glob_decl - } else if glob_decl.is_ambiguity_recursive() { - // Overwriting with an ambiguous glob import. - glob_decl.warn_ambiguity.set_unchecked(true); - glob_decl + } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { + // Overwriting a non-ambiguous glob import with an ambiguous glob import. + self.new_decl_with_ambiguity(old_glob_decl, glob_decl, true) } else { old_glob_decl } diff --git a/tests/ui/imports/ambiguous-14.stderr b/tests/ui/imports/ambiguous-14.stderr index 4efa31c61e32..2a3557c31f12 100644 --- a/tests/ui/imports/ambiguous-14.stderr +++ b/tests/ui/imports/ambiguous-14.stderr @@ -8,15 +8,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/ambiguous-14.rs:13:13 + --> $DIR/ambiguous-14.rs:18:13 | LL | pub use a::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/ambiguous-14.rs:14:13 + --> $DIR/ambiguous-14.rs:19:13 | -LL | pub use b::*; +LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default @@ -34,15 +34,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/ambiguous-14.rs:13:13 + --> $DIR/ambiguous-14.rs:18:13 | LL | pub use a::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/ambiguous-14.rs:14:13 + --> $DIR/ambiguous-14.rs:19:13 | -LL | pub use b::*; +LL | pub use f::*; | ^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default diff --git a/tests/ui/imports/duplicate.stderr b/tests/ui/imports/duplicate.stderr index 5cd3b0c2c8a5..74829fc21e22 100644 --- a/tests/ui/imports/duplicate.stderr +++ b/tests/ui/imports/duplicate.stderr @@ -78,15 +78,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/duplicate.rs:24:13 + --> $DIR/duplicate.rs:29:13 | LL | pub use crate::a::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/duplicate.rs:25:13 + --> $DIR/duplicate.rs:30:13 | -LL | pub use crate::b::*; +LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default @@ -106,15 +106,15 @@ LL | g::foo(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `foo` could refer to the function imported here - --> $DIR/duplicate.rs:24:13 + --> $DIR/duplicate.rs:29:13 | LL | pub use crate::a::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate note: `foo` could also refer to the function imported here - --> $DIR/duplicate.rs:25:13 + --> $DIR/duplicate.rs:30:13 | -LL | pub use crate::b::*; +LL | pub use crate::f::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `foo` to disambiguate = note: `#[deny(ambiguous_glob_imports)]` (part of `#[deny(future_incompatible)]`) on by default From a251ae2615bd92b90e4c850a8026bff47e4786bf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 30 Dec 2025 02:54:43 +0300 Subject: [PATCH 249/340] resolve: Update `NameBindingData::ambiguity` in place instead of creating fresh bindings, except in one case. --- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- .../src/effective_visibilities.rs | 7 ++- compiler/rustc_resolve/src/imports.rs | 51 ++++++++++--------- compiler/rustc_resolve/src/lib.rs | 12 ++--- tests/ui/imports/issue-55884-1.rs | 2 +- tests/ui/imports/issue-55884-1.stderr | 22 +++++++- 6 files changed, 60 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0167b8038649..6bface926edc 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -89,7 +89,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { let decl = self.arenas.alloc_decl(DeclData { kind: DeclKind::Def(res), - ambiguity, + ambiguity: CmCell::new(ambiguity), // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. warn_ambiguity: CmCell::new(true), vis: CmCell::new(vis), diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 7272314b9aa7..ebdb0060e1b9 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -100,7 +100,9 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) } - } else if decl.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) { + } else if decl.ambiguity.get().is_some() + && eff_vis.is_public_at_level(Level::Reexported) + { exported_ambiguities.insert(*decl); } } @@ -125,7 +127,8 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // If the binding is ambiguous, put the root ambiguity binding and all reexports // leading to it into the table. They are used by the `ambiguous_glob_reexports` // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = |decl: Decl<'ra>, warn: bool| decl.ambiguity.is_some() && !warn; + let is_ambiguity = + |decl: Decl<'ra>, warn: bool| decl.ambiguity.get().is_some() && !warn; let mut parent_id = ParentId::Def(module_id); let mut warn_ambiguity = decl.warn_ambiguity.get(); while let DeclKind::Import { source_decl, .. } = decl.kind { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 76aeb7ba85b8..68f042c6e041 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -300,10 +300,10 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra if let DeclKind::Import { import: import1, source_decl: d1_next } = d1.kind && let DeclKind::Import { import: import2, source_decl: d2_next } = d2.kind && import1 == import2 - && d1.ambiguity == d2.ambiguity + && d1.warn_ambiguity.get() == d2.warn_ambiguity.get() { - assert!(d1.ambiguity.is_none()); - assert_eq!(d1.warn_ambiguity.get(), d2.warn_ambiguity.get()); + assert_eq!(d1.ambiguity.get(), d2.ambiguity.get()); + assert!(!d1.warn_ambiguity.get()); assert_eq!(d1.expansion, d2.expansion); assert_eq!(d1.span, d2.span); assert_eq!(d1.vis(), d2.vis()); @@ -335,7 +335,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.arenas.alloc_decl(DeclData { kind: DeclKind::Import { source_decl: decl, import }, - ambiguity: None, + ambiguity: CmCell::new(None), warn_ambiguity: CmCell::new(false), span: import.span, vis: CmCell::new(vis), @@ -359,9 +359,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // all these overwrites will be re-fetched by glob imports importing // from that module without generating new ambiguities. // - A glob decl is overwritten by a non-glob decl arriving later. - // - A glob decl is overwritten by an ambiguous glob decl. - // FIXME: avoid this by putting `DeclData::ambiguity` under a - // cell and updating it in place. + // - A glob decl is overwritten by its clone after setting ambiguity in it. + // FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch + // with the same decl in some way. // - A glob decl is overwritten by a glob decl re-fetching an // overwritten decl from other module (the recursive case). // Here we are detecting all such re-fetches and overwrite old decls @@ -372,21 +372,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if deep_decl != glob_decl { // Some import layers have been removed, need to overwrite. assert_ne!(old_deep_decl, old_glob_decl); - assert_ne!(old_deep_decl, deep_decl); - assert!(old_deep_decl.is_glob_import()); + // FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195). + // assert_ne!(old_deep_decl, deep_decl); + // assert!(old_deep_decl.is_glob_import()); + assert!(!deep_decl.is_glob_import()); if glob_decl.is_ambiguity_recursive() { glob_decl.warn_ambiguity.set_unchecked(true); } glob_decl } else if glob_decl.res() != old_glob_decl.res() { - self.new_decl_with_ambiguity(old_glob_decl, glob_decl, warn_ambiguity) + old_glob_decl.ambiguity.set_unchecked(Some(glob_decl)); + old_glob_decl.warn_ambiguity.set_unchecked(warn_ambiguity); + if warn_ambiguity { + old_glob_decl + } else { + // Need a fresh decl so other glob imports importing it could re-fetch it + // and set their own `warn_ambiguity` to true. + // FIXME: remove this when `warn_ambiguity` is removed (#149195). + self.arenas.alloc_decl((*old_glob_decl).clone()) + } } else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) { // We are glob-importing the same item but with greater visibility. old_glob_decl.vis.set_unchecked(glob_decl.vis()); old_glob_decl } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { // Overwriting a non-ambiguous glob import with an ambiguous glob import. - self.new_decl_with_ambiguity(old_glob_decl, glob_decl, true) + old_glob_decl.ambiguity.set_unchecked(Some(glob_decl)); + old_glob_decl.warn_ambiguity.set_unchecked(true); + old_glob_decl } else { old_glob_decl } @@ -415,6 +428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| { if let Some(old_decl) = resolution.best_decl() { assert_ne!(decl, old_decl); + assert!(!decl.warn_ambiguity.get()); if res == Res::Err && old_decl.res() != Res::Err { // Do not override real declarations with `Res::Err`s from error recovery. return Ok(()); @@ -453,19 +467,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }) } - fn new_decl_with_ambiguity( - &self, - primary_decl: Decl<'ra>, - secondary_decl: Decl<'ra>, - warn_ambiguity: bool, - ) -> Decl<'ra> { - let ambiguity = Some(secondary_decl); - let warn_ambiguity = CmCell::new(warn_ambiguity); - let vis = primary_decl.vis.clone(); - let data = DeclData { ambiguity, warn_ambiguity, vis, ..*primary_decl }; - self.arenas.alloc_decl(data) - } - // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. fn update_local_resolution( @@ -671,7 +672,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(binding) = resolution.best_decl() else { continue }; if let DeclKind::Import { import, .. } = binding.kind - && let Some(amb_binding) = binding.ambiguity + && let Some(amb_binding) = binding.ambiguity.get() && binding.res() != Res::Err && exported_ambiguities.contains(&binding) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index bce14f5376d7..311efb3e881b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -802,10 +802,10 @@ impl<'ra> fmt::Debug for Module<'ra> { } /// Data associated with any name declaration. -#[derive(Debug)] +#[derive(Clone, Debug)] struct DeclData<'ra> { kind: DeclKind<'ra>, - ambiguity: Option>, + ambiguity: CmCell>>, /// Produce a warning instead of an error when reporting ambiguities inside this binding. /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: CmCell, @@ -942,7 +942,7 @@ impl<'ra> DeclData<'ra> { } fn descent_to_ambiguity(self: Decl<'ra>) -> Option<(Decl<'ra>, Decl<'ra>)> { - match self.ambiguity { + match self.ambiguity.get() { Some(ambig_binding) => Some((self, ambig_binding)), None => match self.kind { DeclKind::Import { source_decl, .. } => source_decl.descent_to_ambiguity(), @@ -952,7 +952,7 @@ impl<'ra> DeclData<'ra> { } fn is_ambiguity_recursive(&self) -> bool { - self.ambiguity.is_some() + self.ambiguity.get().is_some() || match self.kind { DeclKind::Import { source_decl, .. } => source_decl.is_ambiguity_recursive(), _ => false, @@ -1346,7 +1346,7 @@ impl<'ra> ResolverArenas<'ra> { ) -> Decl<'ra> { self.alloc_decl(DeclData { kind: DeclKind::Def(res), - ambiguity: None, + ambiguity: CmCell::new(None), warn_ambiguity: CmCell::new(false), vis: CmCell::new(vis), span, @@ -2055,7 +2055,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { used: Used, warn_ambiguity: bool, ) { - if let Some(b2) = used_decl.ambiguity { + if let Some(b2) = used_decl.ambiguity.get() { let ambiguity_error = AmbiguityError { kind: AmbiguityKind::GlobVsGlob, ident, diff --git a/tests/ui/imports/issue-55884-1.rs b/tests/ui/imports/issue-55884-1.rs index 21744aa5d7bf..3c9c033c158e 100644 --- a/tests/ui/imports/issue-55884-1.rs +++ b/tests/ui/imports/issue-55884-1.rs @@ -17,5 +17,5 @@ mod m { fn main() { use m::S; //~ ERROR `S` is ambiguous - let s = S {}; + let s = S {}; //~ ERROR `S` is ambiguous } diff --git a/tests/ui/imports/issue-55884-1.stderr b/tests/ui/imports/issue-55884-1.stderr index ae8edb049564..a0b63ddc9108 100644 --- a/tests/ui/imports/issue-55884-1.stderr +++ b/tests/ui/imports/issue-55884-1.stderr @@ -18,6 +18,26 @@ LL | pub use self::m2::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `S` to disambiguate -error: aborting due to 1 previous error +error[E0659]: `S` is ambiguous + --> $DIR/issue-55884-1.rs:20:13 + | +LL | let s = S {}; + | ^ ambiguous name + | + = note: ambiguous because of multiple glob imports of a name in the same module +note: `S` could refer to the struct imported here + --> $DIR/issue-55884-1.rs:14:13 + | +LL | pub use self::m1::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `S` to disambiguate +note: `S` could also refer to the struct imported here + --> $DIR/issue-55884-1.rs:15:13 + | +LL | pub use self::m2::*; + | ^^^^^^^^^^^ + = help: consider adding an explicit import of `S` to disambiguate + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From 69bedd10d203edfd6559da629c78013345fa0d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 7 Jan 2026 14:27:27 +0100 Subject: [PATCH 250/340] compiler-builtins: Enable AArch64 `__chkstk` for MinGW Similarly to i686 and X86_64 MinGW targets, Rust needs to provide the right chkstk symbol for AArch64 to avoid relying on the linker to provide it. CC https://github.com/rust-lang/rust/issues/150725 --- library/compiler-builtins/compiler-builtins/src/aarch64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/compiler-builtins/compiler-builtins/src/aarch64.rs b/library/compiler-builtins/compiler-builtins/src/aarch64.rs index 039fab2061c5..1b230a214eef 100644 --- a/library/compiler-builtins/compiler-builtins/src/aarch64.rs +++ b/library/compiler-builtins/compiler-builtins/src/aarch64.rs @@ -4,7 +4,7 @@ use core::intrinsics; intrinsics! { #[unsafe(naked)] - #[cfg(target_os = "uefi")] + #[cfg(any(all(windows, target_env = "gnu"), target_os = "uefi"))] pub unsafe extern "custom" fn __chkstk() { core::arch::naked_asm!( ".p2align 2", From 64c78f6e74b885a0afaa4d6ad7d53e44033d714f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 5 Jan 2026 19:30:41 +0100 Subject: [PATCH 251/340] make `MarkdownItemInfo` a field struct --- src/librustdoc/html/markdown.rs | 17 ++++++++++++----- src/librustdoc/html/markdown/tests.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a4d377432c91..834c0cb669c0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -111,7 +111,10 @@ pub(crate) struct MarkdownWithToc<'a> { } /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags /// and includes no paragraph tags. -pub(crate) struct MarkdownItemInfo<'a>(pub(crate) &'a str, pub(crate) &'a mut IdMap); +pub(crate) struct MarkdownItemInfo<'a> { + pub(crate) content: &'a str, + pub(crate) ids: &'a mut IdMap, +} /// A tuple struct like `Markdown` that renders only the first paragraph. pub(crate) struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); @@ -1459,15 +1462,19 @@ impl MarkdownWithToc<'_> { } } -impl MarkdownItemInfo<'_> { +impl<'a> MarkdownItemInfo<'a> { + pub(crate) fn new(content: &'a str, ids: &'a mut IdMap) -> Self { + Self { content, ids } + } + pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result { - let MarkdownItemInfo(md, ids) = self; + let MarkdownItemInfo { content, ids } = self; // This is actually common enough to special-case - if md.is_empty() { + if content.is_empty() { return Ok(()); } - let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); + let p = Parser::new_ext(content, main_body_opts()).into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 61fd42874633..14d86a8abf57 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -471,7 +471,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let mut output = String::new(); - MarkdownItemInfo(input, &mut idmap).write_into(&mut output).unwrap(); + MarkdownItemInfo::new(input, &mut idmap).write_into(&mut output).unwrap(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 4529f5a8c016..de5c8a765275 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -877,7 +877,7 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); let mut id_map = cx.id_map.borrow_mut(); - let html = MarkdownItemInfo(note, &mut id_map); + let html = MarkdownItemInfo::new(note, &mut id_map); message.push_str(": "); html.write_into(&mut message).unwrap(); } From 3be74a744114ed8cdfd9dcd0bada5e17ff35e662 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 6 Jan 2026 12:04:38 +0100 Subject: [PATCH 252/340] render intra-doc links in the `#[deprectated]` note --- compiler/rustc_ast/src/attr/mod.rs | 34 ++++++++++++++ compiler/rustc_hir/src/hir.rs | 8 ++++ compiler/rustc_resolve/src/rustdoc.rs | 13 +++++- src/librustdoc/clean/types.rs | 10 +++++ src/librustdoc/html/markdown.rs | 21 ++++++--- src/librustdoc/html/markdown/tests.rs | 2 +- src/librustdoc/html/render/mod.rs | 3 +- .../passes/collect_intra_doc_links.rs | 45 +++++++++++++------ tests/rustdoc-html/intra-doc/deprecated.rs | 12 +++++ tests/rustdoc-ui/intra-doc/deprecated.rs | 10 +++++ tests/rustdoc-ui/intra-doc/deprecated.stderr | 43 ++++++++++++++++++ 11 files changed, 179 insertions(+), 22 deletions(-) create mode 100644 tests/rustdoc-html/intra-doc/deprecated.rs create mode 100644 tests/rustdoc-ui/intra-doc/deprecated.rs create mode 100644 tests/rustdoc-ui/intra-doc/deprecated.stderr diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 6ecba865c815..0a2a34d932f6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -235,6 +235,34 @@ impl AttributeExt for Attribute { } } + fn deprecation_note(&self) -> Option { + match &self.kind { + AttrKind::Normal(normal) if normal.item.path == sym::deprecated => { + let meta = &normal.item; + + // #[deprecated = "..."] + if let Some(s) = meta.value_str() { + return Some(s); + } + + // #[deprecated(note = "...")] + if let Some(list) = meta.meta_item_list() { + for nested in list { + if let Some(mi) = nested.meta_item() + && mi.path == sym::note + && let Some(s) = mi.value_str() + { + return Some(s); + } + } + } + + None + } + _ => None, + } + } + fn doc_resolution_scope(&self) -> Option { match &self.kind { AttrKind::DocComment(..) => Some(self.style), @@ -277,6 +305,7 @@ impl Attribute { pub fn may_have_doc_links(&self) -> bool { self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) + || self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str())) } /// Extracts the MetaItem from inside this Attribute. @@ -873,6 +902,11 @@ pub trait AttributeExt: Debug { /// * `#[doc(...)]` returns `None`. fn doc_str(&self) -> Option; + /// Returns the deprecation note if this is deprecation attribute. + /// * `#[deprecated = "note"]` returns `Some("note")`. + /// * `#[deprecated(note = "note", ...)]` returns `Some("note")`. + fn deprecation_note(&self) -> Option; + fn is_proc_macro_attr(&self) -> bool { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index aacd6324bb03..883ba23ca214 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1400,6 +1400,14 @@ impl AttributeExt for Attribute { } } + #[inline] + fn deprecation_note(&self) -> Option { + match &self { + Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note, + _ => None, + } + } + fn is_automatically_derived_attr(&self) -> bool { matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..))) } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 7f7c423acb40..9f74a7801d2e 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -410,8 +410,17 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool { /// Simplified version of `preprocessed_markdown_links` from rustdoc. /// Must return at least the same links as it, but may add some more links on top of that. pub(crate) fn attrs_to_preprocessed_links(attrs: &[A]) -> Vec> { - let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); - let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap(); + let (doc_fragments, other_attrs) = + attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false); + let mut doc = + prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap_or_default(); + + for attr in other_attrs { + if let Some(note) = attr.deprecation_note() { + doc += note.as_str(); + doc += "\n"; + } + } parse_links(&doc) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a390a03ff114..c3bafd3db13a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -7,6 +7,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use itertools::Either; use rustc_abi::{ExternAbi, VariantIdx}; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation, DocAttribute}; @@ -450,7 +451,16 @@ impl Item { } pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span { + let deprecation_notes = self + .attrs + .other_attrs + .iter() + .filter_map(|attr| attr.deprecation_note().map(|_| attr.span())); + span_of_fragments(&self.attrs.doc_strings) + .into_iter() + .chain(deprecation_notes) + .reduce(|a, b| a.to(b)) .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner())) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 834c0cb669c0..c472c20a7dc7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -113,6 +113,7 @@ pub(crate) struct MarkdownWithToc<'a> { /// and includes no paragraph tags. pub(crate) struct MarkdownItemInfo<'a> { pub(crate) content: &'a str, + pub(crate) links: &'a [RenderedLink], pub(crate) ids: &'a mut IdMap, } /// A tuple struct like `Markdown` that renders only the first paragraph. @@ -1463,18 +1464,27 @@ impl MarkdownWithToc<'_> { } impl<'a> MarkdownItemInfo<'a> { - pub(crate) fn new(content: &'a str, ids: &'a mut IdMap) -> Self { - Self { content, ids } + pub(crate) fn new(content: &'a str, links: &'a [RenderedLink], ids: &'a mut IdMap) -> Self { + Self { content, links, ids } } pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result { - let MarkdownItemInfo { content, ids } = self; + let MarkdownItemInfo { content: md, links, ids } = self; // This is actually common enough to special-case - if content.is_empty() { + if md.is_empty() { return Ok(()); } - let p = Parser::new_ext(content, main_body_opts()).into_offset_iter(); + + let replacer = move |broken_link: BrokenLink<'_>| { + links + .iter() + .find(|link| *link.original_text == *broken_link.reference) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) + }; + + let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(replacer)); + let p = p.into_offset_iter(); // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { @@ -1484,6 +1494,7 @@ impl<'a> MarkdownItemInfo<'a> { ids.handle_footnotes(|ids, existing_footnotes| { let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1); + let p = SpannedLinkReplacer::new(p, links); let p = footnotes::Footnotes::new(p, existing_footnotes); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = p.filter(|event| { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 14d86a8abf57..1c99ccc5228b 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -471,7 +471,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let mut output = String::new(); - MarkdownItemInfo::new(input, &mut idmap).write_into(&mut output).unwrap(); + MarkdownItemInfo::new(input, &[], &mut idmap).write_into(&mut output).unwrap(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index de5c8a765275..63de870f07f4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -877,7 +877,8 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); let mut id_map = cx.id_map.borrow_mut(); - let html = MarkdownItemInfo::new(note, &mut id_map); + let links = item.links(cx); + let html = MarkdownItemInfo::new(note, &links, &mut id_map); message.push_str(": "); html.write_into(&mut message).unwrap(); } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3abf0fee3959..07d6efaa97e1 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -7,6 +7,7 @@ use std::fmt::Display; use std::mem; use std::ops::Range; +use rustc_ast::attr::AttributeExt; use rustc_ast::util::comments::may_have_doc_links; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -1047,18 +1048,7 @@ impl LinkCollector<'_, '_> { return; } - // We want to resolve in the lexical scope of the documentation. - // In the presence of re-exports, this is not the same as the module of the item. - // Rather than merging all documentation into one, resolve it one attribute at a time - // so we know which module it came from. - for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { - if !may_have_doc_links(&doc) { - continue; - } - debug!("combined_docs={doc}"); - // NOTE: if there are links that start in one crate and end in another, this will not resolve them. - // This is a degenerate case and it's not supported by rustdoc. - let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + let mut insert_links = |item_id, doc: &str| { let module_id = match self.cx.tcx.def_kind(item_id) { DefKind::Mod if item.inner_docs(self.cx.tcx) => item_id, _ => find_nearest_parent_module(self.cx.tcx, item_id).unwrap(), @@ -1074,6 +1064,35 @@ impl LinkCollector<'_, '_> { .insert(link); } } + }; + + // We want to resolve in the lexical scope of the documentation. + // In the presence of re-exports, this is not the same as the module of the item. + // Rather than merging all documentation into one, resolve it one attribute at a time + // so we know which module it came from. + for (item_id, doc) in prepare_to_doc_link_resolution(&item.attrs.doc_strings) { + if !may_have_doc_links(&doc) { + continue; + } + + debug!("combined_docs={doc}"); + // NOTE: if there are links that start in one crate and end in another, this will not resolve them. + // This is a degenerate case and it's not supported by rustdoc. + let item_id = item_id.unwrap_or_else(|| item.item_id.expect_def_id()); + insert_links(item_id, &doc) + } + + // Also resolve links in the note text of `#[deprecated]`. + for attr in &item.attrs.other_attrs { + let Some(note_sym) = attr.deprecation_note() else { continue }; + let note = note_sym.as_str(); + + if !may_have_doc_links(note) { + continue; + } + + debug!("deprecated_note={note}"); + insert_links(item.item_id.expect_def_id(), note) } } @@ -1086,7 +1105,7 @@ impl LinkCollector<'_, '_> { /// FIXME(jynelson): this is way too many arguments fn resolve_link( &mut self, - dox: &String, + dox: &str, item: &Item, item_id: DefId, module_id: DefId, diff --git a/tests/rustdoc-html/intra-doc/deprecated.rs b/tests/rustdoc-html/intra-doc/deprecated.rs new file mode 100644 index 000000000000..6f8639593a2d --- /dev/null +++ b/tests/rustdoc-html/intra-doc/deprecated.rs @@ -0,0 +1,12 @@ +//@ has deprecated/struct.A.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start' +//@ has deprecated/struct.B1.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' +//@ has deprecated/struct.B2.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found' + +#[deprecated = "[start][std::ops::Range::start]"] +pub struct A; + +#[deprecated(since = "0.0.0", note = "[not_found][std::io::ErrorKind::NotFound]")] +pub struct B1; + +#[deprecated(note = "[not_found][std::io::ErrorKind::NotFound]", since = "0.0.0")] +pub struct B2; diff --git a/tests/rustdoc-ui/intra-doc/deprecated.rs b/tests/rustdoc-ui/intra-doc/deprecated.rs new file mode 100644 index 000000000000..37c27dcde598 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated.rs @@ -0,0 +1,10 @@ +#![deny(rustdoc::broken_intra_doc_links)] + +#[deprecated = "[broken cross-reference](TypeAlias::hoge)"] //~ ERROR +pub struct A; + +#[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] //~ ERROR +pub struct B1; + +#[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] //~ ERROR +pub struct B2; diff --git a/tests/rustdoc-ui/intra-doc/deprecated.stderr b/tests/rustdoc-ui/intra-doc/deprecated.stderr new file mode 100644 index 000000000000..9bd64544eef8 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/deprecated.stderr @@ -0,0 +1,43 @@ +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:3:1 + | +LL | #[deprecated = "[broken cross-reference](TypeAlias::hoge)"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope +note: the lint level is defined here + --> $DIR/deprecated.rs:1:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:6:1 + | +LL | #[deprecated(since = "0.0.0", note = "[broken cross-reference](TypeAlias::hoge)")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope + +error: unresolved link to `TypeAlias::hoge` + --> $DIR/deprecated.rs:9:1 + | +LL | #[deprecated(note = "[broken cross-reference](TypeAlias::hoge)", since = "0.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the link appears in this line: + + [broken cross-reference](TypeAlias::hoge) + ^^^^^^^^^^^^^^^ + = note: no item named `TypeAlias` in scope + +error: aborting due to 3 previous errors + From aec8b698784311402bd193497a26357297d105bc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 7 Jan 2026 16:26:52 +0000 Subject: [PATCH 253/340] Minor cleanups to fn_abi_new_uncached --- compiler/rustc_target/src/callconv/mod.rs | 11 +++++------ compiler/rustc_ty_utils/src/abi.rs | 12 +++--------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 092d99e91118..6faa57252ca2 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -381,15 +381,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn new( cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, - scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, Scalar, Size) -> ArgAttributes, + scalar_attrs: impl Fn(Scalar, Size) -> ArgAttributes, ) -> Self { let mode = match layout.backend_repr { - BackendRepr::Scalar(scalar) => { - PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)) - } + _ if layout.is_zst() => PassMode::Ignore, + BackendRepr::Scalar(scalar) => PassMode::Direct(scalar_attrs(scalar, Size::ZERO)), BackendRepr::ScalarPair(a, b) => PassMode::Pair( - scalar_attrs(&layout, a, Size::ZERO), - scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), + scalar_attrs(a, Size::ZERO), + scalar_attrs(b, a.size(cx).align_to(b.align(cx).abi)), ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0676fa99d826..ad621c67772c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -549,15 +549,9 @@ fn fn_abi_new_uncached<'tcx>( layout }; - let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { - arg_attrs_for_rust_scalar(*cx, scalar, *layout, offset, is_return, drop_target_pointee) - }); - - if arg.layout.is_zst() { - arg.mode = PassMode::Ignore; - } - - Ok(arg) + Ok(ArgAbi::new(cx, layout, |scalar, offset| { + arg_attrs_for_rust_scalar(*cx, scalar, layout, offset, is_return, drop_target_pointee) + })) }; let mut fn_abi = FnAbi { From a3359bdd4f117b6f315fce15e1d97d02c7bad015 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: [PATCH 254/340] Compile-Time Reflection MVP: tuples --- .../src/const_eval/machine.rs | 9 +- .../rustc_const_eval/src/const_eval/mod.rs | 1 + .../src/const_eval/type_info.rs | 158 ++++++++++++++++++ .../src/interpret/intrinsics.rs | 5 +- compiler/rustc_hir/src/lang_items.rs | 1 + .../rustc_hir_analysis/src/check/intrinsic.rs | 18 +- compiler/rustc_span/src/symbol.rs | 5 + library/core/src/intrinsics/mod.rs | 9 + library/core/src/lib.rs | 1 + library/core/src/mem/mod.rs | 3 + library/core/src/mem/type_info.rs | 69 ++++++++ src/tools/clippy/clippy_utils/src/sym.rs | 1 - .../abi/issues/issue-22565-rust-call.stderr | 4 +- tests/ui/error-codes/E0059.stderr | 4 +- tests/ui/impl-trait/where-allowed.stderr | 6 +- ...rust-call-abi-not-a-tuple-ice-81974.stderr | 16 +- .../overloaded-calls-nontuple.stderr | 12 +- tests/ui/reflection/dump.rs | 30 ++++ tests/ui/reflection/dump.run.stdout | 23 +++ tests/ui/reflection/feature_gate.rs | 8 + tests/ui/reflection/feature_gate.stderr | 33 ++++ tests/ui/reflection/tuples.rs | 36 ++++ .../resolve/resolve-assoc-suggestions.stderr | 4 + tests/ui/suggestions/fn-trait-notation.stderr | 4 +- tests/ui/thir-print/offset_of.stdout | 18 +- tests/ui/traits/ignore-err-impls.stderr | 6 +- .../next-solver/well-formed-in-relate.stderr | 6 +- tests/ui/tuple/builtin-fail.stderr | 8 +- tests/ui/typeck/issue-57404.stderr | 2 +- .../non-tupled-arg-mismatch.stderr | 2 +- triagebot.toml | 7 + 31 files changed, 456 insertions(+), 53 deletions(-) create mode 100644 compiler/rustc_const_eval/src/const_eval/type_info.rs create mode 100644 library/core/src/mem/type_info.rs create mode 100644 tests/ui/reflection/dump.rs create mode 100644 tests/ui/reflection/dump.run.stdout create mode 100644 tests/ui/reflection/feature_gate.rs create mode 100644 tests/ui/reflection/feature_gate.stderr create mode 100644 tests/ui/reflection/tuples.rs diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7538130e9d92..719187b99012 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; -use rustc_middle::mir::interpret::ReportedErrorInfo; +use rustc_middle::mir::interpret::{Pointer, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -22,7 +22,7 @@ use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, - GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, + GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, RangeSet, Scalar, compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; @@ -586,6 +586,11 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } + sym::type_of => { + let ty = ecx.read_type_id(&args[0])?; + ecx.write_type_info(ty, dest)?; + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 624ca1dd2da0..e70488b81c4c 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -13,6 +13,7 @@ mod error; mod eval_queries; mod fn_queries; mod machine; +mod type_info; mod valtrees; pub use self::dummy_machine::*; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs new file mode 100644 index 000000000000..a94ef580027b --- /dev/null +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -0,0 +1,158 @@ +use rustc_abi::FieldIdx; +use rustc_hir::LangItem; +use rustc_middle::mir::interpret::CtfeProvenance; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::{self, ScalarInt, Ty}; +use rustc_span::{Symbol, sym}; + +use crate::const_eval::CompileTimeMachine; +use crate::interpret::{ + Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok, +}; + +impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { + /// Writes a `core::mem::type_info::TypeInfo` for a given type, `ty` to the given place. + pub(crate) fn write_type_info( + &mut self, + ty: Ty<'tcx>, + dest: &impl Writeable<'tcx, CtfeProvenance>, + ) -> InterpResult<'tcx> { + let ty_struct = self.tcx.require_lang_item(LangItem::Type, self.tcx.span); + let ty_struct = self.tcx.type_of(ty_struct).no_bound_vars().unwrap(); + assert_eq!(ty_struct, dest.layout().ty); + let ty_struct = ty_struct.ty_adt_def().unwrap().non_enum_variant(); + // Fill all fields of the `TypeInfo` struct. + for (idx, field) in ty_struct.fields.iter_enumerated() { + let field_dest = self.project_field(dest, idx)?; + let downcast = |name: Symbol| { + let variants = field_dest.layout().ty.ty_adt_def().unwrap().variants(); + let variant_id = variants + .iter_enumerated() + .find(|(_idx, var)| var.name == name) + .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) + .0; + + interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?)) + }; + match field.name { + sym::kind => { + let variant_index = match ty.kind() { + ty::Tuple(fields) => { + let (variant, variant_place) = downcast(sym::Tuple)?; + // project to the single tuple variant field of `type_info::Tuple` struct type + let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; + assert_eq!( + 1, + tuple_place + .layout() + .ty + .ty_adt_def() + .unwrap() + .non_enum_variant() + .fields + .len() + ); + self.write_tuple_fields(tuple_place, fields, ty)?; + variant + } + // For now just merge all primitives into one `Leaf` variant with no data + ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => { + downcast(sym::Leaf)?.0 + } + ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::UnsafeBinder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Alias(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(..) + | ty::Error(_) => downcast(sym::Other)?.0, + }; + self.write_discriminant(variant_index, &field_dest)? + } + other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), + } + } + + interp_ok(()) + } + + pub(crate) fn write_tuple_fields( + &mut self, + tuple_place: impl Writeable<'tcx, CtfeProvenance>, + fields: &[Ty<'tcx>], + tuple_ty: Ty<'tcx>, + ) -> InterpResult<'tcx> { + // project into the `type_info::Tuple::fields` field + let fields_slice_place = self.project_field(&tuple_place, FieldIdx::ZERO)?; + // get the `type_info::Field` type from `fields: &[Field]` + let field_type = fields_slice_place + .layout() + .ty + .builtin_deref(false) + .unwrap() + .sequence_element_type(self.tcx.tcx); + // Create an array with as many elements as the number of fields in the inspected tuple + let fields_layout = + self.layout_of(Ty::new_array(self.tcx.tcx, field_type, fields.len() as u64))?; + let fields_place = self.allocate(fields_layout, MemoryKind::Stack)?; + let mut fields_places = self.project_array_fields(&fields_place)?; + + let tuple_layout = self.layout_of(tuple_ty)?; + + while let Some((i, place)) = fields_places.next(self)? { + let field_ty = fields[i as usize]; + self.write_field(field_ty, place, tuple_layout, i)?; + } + + let fields_place = fields_place.map_provenance(CtfeProvenance::as_immutable); + + let ptr = Immediate::new_slice(fields_place.ptr(), fields.len() as u64, self); + + self.write_immediate(ptr, &fields_slice_place) + } + + fn write_field( + &mut self, + field_ty: Ty<'tcx>, + place: MPlaceTy<'tcx>, + layout: TyAndLayout<'tcx>, + idx: u64, + ) -> InterpResult<'tcx> { + for (field_idx, field_ty_field) in + place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated() + { + let field_place = self.project_field(&place, field_idx)?; + match field_ty_field.name { + sym::ty => self.write_type_id(field_ty, &field_place)?, + sym::offset => { + let offset = layout.fields.offset(idx as usize); + self.write_scalar( + ScalarInt::try_from_target_usize(offset.bytes(), self.tcx.tcx).unwrap(), + &field_place, + )?; + } + other => { + span_bug!(self.tcx.def_span(field_ty_field.did), "unimplemented field {other}") + } + } + } + interp_ok(()) + } +} diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d70d157d8808..94832c0c2577 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -27,6 +27,7 @@ use super::{ throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; +use crate::interpret::Writeable; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MulAddType { @@ -68,10 +69,10 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId } impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Generates a value of `TypeId` for `ty` in-place. - fn write_type_id( + pub(crate) fn write_type_id( &mut self, ty: Ty<'tcx>, - dest: &PlaceTy<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ()> { let tcx = self.tcx; let type_id_hash = tcx.type_id_hash(ty).as_u128(); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4ac3e4e83e80..557f76208bfe 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -278,6 +278,7 @@ language_item_table! { PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1); CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None; + Type, sym::type_info, type_struct, Target::Struct, GenericRequirement::None; TypeId, sym::type_id, type_id, Target::Struct, GenericRequirement::None; // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 9eaf5319cb04..c84c1a8ca16d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -213,6 +213,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::type_id | sym::type_id_eq | sym::type_name + | sym::type_of | sym::ub_checks | sym::variant_count | sym::vtable_for @@ -308,13 +309,22 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => { - (1, 0, vec![], tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity()) - } + sym::type_id => ( + 1, + 0, + vec![], + tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(), + ), sym::type_id_eq => { - let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).instantiate_identity(); + let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); (0, 0, vec![type_id, type_id], tcx.types.bool) } + sym::type_of => ( + 0, + 0, + vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()], + tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(), + ), sym::offload => ( 3, 0, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72709753b1df..1e288adc11cb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -284,6 +284,7 @@ symbols! { IteratorItem, IteratorMap, Layout, + Leaf, Left, LinkedList, LintDiagnostic, @@ -302,6 +303,7 @@ symbols! { Ordering, OsStr, OsString, + Other, Output, Param, ParamSet, @@ -380,6 +382,7 @@ symbols! { TryCapturePrintable, TryFrom, TryInto, + Tuple, Ty, TyCtxt, TyKind, @@ -2317,6 +2320,7 @@ symbols! { type_const, type_id, type_id_eq, + type_info, type_ir, type_ir_infer_ctxt_like, type_ir_inherent, @@ -2324,6 +2328,7 @@ symbols! { type_length_limit, type_macros, type_name, + type_of, type_privacy_lints, typed_swap_nonoverlapping, u8, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 0ae8d3d4a4ce..e8e0cda38e9b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2849,6 +2849,15 @@ pub const unsafe fn size_of_val(ptr: *const T) -> usize; #[rustc_intrinsic_const_stable_indirect] pub const unsafe fn align_of_val(ptr: *const T) -> usize; +/// Compute the type information of a concrete type. +/// It can only be called at compile time, the backends do +/// not implement it. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { + panic!("`TypeId::info` can only be called at compile-time") +} + /// Gets a static string slice containing the name of a type. /// /// Note that, unlike most intrinsics, this can only be called at compile-time diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 962b0cea4a4f..dfc9a7b5dbc3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -124,6 +124,7 @@ #![feature(str_internals)] #![feature(str_split_inclusive_remainder)] #![feature(str_split_remainder)] +#![feature(type_info)] #![feature(ub_checks)] #![feature(unsafe_pinned)] #![feature(utf16_extra)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 4f7edce1e977..1671c8219de1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -37,6 +37,9 @@ pub use drop_guard::DropGuard; #[doc(inline)] pub use crate::intrinsics::transmute; +#[unstable(feature = "type_info", issue = "146922")] +pub mod type_info; + /// Takes ownership and "forgets" about the value **without running its destructor**. /// /// Any resources the value manages, such as heap memory or a file handle, will linger diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs new file mode 100644 index 000000000000..b188504f76d9 --- /dev/null +++ b/library/core/src/mem/type_info.rs @@ -0,0 +1,69 @@ +//! MVP for exposing compile-time information about types in a +//! runtime or const-eval processable way. + +use crate::any::TypeId; +use crate::intrinsics::type_of; + +/// Compile-time type information. +#[derive(Debug)] +#[non_exhaustive] +#[lang = "type_info"] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Type { + /// Per-type information + pub kind: TypeKind, +} + +impl TypeId { + /// Compute the type information of a concrete type. + /// It can only be called at compile time. + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn info(self) -> Type { + type_of(self) + } +} + +impl Type { + /// Returns the type information of the generic type parameter. + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + // FIXME(reflection): don't require the 'static bound + pub const fn of() -> Self { + const { TypeId::of::().info() } + } +} + +/// Compile-time type information. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub enum TypeKind { + /// Tuples. + Tuple(Tuple), + /// Primitives + /// FIXME(#146922): disambiguate further + Leaf, + /// FIXME(#146922): add all the common types + Other, +} + +/// Compile-time type information about tuples. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Tuple { + /// All fields of a tuple. + pub fields: &'static [Field], +} + +/// Compile-time type information about fields of tuples, structs and enum variants. +#[derive(Debug)] +#[non_exhaustive] +#[unstable(feature = "type_info", issue = "146922")] +pub struct Field { + /// The field's type. + pub ty: TypeId, + /// Offset in bytes from the parent type + pub offset: usize, +} diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index a0d2e8673fe6..74f89cfc6811 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -62,7 +62,6 @@ generate! { MsrvStack, Octal, OpenOptions, - Other, PathLookup, Regex, RegexBuilder, diff --git a/tests/ui/abi/issues/issue-22565-rust-call.stderr b/tests/ui/abi/issues/issue-22565-rust-call.stderr index 0fd3285cd3a5..3e296bdaea41 100644 --- a/tests/ui/abi/issues/issue-22565-rust-call.stderr +++ b/tests/ui/abi/issues/issue-22565-rust-call.stderr @@ -2,7 +2,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:3:1 | LL | extern "rust-call" fn b(_i: i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:17:5 @@ -32,7 +32,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/issue-22565-rust-call.rs:27:7 | LL | b(10); - | ^^ the trait `Tuple` is not implemented for `i32` + | ^^ the trait `std::marker::Tuple` is not implemented for `i32` error: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/issue-22565-rust-call.rs:29:5 diff --git a/tests/ui/error-codes/E0059.stderr b/tests/ui/error-codes/E0059.stderr index d26fadcdbfa7..698ee0a2a902 100644 --- a/tests/ui/error-codes/E0059.stderr +++ b/tests/ui/error-codes/E0059.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/E0059.rs:3:11 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/E0059.rs:3:41 | LL | fn foo>(f: F) -> F::Output { f(3) } - | ^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit --> $DIR/E0059.rs:3:41 diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 6cab4fabb1ff..1a8d6509e137 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -384,11 +384,11 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani | = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F - where A: Tuple, F: Fn, F: ?Sized; + where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box - where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for Exclusive - where F: Sync, F: Fn, Args: Tuple; + where F: Sync, F: Fn, Args: std::marker::Tuple; error[E0118]: no nominal type found for inherent implementation --> $DIR/where-allowed.rs:241:1 diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr index 75ee936d9e8b..e7cb82687fa7 100644 --- a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr +++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -15,7 +15,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:24:12 | LL | impl FnOnce for CachedFun - | ^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -28,7 +28,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -41,7 +41,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:39:12 | LL | impl FnMut for CachedFun - | ^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -54,7 +54,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 | LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -65,7 +65,7 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:45:5 | LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `A` | help: consider further restricting type parameter `A` with unstable trait `Tuple` | @@ -76,7 +76,7 @@ error[E0277]: `A` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:34:19 | LL | self.call_mut(a) - | -------- ^ the trait `Tuple` is not implemented for `A` + | -------- ^ the trait `std::marker::Tuple` is not implemented for `A` | | | required by a bound introduced by this call | @@ -91,7 +91,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:59:26 | LL | cachedcoso.call_once(1); - | --------- ^ the trait `Tuple` is not implemented for `i32` + | --------- ^ the trait `std::marker::Tuple` is not implemented for `i32` | | | required by a bound introduced by this call | diff --git a/tests/ui/overloaded/overloaded-calls-nontuple.stderr b/tests/ui/overloaded/overloaded-calls-nontuple.stderr index 22598f3a3901..54a9d1f09b52 100644 --- a/tests/ui/overloaded/overloaded-calls-nontuple.stderr +++ b/tests/ui/overloaded/overloaded-calls-nontuple.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `FnMut` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:10:6 | LL | impl FnMut for S { - | ^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -11,7 +11,7 @@ error[E0059]: type parameter to bare `FnOnce` trait must be a tuple --> $DIR/overloaded-calls-nontuple.rs:18:6 | LL | impl FnOnce for S { - | ^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` | note: required by a bound in `FnOnce` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -20,19 +20,19 @@ error[E0277]: functions with the "rust-call" ABI must take a single non-self tup --> $DIR/overloaded-calls-nontuple.rs:12:5 | LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument --> $DIR/overloaded-calls-nontuple.rs:21:5 | LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:23:23 | LL | self.call_mut(z) - | -------- ^ the trait `Tuple` is not implemented for `isize` + | -------- ^ the trait `std::marker::Tuple` is not implemented for `isize` | | | required by a bound introduced by this call | @@ -53,7 +53,7 @@ error[E0277]: `isize` is not a tuple --> $DIR/overloaded-calls-nontuple.rs:29:10 | LL | drop(s(3)) - | ^^^^ the trait `Tuple` is not implemented for `isize` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `isize` error: aborting due to 7 previous errors diff --git a/tests/ui/reflection/dump.rs b/tests/ui/reflection/dump.rs new file mode 100644 index 000000000000..3bf4f32b6641 --- /dev/null +++ b/tests/ui/reflection/dump.rs @@ -0,0 +1,30 @@ +#![feature(type_info)] +//@ run-pass +//@ check-run-results +#![allow(dead_code)] + +use std::mem::type_info::Type; + +struct Foo { + a: u32, +} + +enum Bar { + Some(u32), + None, + Foomp { a: (), b: &'static str }, +} + +struct Unsized { + x: u16, + s: str, +} + +fn main() { + println!("{:#?}", const { Type::of::<(u8, u8, ())>() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::() }.kind); + println!("{:#?}", const { Type::of::<&Unsized>() }.kind); + println!("{:#?}", const { Type::of::<&str>() }.kind); + println!("{:#?}", const { Type::of::<&[u8]>() }.kind); +} diff --git a/tests/ui/reflection/dump.run.stdout b/tests/ui/reflection/dump.run.stdout new file mode 100644 index 000000000000..71fd80b46658 --- /dev/null +++ b/tests/ui/reflection/dump.run.stdout @@ -0,0 +1,23 @@ +Tuple( + Tuple { + fields: [ + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 0, + }, + Field { + ty: TypeId(0x0596b48cc04376e64d5c788c2aa46bdb), + offset: 1, + }, + Field { + ty: TypeId(0x41223169ff28813ba79b7268a2a968d9), + offset: 2, + }, + ], + }, +) +Other +Other +Other +Other +Other diff --git a/tests/ui/reflection/feature_gate.rs b/tests/ui/reflection/feature_gate.rs new file mode 100644 index 000000000000..2dde26809793 --- /dev/null +++ b/tests/ui/reflection/feature_gate.rs @@ -0,0 +1,8 @@ +use std::mem::type_info::Type; +//~^ ERROR: use of unstable library feature `type_info` + +fn main() { + let ty = std::mem::type_info::Type::of::<()>(); + //~^ ERROR: use of unstable library feature `type_info` + //~| ERROR: use of unstable library feature `type_info` +} diff --git a/tests/ui/reflection/feature_gate.stderr b/tests/ui/reflection/feature_gate.stderr new file mode 100644 index 000000000000..76ad18ffb0ba --- /dev/null +++ b/tests/ui/reflection/feature_gate.stderr @@ -0,0 +1,33 @@ +error[E0658]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:1:5 + | +LL | use std::mem::type_info::Type; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` 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]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:5:14 + | +LL | let ty = std::mem::type_info::Type::of::<()>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` 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]: use of unstable library feature `type_info` + --> $DIR/feature_gate.rs:5:14 + | +LL | let ty = std::mem::type_info::Type::of::<()>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146922 for more information + = help: add `#![feature(type_info)]` 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 + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/reflection/tuples.rs b/tests/ui/reflection/tuples.rs new file mode 100644 index 000000000000..eab25a691efe --- /dev/null +++ b/tests/ui/reflection/tuples.rs @@ -0,0 +1,36 @@ +#![feature(type_info)] + +//@ run-pass + +use std::mem::type_info::{Type, TypeKind}; + +fn assert_tuple_arity() { + const { + match &Type::of::().kind { + TypeKind::Tuple(tup) => { + assert!(tup.fields.len() == N); + } + _ => unreachable!(), + } + } +} + +fn main() { + assert_tuple_arity::<(), 0>(); + assert_tuple_arity::<(u8,), 1>(); + assert_tuple_arity::<(u8, u8), 2>(); + const { + match &Type::of::<(u8, u8)>().kind { + TypeKind::Tuple(tup) => { + let [a, b] = tup.fields else { unreachable!() }; + assert!(a.offset == 0); + assert!(b.offset == 1); + match (&a.ty.info().kind, &b.ty.info().kind) { + (TypeKind::Leaf, TypeKind::Leaf) => {} + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/tests/ui/resolve/resolve-assoc-suggestions.stderr b/tests/ui/resolve/resolve-assoc-suggestions.stderr index ef519ac0d921..7d94fb5ca35f 100644 --- a/tests/ui/resolve/resolve-assoc-suggestions.stderr +++ b/tests/ui/resolve/resolve-assoc-suggestions.stderr @@ -31,6 +31,10 @@ help: you might have meant to use the associated type | LL | let _: Self::Type; | ++++++ +help: consider importing this struct + | +LL + use std::mem::type_info::Type; + | error[E0531]: cannot find tuple struct or tuple variant `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:25:13 diff --git a/tests/ui/suggestions/fn-trait-notation.stderr b/tests/ui/suggestions/fn-trait-notation.stderr index 9b47c8c02a78..9d0845478527 100644 --- a/tests/ui/suggestions/fn-trait-notation.stderr +++ b/tests/ui/suggestions/fn-trait-notation.stderr @@ -32,7 +32,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/fn-trait-notation.rs:4:8 | LL | F: Fn, - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -47,7 +47,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/fn-trait-notation.rs:9:5 | LL | f(3); - | ^^^^ the trait `Tuple` is not implemented for `i32` + | ^^^^ the trait `std::marker::Tuple` is not implemented for `i32` error[E0308]: mismatched types --> $DIR/fn-trait-notation.rs:17:5 diff --git a/tests/ui/thir-print/offset_of.stdout b/tests/ui/thir-print/offset_of.stdout index ab924091ba7a..dcf60a86af9b 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: 1437:57 (#0) + span: $DIR/offset_of.rs:37:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:38:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:39:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:40:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:41:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:45:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:46:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:47:5: 1440: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: 1437:57 (#0) + span: $DIR/offset_of.rs:48:5: 1440:57 (#0) } } ] diff --git a/tests/ui/traits/ignore-err-impls.stderr b/tests/ui/traits/ignore-err-impls.stderr index 68077c435135..46a2a7d55a2e 100644 --- a/tests/ui/traits/ignore-err-impls.stderr +++ b/tests/ui/traits/ignore-err-impls.stderr @@ -4,10 +4,10 @@ error[E0425]: cannot find type `Type` in this scope LL | impl Generic for S {} | ^^^^ not found in this scope | -help: you might be missing a type parameter +help: consider importing this struct + | +LL + use std::mem::type_info::Type; | -LL | impl Generic for S {} - | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index d79e465b3e38..264ab9bebbb9 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -9,11 +9,11 @@ LL | x = unconstrained_map(); | = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F - where A: Tuple, F: Fn, F: ?Sized; + where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box - where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for Exclusive - where F: Sync, F: Fn, Args: Tuple; + where F: Sync, F: Fn, Args: std::marker::Tuple; note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 | diff --git a/tests/ui/tuple/builtin-fail.stderr b/tests/ui/tuple/builtin-fail.stderr index 44e79578f4c9..0dec88ded7ce 100644 --- a/tests/ui/tuple/builtin-fail.stderr +++ b/tests/ui/tuple/builtin-fail.stderr @@ -2,7 +2,7 @@ error[E0277]: `T` is not a tuple --> $DIR/builtin-fail.rs:8:23 | LL | assert_is_tuple::(); - | ^ the trait `Tuple` is not implemented for `T` + | ^ the trait `std::marker::Tuple` is not implemented for `T` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -18,7 +18,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:13:23 | LL | assert_is_tuple::(); - | ^^^ the trait `Tuple` is not implemented for `i32` + | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -30,7 +30,7 @@ error[E0277]: `i32` is not a tuple --> $DIR/builtin-fail.rs:15:24 | LL | assert_is_tuple::<(i32)>(); - | ^^^ the trait `Tuple` is not implemented for `i32` + | ^^^ the trait `std::marker::Tuple` is not implemented for `i32` | note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 @@ -44,7 +44,7 @@ error[E0277]: `TupleStruct` is not a tuple LL | assert_is_tuple::(); | ^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `Tuple` is not implemented for `TupleStruct` +help: the trait `std::marker::Tuple` is not implemented for `TupleStruct` --> $DIR/builtin-fail.rs:5:1 | LL | struct TupleStruct(i32, i32); diff --git a/tests/ui/typeck/issue-57404.stderr b/tests/ui/typeck/issue-57404.stderr index 4c1bfc0cbf77..f1d28e475a07 100644 --- a/tests/ui/typeck/issue-57404.stderr +++ b/tests/ui/typeck/issue-57404.stderr @@ -2,7 +2,7 @@ error[E0277]: `&mut ()` is not a tuple --> $DIR/issue-57404.rs:6:41 | LL | handlers.unwrap().as_mut().call_mut(&mut ()); - | -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()` + | -------- ^^^^^^^ the trait `std::marker::Tuple` is not implemented for `&mut ()` | | | required by a bound introduced by this call | diff --git a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr index 0d4265ddf8bd..621a533dd1c5 100644 --- a/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr +++ b/tests/ui/unboxed-closures/non-tupled-arg-mismatch.stderr @@ -2,7 +2,7 @@ error[E0059]: type parameter to bare `Fn` trait must be a tuple --> $DIR/non-tupled-arg-mismatch.rs:3:9 | LL | fn a>(f: F) {} - | ^^^^^^^^^ the trait `Tuple` is not implemented for `usize` + | ^^^^^^^^^ the trait `std::marker::Tuple` is not implemented for `usize` | note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/triagebot.toml b/triagebot.toml index fb6660b9dd03..9afe66c24717 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1003,6 +1003,13 @@ cc = ["@lcnr"] message = "HIR ty lowering was modified" cc = ["@fmease"] +[mentions."library/core/src/mem/type_info.rs"] +message = """ +The reflection data structures are tied exactly to the implementation +in the compiler. Make sure to also adjust `rustc_const_eval/src/const_eval/type_info.rs +""" +cc = ["@oli-obk"] + [mentions."compiler/rustc_error_codes/src/lib.rs"] message = "Some changes occurred in diagnostic error codes" cc = ["@GuillaumeGomez"] From 2afe5b1a837b5e4d1cb27f675218de4c800d2b80 Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Thu, 8 Jan 2026 11:59:41 +0000 Subject: [PATCH 255/340] Fix ICE in inline always warning emission. The calls to `def_path_str` were outside the decorate callback in `node_span_lint` which caused an ICE when the warning was an allowed warning due to the call to `def_path_str` being executed but the warning not actually being emitted. --- compiler/rustc_mir_transform/src/errors.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index ee21d4fbcead..21a6c4d653bc 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -19,14 +19,14 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( caller_def_id: DefId, callee_only: &[&'a str], ) { - let callee = tcx.def_path_str(callee_def_id); - let caller = tcx.def_path_str(caller_def_id); - tcx.node_span_lint( lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), call_span, |lint| { + let callee = tcx.def_path_str(callee_def_id); + let caller = tcx.def_path_str(caller_def_id); + lint.primary_message(format!( "call to `#[inline(always)]`-annotated `{callee}` \ requires the same target features to be inlined" From 82028b0f9a9695edd3f70d54234df0bb61e4184d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Mar 2025 14:39:58 +0000 Subject: [PATCH 256/340] Add size information --- .../src/const_eval/type_info.rs | 17 +++++++++++++++++ library/core/src/mem/type_info.rs | 2 ++ 2 files changed, 19 insertions(+) diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index a94ef580027b..f932b198b426 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -86,6 +86,23 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { }; self.write_discriminant(variant_index, &field_dest)? } + sym::size => { + let layout = self.layout_of(ty)?; + let variant_index = if layout.is_sized() { + let (variant, variant_place) = downcast(sym::Some)?; + let size_field_place = + self.project_field(&variant_place, FieldIdx::ZERO)?; + self.write_scalar( + ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx) + .unwrap(), + &size_field_place, + )?; + variant + } else { + downcast(sym::None)?.0 + }; + self.write_discriminant(variant_index, &field_dest)?; + } other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), } } diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index b188504f76d9..7938e2b52ed0 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -12,6 +12,8 @@ use crate::intrinsics::type_of; pub struct Type { /// Per-type information pub kind: TypeKind, + /// Size of the type. `None` if it is unsized + pub size: Option, } impl TypeId { From d41191958a87e483de72fd73fc4470b0f9b9e6f2 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 8 Jan 2026 12:35:30 +0000 Subject: [PATCH 257/340] rename the `derive_{eq, clone_copy}` features to `*_internals` --- library/core/src/clone.rs | 6 +++--- library/core/src/cmp.rs | 8 ++++++-- library/core/src/marker.rs | 2 +- .../{derive-eq.md => derive-clone-copy-internals.md} | 2 +- .../{derive-clone-copy.md => derive-eq-internals.md} | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) rename src/doc/unstable-book/src/library-features/{derive-eq.md => derive-clone-copy-internals.md} (77%) rename src/doc/unstable-book/src/library-features/{derive-clone-copy.md => derive-eq-internals.md} (82%) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index e3d4b5c3331c..85b09ee06f1f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -285,7 +285,7 @@ pub const unsafe trait TrivialClone: [const] Clone {} /// Derive macro generating an impl of the trait `Clone`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_clone_copy, trivial_clone)] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy_internals, trivial_clone)] pub macro Clone($item:item) { /* compiler built-in */ } @@ -350,7 +350,7 @@ impl_use_cloned! { #[doc(hidden)] #[allow(missing_debug_implementations)] #[unstable( - feature = "derive_clone_copy", + feature = "derive_clone_copy_internals", reason = "deriving hack, should not be public", issue = "none" )] @@ -360,7 +360,7 @@ pub struct AssertParamIsClone { #[doc(hidden)] #[allow(missing_debug_implementations)] #[unstable( - feature = "derive_clone_copy", + feature = "derive_clone_copy_internals", reason = "deriving hack, should not be public", issue = "none" )] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index feb9c4319604..2f2477008206 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -351,7 +351,7 @@ pub const trait Eq: [const] PartialEq + PointeeSized { /// Derive macro generating an impl of the trait [`Eq`]. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] +#[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)] #[allow_internal_unstable(coverage_attribute)] pub macro Eq($item:item) { /* compiler built-in */ @@ -363,7 +363,11 @@ pub macro Eq($item:item) { // This struct should never appear in user code. #[doc(hidden)] #[allow(missing_debug_implementations)] -#[unstable(feature = "derive_eq", reason = "deriving hack, should not be public", issue = "none")] +#[unstable( + feature = "derive_eq_internals", + reason = "deriving hack, should not be public", + issue = "none" +)] pub struct AssertParamIsEq { _field: crate::marker::PhantomData, } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ecc2a63ea83..68f5649210de 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -466,7 +466,7 @@ pub trait Copy: Clone { /// Derive macro generating an impl of the trait `Copy`. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow_internal_unstable(core_intrinsics, derive_clone_copy)] +#[allow_internal_unstable(core_intrinsics, derive_clone_copy_internals)] pub macro Copy($item:item) { /* compiler built-in */ } diff --git a/src/doc/unstable-book/src/library-features/derive-eq.md b/src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md similarity index 77% rename from src/doc/unstable-book/src/library-features/derive-eq.md rename to src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md index 68a275f5419d..c53a55132de5 100644 --- a/src/doc/unstable-book/src/library-features/derive-eq.md +++ b/src/doc/unstable-book/src/library-features/derive-clone-copy-internals.md @@ -1,4 +1,4 @@ -# `derive_eq` +# `derive_clone_copy_internals` This feature is internal to the Rust compiler and is not intended for general use. diff --git a/src/doc/unstable-book/src/library-features/derive-clone-copy.md b/src/doc/unstable-book/src/library-features/derive-eq-internals.md similarity index 82% rename from src/doc/unstable-book/src/library-features/derive-clone-copy.md rename to src/doc/unstable-book/src/library-features/derive-eq-internals.md index cc603911cbd2..3f334b5ad3b6 100644 --- a/src/doc/unstable-book/src/library-features/derive-clone-copy.md +++ b/src/doc/unstable-book/src/library-features/derive-eq-internals.md @@ -1,4 +1,4 @@ -# `derive_clone_copy` +# `derive_eq_internals` This feature is internal to the Rust compiler and is not intended for general use. From 27b1083a96ab1bcc8b511882b31534e333a8e5c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 14:10:33 +0100 Subject: [PATCH 258/340] Update `literal-escaper` version to `0.0.7` --- Cargo.lock | 4 ++-- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- library/Cargo.lock | 5 ++--- library/proc_macro/Cargo.toml | 2 +- src/tools/clippy/clippy_dev/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 427e93e56cd8..4c1697ec4d0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3412,9 +3412,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-literal-escaper" -version = "0.0.5" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" +checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" [[package]] name = "rustc-main" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 34d90adf5cb3..471a6bf1df13 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" memchr = "2.7.6" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 04a51c905661..f0c84e07a56f 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index d178fcda1fb9..10b41a39c3bf 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index beb95aa3b52f..54c765075113 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" # tidy-alphabetical-end [features] diff --git a/library/Cargo.lock b/library/Cargo.lock index 5e49843dae06..f6c14bc58a04 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -283,12 +283,11 @@ dependencies = [ [[package]] name = "rustc-literal-escaper" -version = "0.0.5" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b" +checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" dependencies = [ "rustc-std-workspace-core", - "rustc-std-workspace-std", ] [[package]] diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index 3a4840a57334..1e5046ca61c3 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -9,7 +9,7 @@ std = { path = "../std" } # `core` when resolving doc links. Without this line a different `core` will be # loaded from sysroot causing duplicate lang items and other similar errors. core = { path = "../core" } -rustc-literal-escaper = { version = "0.0.5", features = ["rustc-dep-of-std"] } +rustc-literal-escaper = { version = "0.0.7", features = ["rustc-dep-of-std"] } [features] default = ["rustc-dep-of-std"] diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index c2abbac37535..238465210ee2 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -10,7 +10,7 @@ clap = { version = "4.4", features = ["derive"] } indoc = "1.0" itertools = "0.12" opener = "0.7" -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" walkdir = "2.3" [package.metadata.rust-analyzer] diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index 6e1ab84ed18d..ab99eb8ea3b7 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -7,7 +7,7 @@ description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rustc-literal-escaper = "0.0.5" +rustc-literal-escaper = "0.0.7" serde_json = "1.0.57" tempfile = "3.1.0" walkdir = "2.3.1" From 665770ec84032d2ce7e5c90fa116764c0d9c61cf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:03:56 +0000 Subject: [PATCH 259/340] Remove std_detect_file_io and std_detect_dlsym_getauxval features They were introduced back when std_detect was a standalone crate published to crates.io. The motivation for std_detect_dlsym_getauxval was to allow using getauxval without dlopen when statically linking musl, which we now unconditionally do for musl. And for std_detect_file_io to allow no_std usage, which std_detect now supports even with that feature enabled as it directly uses libc. This also prevents accidentally disabling runtime feature detection when using cargo build -Zbuild-std -Zbuild-std-features= --- library/std/Cargo.toml | 4 -- library/std_detect/Cargo.toml | 7 +-- library/std_detect/README.md | 26 ----------- library/std_detect/src/detect/mod.rs | 8 ++-- .../src/detect/os/linux/aarch64/tests.rs | 1 - .../std_detect/src/detect/os/linux/auxvec.rs | 44 +++++++------------ .../src/detect/os/linux/auxvec/tests.rs | 3 -- library/std_detect/src/detect/os/linux/mod.rs | 4 +- library/std_detect/src/lib.rs | 3 +- library/sysroot/Cargo.toml | 4 +- 10 files changed, 24 insertions(+), 80 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 43caf7734fdb..5c9ae52d9e6c 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -128,10 +128,6 @@ debug_refcell = ["core/debug_refcell"] llvm_enzyme = ["core/llvm_enzyme"] -# Enable std_detect features: -std_detect_file_io = ["std_detect/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] - # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = ["windows-targets/windows_raw_dylib"] diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index 2739bb592300..bcfdb3901957 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -25,10 +25,7 @@ core = { version = "1.0.0", package = 'rustc-std-workspace-core' } alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' } [target.'cfg(not(windows))'.dependencies] -libc = { version = "0.2.0", optional = true, default-features = false } +libc = { version = "0.2.0", default-features = false } [features] -default = [] -std_detect_file_io = [ "libc" ] -std_detect_dlsym_getauxval = [ "libc" ] -std_detect_env_override = [ "libc" ] +std_detect_env_override = [] diff --git a/library/std_detect/README.md b/library/std_detect/README.md index 177848dec104..895f3426d049 100644 --- a/library/std_detect/README.md +++ b/library/std_detect/README.md @@ -21,32 +21,6 @@ run-time feature detection support than the one offered by Rust's standard library. We intend to make `std_detect` more flexible and configurable in this regard to better serve the needs of `#[no_std]` targets. -# Features - -* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to -use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When -this is not the case, this feature allows other fallback methods to perform -run-time feature detection. When this feature is disabled, `std_detect` assumes -that [`getauxval`] is linked to the binary. If that is not the case the behavior -is undefined. - - Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets - because we can safely assume `getauxval` is linked to the binary. - * `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) - have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). - * `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) - use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197) - * `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md) - * `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html)) - have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49). - -* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature -detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant -methods fail. This feature requires `libstd` as a dependency, preventing the -crate from working on applications in which `std` is not available. - -[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html - # Platform support * All `x86`/`x86_64` targets are supported on all platforms by querying the diff --git a/library/std_detect/src/detect/mod.rs b/library/std_detect/src/detect/mod.rs index ae6fb2ab3727..c888dd34d9db 100644 --- a/library/std_detect/src/detect/mod.rs +++ b/library/std_detect/src/detect/mod.rs @@ -47,21 +47,21 @@ cfg_select! { #[path = "os/x86.rs"] mod os; } - all(any(target_os = "linux", target_os = "android"), feature = "libc") => { + any(target_os = "linux", target_os = "android") => { #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[path = "os/riscv.rs"] mod riscv; #[path = "os/linux/mod.rs"] mod os; } - all(target_os = "freebsd", feature = "libc") => { + target_os = "freebsd" => { #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] mod aarch64; #[path = "os/freebsd/mod.rs"] mod os; } - all(target_os = "openbsd", feature = "libc") => { + target_os = "openbsd" => { #[allow(dead_code)] // we don't use code that calls the mrs instruction. #[cfg(target_arch = "aarch64")] #[path = "os/aarch64.rs"] @@ -73,7 +73,7 @@ cfg_select! { #[path = "os/windows/aarch64.rs"] mod os; } - all(target_vendor = "apple", target_arch = "aarch64", feature = "libc") => { + all(target_vendor = "apple", target_arch = "aarch64") => { #[path = "os/darwin/aarch64.rs"] mod os; } diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs index a3562f2fd936..912d116d57b8 100644 --- a/library/std_detect/src/detect/os/linux/aarch64/tests.rs +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -1,6 +1,5 @@ use super::*; -#[cfg(feature = "std_detect_file_io")] mod auxv_from_file { use super::auxvec::auxv_from_file; use super::*; diff --git a/library/std_detect/src/detect/os/linux/auxvec.rs b/library/std_detect/src/detect/os/linux/auxvec.rs index 75e01bdc4499..c0bbc7d4efa8 100644 --- a/library/std_detect/src/detect/os/linux/auxvec.rs +++ b/library/std_detect/src/detect/os/linux/auxvec.rs @@ -44,20 +44,16 @@ pub(crate) struct AuxVec { /// /// There is no perfect way of reading the auxiliary vector. /// -/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use -/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation. -/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is -/// linked to the binary - if that is not the case the behavior is undefined. -/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will +/// - If [`getauxval`] is linked to the binary we use it, and otherwise it will /// try to read `/proc/self/auxv`. /// - If that fails, this function returns an error. /// /// Note that run-time feature detection is not invoked for features that can /// be detected at compile-time. /// -/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on -/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval` -/// is linked to the binary. +/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and +/// `*-android*` targets rather than `dlsym` it because we can safely assume +/// `getauxval` is linked to the binary. /// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html)) /// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html). /// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15)) @@ -71,6 +67,7 @@ pub(crate) struct AuxVec { /// /// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h /// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/ +/// [`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html pub(crate) fn auxv() -> Result { // Try to call a getauxval function. if let Ok(hwcap) = getauxval(AT_HWCAP) { @@ -115,16 +112,9 @@ pub(crate) fn auxv() -> Result { let _ = hwcap; } - #[cfg(feature = "std_detect_file_io")] - { - // If calling getauxval fails, try to read the auxiliary vector from - // its file: - auxv_from_file("/proc/self/auxv").map_err(|_| ()) - } - #[cfg(not(feature = "std_detect_file_io"))] - { - Err(()) - } + // If calling getauxval fails, try to read the auxiliary vector from + // its file: + auxv_from_file("/proc/self/auxv").map_err(|_| ()) } /// Tries to read the `key` from the auxiliary vector by calling the @@ -132,14 +122,16 @@ pub(crate) fn auxv() -> Result { fn getauxval(key: usize) -> Result { type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong; cfg_select! { - all( - feature = "std_detect_dlsym_getauxval", - not(all( + any( + all( target_os = "linux", any(target_env = "gnu", target_env = "musl", target_env = "ohos"), - )), - not(target_os = "android"), + ), + target_os = "android", ) => { + let ffi_getauxval: F = libc::getauxval; + } + _ => { let ffi_getauxval: F = unsafe { let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr()); if ptr.is_null() { @@ -148,23 +140,18 @@ fn getauxval(key: usize) -> Result { core::mem::transmute(ptr) }; } - _ => { - let ffi_getauxval: F = libc::getauxval; - } } Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize }) } /// Tries to read the auxiliary vector from the `file`. If this fails, this /// function returns `Err`. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file(file: &str) -> Result { let file = super::read_file(file)?; auxv_from_file_bytes(&file) } /// Read auxiliary vector from a slice of bytes. -#[cfg(feature = "std_detect_file_io")] pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result { // See . // @@ -181,7 +168,6 @@ pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result Result { // Targets with only AT_HWCAP: #[cfg(any( diff --git a/library/std_detect/src/detect/os/linux/auxvec/tests.rs b/library/std_detect/src/detect/os/linux/auxvec/tests.rs index 631a3e5e9ef1..88f0d6d49337 100644 --- a/library/std_detect/src/detect/os/linux/auxvec/tests.rs +++ b/library/std_detect/src/detect/os/linux/auxvec/tests.rs @@ -41,7 +41,6 @@ fn auxv_dump() { } } -#[cfg(feature = "std_detect_file_io")] cfg_select! { target_arch = "arm" => { // The tests below can be executed under qemu, where we do not have access to the test @@ -86,7 +85,6 @@ cfg_select! { } #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_dump_procfs() { if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") { println!("{:?}", auxvec); @@ -103,7 +101,6 @@ fn auxv_dump_procfs() { target_arch = "s390x", ))] #[test] -#[cfg(feature = "std_detect_file_io")] fn auxv_crate_procfs() { if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") { assert_eq!(auxv().unwrap(), procfs_auxv); diff --git a/library/std_detect/src/detect/os/linux/mod.rs b/library/std_detect/src/detect/os/linux/mod.rs index 5273c16c0893..aec94f963f5c 100644 --- a/library/std_detect/src/detect/os/linux/mod.rs +++ b/library/std_detect/src/detect/os/linux/mod.rs @@ -1,11 +1,9 @@ //! Run-time feature detection on Linux -//! -#[cfg(feature = "std_detect_file_io")] + use alloc::vec::Vec; mod auxvec; -#[cfg(feature = "std_detect_file_io")] fn read_file(orig_path: &str) -> Result, alloc::string::String> { use alloc::format; diff --git a/library/std_detect/src/lib.rs b/library/std_detect/src/lib.rs index 73e2f5dd9644..5e1d21bbfd17 100644 --- a/library/std_detect/src/lib.rs +++ b/library/std_detect/src/lib.rs @@ -27,8 +27,7 @@ extern crate std; // rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare> -#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))] -#[cfg(feature = "std_detect_file_io")] +#[allow(unused_extern_crates)] extern crate alloc; #[doc(hidden)] diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index eec8c461b6db..a18868082916 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,7 +20,7 @@ test = { path = "../test", public = true } # Forward features to the `std` crate as necessary [features] -default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] +default = ["panic-unwind"] backtrace = ["std/backtrace"] backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] @@ -32,7 +32,5 @@ system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] panic-unwind = ["std/panic-unwind"] profiler = ["dep:profiler_builtins"] -std_detect_file_io = ["std/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] windows_raw_dylib = ["std/windows_raw_dylib"] llvm_enzyme = ["std/llvm_enzyme"] From 3fed6e67ef0af1da28254cfc4d8078f0ba222c24 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 12:14:18 +0000 Subject: [PATCH 260/340] Remove a couple of outdated fields in std_detect Cargo.toml It is no longer a part of the stdarch repo and the rest is not necessary anymore due to no longer publishing to crates.io. --- library/std_detect/Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/std_detect/Cargo.toml b/library/std_detect/Cargo.toml index bcfdb3901957..a6785bb20555 100644 --- a/library/std_detect/Cargo.toml +++ b/library/std_detect/Cargo.toml @@ -7,11 +7,6 @@ authors = [ "Gonzalo Brito Gadeschi ", ] description = "`std::detect` - Rust's standard library run-time CPU feature detection." -homepage = "https://github.com/rust-lang/stdarch" -repository = "https://github.com/rust-lang/stdarch" -readme = "README.md" -keywords = ["std", "run-time", "feature", "detection"] -categories = ["hardware-support"] license = "MIT OR Apache-2.0" edition = "2024" From c873d163239a000bb0d3c29a15a24a98f6f6adf3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:02:42 +0000 Subject: [PATCH 261/340] Remove unnecessary module --- .../src/detect/os/linux/aarch64/tests.rs | 140 +++++++++--------- 1 file changed, 67 insertions(+), 73 deletions(-) diff --git a/library/std_detect/src/detect/os/linux/aarch64/tests.rs b/library/std_detect/src/detect/os/linux/aarch64/tests.rs index 912d116d57b8..4d7c9a419d38 100644 --- a/library/std_detect/src/detect/os/linux/aarch64/tests.rs +++ b/library/std_detect/src/detect/os/linux/aarch64/tests.rs @@ -1,76 +1,70 @@ +use super::auxvec::auxv_from_file; use super::*; - -mod auxv_from_file { - use super::auxvec::auxv_from_file; - use super::*; - // The baseline hwcaps used in the (artificial) auxv test files. - fn baseline_hwcaps() -> AtHwcap { - AtHwcap { - fp: true, - asimd: true, - aes: true, - pmull: true, - sha1: true, - sha2: true, - crc32: true, - atomics: true, - fphp: true, - asimdhp: true, - asimdrdm: true, - lrcpc: true, - dcpop: true, - asimddp: true, - ssbs: true, - ..AtHwcap::default() - } - } - - #[test] - fn linux_empty_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_no_hwcap2_aarch64() { - let file = concat!( - env!("CARGO_MANIFEST_DIR"), - "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv" - ); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!(AtHwcap::from(v), baseline_hwcaps()); - } - #[test] - fn linux_hwcap2_aarch64() { - let file = - concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); - println!("file: {file}"); - let v = auxv_from_file(file).unwrap(); - println!("HWCAP : 0x{:0x}", v.hwcap); - println!("HWCAP2: 0x{:0x}", v.hwcap2); - assert_eq!( - AtHwcap::from(v), - AtHwcap { - // Some other HWCAP bits. - paca: true, - pacg: true, - // HWCAP2-only bits. - dcpodp: true, - frint: true, - rng: true, - bti: true, - mte: true, - ..baseline_hwcaps() - } - ); +// The baseline hwcaps used in the (artificial) auxv test files. +fn baseline_hwcaps() -> AtHwcap { + AtHwcap { + fp: true, + asimd: true, + aes: true, + pmull: true, + sha1: true, + sha2: true, + crc32: true, + atomics: true, + fphp: true, + asimdhp: true, + asimdrdm: true, + lrcpc: true, + dcpop: true, + asimddp: true, + ssbs: true, + ..AtHwcap::default() } } + +#[test] +fn linux_empty_hwcap2_aarch64() { + let file = concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv" + ); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_no_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!(AtHwcap::from(v), baseline_hwcaps()); +} +#[test] +fn linux_hwcap2_aarch64() { + let file = + concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv"); + println!("file: {file}"); + let v = auxv_from_file(file).unwrap(); + println!("HWCAP : 0x{:0x}", v.hwcap); + println!("HWCAP2: 0x{:0x}", v.hwcap2); + assert_eq!( + AtHwcap::from(v), + AtHwcap { + // Some other HWCAP bits. + paca: true, + pacg: true, + // HWCAP2-only bits. + dcpodp: true, + frint: true, + rng: true, + bti: true, + mte: true, + ..baseline_hwcaps() + } + ); +} From 6b88c6b7c2a8322de6ff2211bd3f683e4fb1edbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:25:03 +0100 Subject: [PATCH 262/340] store defids instead of symbol names in the aliases list --- compiler/rustc_codegen_llvm/src/mono_item.rs | 7 ++++--- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 8 +++----- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 3 ++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 41cf92390b0d..3ce28612ddfc 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -10,7 +10,6 @@ use rustc_middle::mir::mono::Visibility; 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; @@ -92,17 +91,19 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { } impl CodegenCx<'_, '_> { - fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) { + fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(DefId, Linkage, Visibility)]) { let ty = self.get_type_of_global(aliasee); for (alias, linkage, visibility) in aliases { + let symbol_name = self.tcx.symbol_name(Instance::mono(self.tcx, *alias)); + tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}"); let lldecl = llvm::add_alias( self.llmod, ty, AddressSpace::ZERO, aliasee, - &CString::new(alias.as_str()).unwrap(), + &CString::new(symbol_name.name).unwrap(), ); llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility)); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 94dc3f44a68b..74f4662118b6 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -13,10 +13,10 @@ use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::mir::mono::Visibility; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self as ty, Instance, TyCtxt}; +use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::lint; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, sym}; use rustc_target::spec::Os; use crate::errors; @@ -291,8 +291,6 @@ fn process_builtin_attrs( ) .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. @@ -310,7 +308,7 @@ fn process_builtin_attrs( } codegen_fn_attrs.foreign_item_symbol_aliases.push(( - Symbol::intern(symbol_name.name), + extern_item, 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 9033d9c46d54..4f600af0cbfc 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr, RtsanSetting}; +use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; @@ -72,7 +73,7 @@ pub struct CodegenFnAttrs { /// 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)>, + pub foreign_item_symbol_aliases: Vec<(DefId, 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 From 9f3956f37863800fa6dd325607adf8e43bd66196 Mon Sep 17 00:00:00 2001 From: human9000 Date: Mon, 5 Jan 2026 18:14:12 +0500 Subject: [PATCH 263/340] MGCA: literals support --- compiler/rustc_ast_lowering/src/lib.rs | 10 ++++++++++ compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_hir/src/intravisit.rs | 1 + .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 15 +++++++++++++++ compiler/rustc_hir_pretty/src/lib.rs | 6 +++++- compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + src/librustdoc/clean/mod.rs | 6 +++++- src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- src/tools/clippy/clippy_utils/src/hir_utils.rs | 5 +++++ .../mgca/explicit_anon_consts_literals_hack.rs | 8 ++------ .../explicit_anon_consts_literals_hack.stderr | 8 -------- 12 files changed, 47 insertions(+), 17 deletions(-) delete mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a81d2297ef85..fd7c3360b05e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2536,6 +2536,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { overly_complex_const(self) } + ExprKind::Lit(literal) => { + let span = expr.span; + let literal = self.lower_lit(literal, span); + + ConstArg { + hir_id: self.lower_node_id(expr.id), + kind: hir::ConstArgKind::Literal(literal.node), + span, + } + } _ => overly_complex_const(self), } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index aacd6324bb03..666987860d50 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -518,6 +518,7 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// This variant is not always used to represent inference consts, sometimes /// [`GenericArg::Infer`] is used instead. Infer(Unambig), + Literal(LitKind), } #[derive(Clone, Copy, Debug, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 59db60fdc55c..e5e6fc7b1d8d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1104,6 +1104,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_) => V::Result::output(), // errors and spans are not important + ConstArgKind::Literal(..) => V::Result::output(), // FIXME(mcga) } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index aaa566760013..1dd9bff42575 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -22,6 +22,7 @@ pub mod generics; use std::assert_matches::assert_matches; use std::slice; +use rustc_ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -2391,6 +2392,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(()) => self.ct_infer(None, const_arg.span), hir::ConstArgKind::Error(e) => ty::Const::new_error(tcx, e), + hir::ConstArgKind::Literal(kind) if let FeedConstTy::WithTy(anon_const_type) = feed => { + self.lower_const_arg_literal(&kind, anon_const_type, const_arg.span) + } + hir::ConstArgKind::Literal(..) => { + let e = self.dcx().span_err(const_arg.span, "literal of unknown type"); + ty::Const::new_error(tcx, e) + } } } @@ -2773,6 +2781,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + #[instrument(skip(self), level = "debug")] + fn lower_const_arg_literal(&self, kind: &LitKind, ty: Ty<'tcx>, span: Span) -> Const<'tcx> { + let tcx = self.tcx(); + let input = LitToConstInput { lit: *kind, ty, neg: false }; + tcx.at(span).lit_to_const(input) + } + #[instrument(skip(self), level = "debug")] fn try_lower_anon_const_lit( &self, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2c160ccef2b6..37fa18c00887 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -21,7 +21,7 @@ use rustc_hir::{ GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use {rustc_ast as ast, rustc_hir as hir}; @@ -1157,6 +1157,10 @@ impl<'a> State<'a> { ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_) => self.word("/*ERROR*/"), ConstArgKind::Infer(..) => self.word("_"), + ConstArgKind::Literal(node) => { + let span = const_arg.span; + self.print_literal(&Spanned { span, node: *node }) + } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d0e8bc50c495..c85327dc3db1 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1444,6 +1444,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { | hir::ConstArgKind::TupleCall(..) | hir::ConstArgKind::Tup(..) | hir::ConstArgKind::Path(..) + | hir::ConstArgKind::Literal(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, }, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e05d3e416430..817eda4c52ec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -332,6 +332,9 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, + hir::ConstArgKind::Literal(..) => { + ConstantKind::Path { path: "/* LITERAL */".to_string().into() } + } } } @@ -1814,7 +1817,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::TupleCall(..) - | hir::ConstArgKind::Tup(..) => { + | hir::ConstArgKind::Tup(..) + | hir::ConstArgKind::Literal(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 455f76edc904..7a54ba7a8fe1 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -324,6 +324,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 46b87fd5df96..5f4b87590dc1 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => { + ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) | ConstArgKind::Literal(..) => { None }, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 57c896c97172..b4e483ea8072 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -689,6 +689,9 @@ impl HirEqInterExpr<'_, '_, '_> { .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) } + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { + kind_l == kind_r + }, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) @@ -697,6 +700,7 @@ impl HirEqInterExpr<'_, '_, '_> { | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) + | ConstArgKind::Literal(..) | ConstArgKind::Error(..), _, ) => false, @@ -1577,6 +1581,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, + ConstArgKind::Literal(lit) => lit.hash(&mut self.s) } } 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 index eb8f04b8b24b..8131a5b72343 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -1,8 +1,4 @@ -// We allow for literals to implicitly be anon consts still regardless -// of whether a const block is placed around them or not -// -// However, we don't allow so for const arguments in field init positions. -// This is just harder to implement so we did not do so. +//@ check-pass #![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] @@ -27,7 +23,7 @@ fn struct_expr() { fn takes_n() {} takes_n::<{ ADT { field: 1 } }>(); - //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_n::<{ ADT { field: const { 1 } } }>(); } diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr deleted file mode 100644 index 02647fd808cc..000000000000 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts_literals_hack.rs:29:30 - | -LL | takes_n::<{ ADT { field: 1 } }>(); - | ^ - -error: aborting due to 1 previous error - From 20a94d65e5e6ea1c187fe14e5ae79a7078dcd206 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 8 Jan 2026 23:55:57 +0800 Subject: [PATCH 264/340] Bump `diesel` to the most recent commit in `cargotest` `cargotest` can only detect the worst offenders (like tests failing, or hard compiler errors / ICEs), but regardless, bumping `diesel` to a way more recent version hopefully contributes slightly towards helping us not break `diesel` if at all possible. --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 4c57683806e6..5bbed35e2068 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -84,7 +84,7 @@ const TEST_REPOS: &[Test] = &[ Test { name: "diesel", repo: "https://github.com/diesel-rs/diesel", - sha: "91493fe47175076f330ce5fc518f0196c0476f56", + sha: "3db7c17c5b069656ed22750e84d6498c8ab5b81d", lock: None, packages: &[], // Test the embedded sqlite variant of diesel From 5356be04a8c8ee194e200c66b6c5eeb34c0543ca Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 8 Jan 2026 18:36:51 +0100 Subject: [PATCH 265/340] Bump nightly version -> 2026-01-08 --- 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 69bb6a2d6669..ecd36b157571 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-12-25 +nightly-2026-01-08 ``` diff --git a/rust-toolchain.toml b/rust-toolchain.toml index dbec79e111fb..0755e1d29c69 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-12-25" +channel = "nightly-2026-01-08" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" From 6ed95301410f592c97b4a7499fb22ea087148291 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 8 Jan 2026 18:21:54 +0100 Subject: [PATCH 266/340] tests/ui/borrowck/issue-92157.rs: Remove (bug not fixed) --- src/tools/tidy/src/issues.txt | 1 - tests/ui/borrowck/issue-92157.rs | 20 -------------------- tests/ui/borrowck/issue-92157.stderr | 12 ------------ 3 files changed, 33 deletions(-) delete mode 100644 tests/ui/borrowck/issue-92157.rs delete mode 100644 tests/ui/borrowck/issue-92157.stderr diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 45187a0b6450..b3e17b73237d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -379,7 +379,6 @@ ui/borrowck/issue-88434-minimal-example.rs ui/borrowck/issue-88434-removal-index-should-be-less.rs ui/borrowck/issue-91206.rs ui/borrowck/issue-92015.rs -ui/borrowck/issue-92157.rs ui/borrowck/issue-93078.rs ui/borrowck/issue-93093.rs ui/borrowck/issue-95079-missing-move-in-nested-closure.rs diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs deleted file mode 100644 index 3dbcb4ad8b7f..000000000000 --- a/tests/ui/borrowck/issue-92157.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ add-minicore -#![feature(no_core)] -#![feature(lang_items)] - -#![no_core] - -#[cfg(target_os = "linux")] -#[link(name = "c")] -extern "C" {} - -#[lang = "start"] -fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - //~^ ERROR lang item `start` function has wrong type [E0308] - 40+2 -} - -extern crate minicore; -use minicore::*; - -fn main() {} diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr deleted file mode 100644 index 248d700ab4b9..000000000000 --- a/tests/ui/borrowck/issue-92157.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0308]: lang item `start` function has wrong type - --> $DIR/issue-92157.rs:12:1 - | -LL | fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters - | - = note: expected signature `fn(fn() -> T, isize, *const *const u8, u8) -> _` - found signature `fn(fn() -> T, isize, *const *const u8) -> _` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. From 8e3d60447cfe78a7467a61a509032b45dca66c0b Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 1 Jan 2026 10:47:22 +0100 Subject: [PATCH 267/340] Finish transition from `semitransparent` to `semiopaque` for `rustc_macro_transparency` --- compiler/rustc_arena/src/lib.rs | 2 +- .../src/attributes/transparency.rs | 6 +++--- .../rustc_codegen_cranelift/example/mini_core.rs | 14 +++++++------- compiler/rustc_codegen_cranelift/src/global_asm.rs | 2 +- compiler/rustc_codegen_gcc/example/mini_core.rs | 8 ++++---- compiler/rustc_span/src/symbol.rs | 1 - library/core/src/macros/mod.rs | 4 ++-- library/core/src/panic.rs | 8 ++++---- library/core/src/pin.rs | 2 +- library/core/src/ptr/mod.rs | 4 ++-- library/core/src/task/ready.rs | 2 +- library/std/src/io/error.rs | 2 +- library/std/src/panic.rs | 2 +- library/std/src/sys/thread_local/native/mod.rs | 4 ++-- library/std/src/sys/thread_local/no_threads.rs | 4 ++-- library/std/src/sys/thread_local/os.rs | 4 ++-- library/std/src/thread/local.rs | 2 +- tests/rustdoc-html/macro/macro_pub_in_module.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 4 ++-- tests/ui/hygiene/duplicate_lifetimes.rs | 2 +- tests/ui/hygiene/generic_params.rs | 6 +++--- tests/ui/hygiene/rustc-macro-transparency.rs | 2 +- tests/ui/single-use-lifetime/issue-104440.rs | 6 +++--- 23 files changed, 46 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a0350dd6ff31..5e81ec28ee35 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -618,7 +618,7 @@ impl DroplessArena { /// - Types that are `!Copy` and `Drop`: these must be specified in the /// arguments. The `TypedArena` will be used for them. /// -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[derive(Default)] pub struct Arena<'tcx> { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 52aa42b1085a..7db84f8f2d95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -15,7 +15,7 @@ impl SingleAttributeParser for TransparencyParser { }); const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = - template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); + template!(NameValueStr: ["transparent", "semiopaque", "opaque"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(nv) = args.name_value() else { @@ -24,12 +24,12 @@ impl SingleAttributeParser for TransparencyParser { }; match nv.value_as_str() { Some(sym::transparent) => Some(Transparency::Transparent), - Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), + Some(sym::semiopaque) => Some(Transparency::SemiOpaque), Some(sym::opaque) => Some(Transparency::Opaque), Some(_) => { cx.expected_specific_argument_strings( nv.value_span, - &[sym::transparent, sym::semitransparent, sym::opaque], + &[sym::transparent, sym::semiopaque, sym::opaque], ); None } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index b522ea193716..301547cadaf7 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -744,43 +744,43 @@ unsafe extern "C" { pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro stringify($($t:tt)*) { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro file() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro line() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro cfg() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro asm() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro global_asm() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro naked_asm() { /* compiler built-in */ } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 8d8cdb14dbc6..97d6cecf6848 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -233,7 +233,7 @@ pub(crate) fn compile_global_asm( #![allow(internal_features)] #![no_core] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro global_asm() { /* compiler built-in */ } global_asm!(r###" "####, diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 64a5b431bd07..0aba44a88c5a 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -748,25 +748,25 @@ extern "C" { pub struct VaList<'a>(&'a mut VaListImpl); #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro stringify($($t:tt)*) { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro file() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro line() { /* compiler built-in */ } #[rustc_builtin_macro] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro cfg() { /* compiler built-in */ } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c7ff28ccaffb..1b868a933af8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2041,7 +2041,6 @@ symbols! { self_in_typedefs, self_struct_ctor, semiopaque, - semitransparent, sha2, sha3, sha512_sm_x86, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a12ee60277f0..338c5688bf10 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -168,7 +168,7 @@ macro_rules! assert_ne { /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(panic_internals)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro assert_matches { ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $left { @@ -401,7 +401,7 @@ macro_rules! debug_assert_ne { /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro debug_assert_matches($($arg:tt)*) { if $crate::cfg!(debug_assertions) { $crate::assert_matches::assert_matches!($($arg)*); diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 81520c3ecd1b..cf0750446680 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -20,7 +20,7 @@ use crate::any::Any; #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2015_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2015 { () => ( $crate::panicking::panic("explicit panic") @@ -47,7 +47,7 @@ pub macro panic_2015 { #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2021 { () => ( $crate::panicking::panic("explicit panic") @@ -67,7 +67,7 @@ pub macro panic_2021 { #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(panic_internals)] #[rustc_diagnostic_item = "unreachable_2015_macro"] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro unreachable_2015 { () => ( $crate::panicking::panic("internal error: entered unreachable code") @@ -85,7 +85,7 @@ pub macro unreachable_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(panic_internals)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro unreachable_2021 { () => ( $crate::panicking::panic("internal error: entered unreachable code") diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 74ecb5ee4946..4791f5612bfa 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -2027,7 +2027,7 @@ unsafe impl PinCoerceUnsized for *mut T {} /// /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin #[stable(feature = "pin_macro", since = "1.68.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] #[allow_internal_unstable(super_let)] #[rustc_diagnostic_item = "pin_macro"] // `super` gets removed by rustfmt diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 335c5c6ee944..ad74a8628c61 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2662,7 +2662,7 @@ impl fmt::Debug for F { /// same requirements apply to field projections, even inside `addr_of!`. (In particular, it makes /// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro addr_of($place:expr) { &raw const $place } @@ -2752,7 +2752,7 @@ pub macro addr_of($place:expr) { /// same requirements apply to field projections, even inside `addr_of_mut!`. (In particular, it /// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro addr_of_mut($place:expr) { &raw mut $place } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 495d72fd14be..468b3b4e528e 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -46,7 +46,7 @@ /// # } /// ``` #[stable(feature = "ready_macro", since = "1.64.0")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro ready($e:expr) { match $e { $crate::task::Poll::Ready(t) => t, diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 528eb185df08..898ed0f7469c 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -187,7 +187,7 @@ pub struct SimpleMessage { /// Err(FAIL) /// } /// ``` -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] #[unstable(feature = "io_const_error", issue = "133448")] #[allow_internal_unstable(hint_must_use, io_const_error_internals)] pub macro const_error($kind:expr, $message:expr $(,)?) { diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index beddc328582c..658026a8020f 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -212,7 +212,7 @@ impl fmt::Display for PanicHookInfo<'_> { #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro panic_2015 { () => ({ $crate::rt::begin_panic("explicit panic") diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index 38b373be56c9..4dad81685a94 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -47,7 +47,7 @@ pub use lazy::Storage as LazyStorage; )] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // NOTE: we cannot import `LocalKey`, `LazyStorage` or `EagerStorage` with a `use` because that // can shadow user provided type or type alias with a matching name. Please update the shadowing @@ -110,7 +110,7 @@ pub macro thread_local_inner { }}, } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 936d464be9f1..27a589a4a76a 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -9,7 +9,7 @@ use crate::ptr; #[allow_internal_unstable(thread_local_internals)] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ @@ -119,7 +119,7 @@ impl LazyStorage { // SAFETY: the target doesn't have threads. unsafe impl Sync for LazyStorage {} -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 07b93a2cbbc3..3f06c9bd1d77 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -12,7 +12,7 @@ use crate::ptr::{self, NonNull}; #[allow_internal_unstable(thread_local_internals)] #[allow_internal_unsafe] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_inner { // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user // provided type or type alias with a matching name. Please update the shadowing test in @@ -261,7 +261,7 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) }); } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub(crate) macro local_pointer { () => {}, ($vis:vis static $name:ident; $($rest:tt)*) => { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 06e4b252fc8f..1318d8dc2780 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -140,7 +140,7 @@ impl fmt::Debug for LocalKey { #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] #[unstable(feature = "thread_local_internals", issue = "none")] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] pub macro thread_local_process_attrs { // Parse `cfg_attr` to figure out whether it's a `rustc_align_static`. diff --git a/tests/rustdoc-html/macro/macro_pub_in_module.rs b/tests/rustdoc-html/macro/macro_pub_in_module.rs index 2dce73c2cf26..a4b39e20d126 100644 --- a/tests/rustdoc-html/macro/macro_pub_in_module.rs +++ b/tests/rustdoc-html/macro/macro_pub_in_module.rs @@ -33,7 +33,7 @@ pub mod inner { // Make sure the logic is not affected by re-exports. mod unrenamed { //@ !has krate/macro.unrenamed.html - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro unrenamed() {} } //@ has krate/inner/macro.unrenamed.html diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 7027328bc27b..fd6f34fb45e2 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -223,8 +223,8 @@ help: try changing it to one of the following valid forms of the attribute | LL | #[rustc_macro_transparency = "opaque"] | ++++++++++ -LL | #[rustc_macro_transparency = "semitransparent"] - | +++++++++++++++++++ +LL | #[rustc_macro_transparency = "semiopaque"] + | ++++++++++++++ LL | #[rustc_macro_transparency = "transparent"] | +++++++++++++++ diff --git a/tests/ui/hygiene/duplicate_lifetimes.rs b/tests/ui/hygiene/duplicate_lifetimes.rs index 8971fb62626c..4d128da7fdbf 100644 --- a/tests/ui/hygiene/duplicate_lifetimes.rs +++ b/tests/ui/hygiene/duplicate_lifetimes.rs @@ -3,7 +3,7 @@ #![feature(decl_macro, rustc_attrs)] -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] macro m($a:lifetime) { fn g<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter } diff --git a/tests/ui/hygiene/generic_params.rs b/tests/ui/hygiene/generic_params.rs index def9be3a1b64..bb0de15d9a0a 100644 --- a/tests/ui/hygiene/generic_params.rs +++ b/tests/ui/hygiene/generic_params.rs @@ -11,7 +11,7 @@ mod type_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($T:ident) { fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { (t1.clone(), t2.clone()) @@ -43,7 +43,7 @@ mod lifetime_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($a:lifetime) { fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { (t1, t2) @@ -75,7 +75,7 @@ mod const_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($C:ident) { fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { (t1, t2) diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs index 1a78a7543cfd..0c680abb4153 100644 --- a/tests/ui/hygiene/rustc-macro-transparency.rs +++ b/tests/ui/hygiene/rustc-macro-transparency.rs @@ -5,7 +5,7 @@ macro transparent() { struct Transparent; let transparent = 0; } -#[rustc_macro_transparency = "semitransparent"] +#[rustc_macro_transparency = "semiopaque"] macro semiopaque() { struct SemiOpaque; let semiopaque = 0; diff --git a/tests/ui/single-use-lifetime/issue-104440.rs b/tests/ui/single-use-lifetime/issue-104440.rs index 0795e95303a1..cecd17fb930b 100644 --- a/tests/ui/single-use-lifetime/issue-104440.rs +++ b/tests/ui/single-use-lifetime/issue-104440.rs @@ -8,7 +8,7 @@ mod type_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($T:ident) { fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { (t1.clone(), t2.clone()) @@ -40,7 +40,7 @@ mod lifetime_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($a:lifetime) { fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { (t1, t2) @@ -72,7 +72,7 @@ mod const_params { } } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] macro n($C:ident) { fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { (t1, t2) From 9e00663d73301dbc0482526f9019deaa14f348e1 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 1 Jan 2026 10:58:23 +0100 Subject: [PATCH 268/340] rust-analyzer: Also use `semiopaque` instead of `semitransparent` Like in rustc. --- .../crates/hir-def/src/expr_store/expander.rs | 2 +- .../crates/hir-def/src/expr_store/lower.rs | 2 +- .../crates/hir-def/src/resolver.rs | 2 +- .../crates/hir-expand/src/declarative.rs | 5 +++-- .../crates/hir-expand/src/hygiene.rs | 14 +++++++------- .../crates/hir-expand/src/inert_attr_macro.rs | 2 +- .../crates/hir-expand/src/mod_path.rs | 4 ++-- .../crates/hir-ty/src/tests/simple.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 2 +- .../crates/intern/src/symbol/symbols.rs | 1 - .../rust-analyzer/crates/span/src/hygiene.rs | 18 +++++++++--------- .../crates/test-utils/src/minicore.rs | 4 ++-- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index de5974fff1ad..d34ec9bbc182 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -61,7 +61,7 @@ impl Expander { pub(super) fn hygiene_for_range(&self, db: &dyn DefDatabase, range: TextRange) -> HygieneId { match self.span_map.as_ref() { hir_expand::span_map::SpanMapRef::ExpansionSpanMap(span_map) => { - HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semitransparent(db)) + HygieneId::new(span_map.span_at(range.start()).ctx.opaque_and_semiopaque(db)) } hir_expand::span_map::SpanMapRef::RealSpanMap(_) => HygieneId::ROOT, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index d3774ded39dc..4ae4271b92f5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2546,7 +2546,7 @@ impl<'db> ExprCollector<'db> { // Therefore, if we got to the rib of its declaration, give up its hygiene // and use its parent expansion. - hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db)); + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semiopaque(self.db)); hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| { let expansion = self.db.lookup_intern_macro_call(expansion.into()); (parent_ctx.parent(self.db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index f643ed31ad53..2ac0f90fb209 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -936,7 +936,7 @@ fn handle_macro_def_scope( // A macro is allowed to refer to variables from before its declaration. // Therefore, if we got to the rib of its declaration, give up its hygiene // and use its parent expansion. - *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db)); + *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semiopaque(db)); *hygiene_info = parent_ctx.outer_expn(db).map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion.into()); (parent_ctx.parent(db), expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index d2df9a1ff6b2..d10e122a5deb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -100,7 +100,8 @@ impl DeclarativeMacroExpander { { match &*value { "transparent" => ControlFlow::Break(Transparency::Transparent), - "semitransparent" => ControlFlow::Break(Transparency::SemiTransparent), + // "semitransparent" is for old rustc versions. + "semiopaque" | "semitransparent" => ControlFlow::Break(Transparency::SemiOpaque), "opaque" => ControlFlow::Break(Transparency::Opaque), _ => ControlFlow::Continue(()), } @@ -140,7 +141,7 @@ impl DeclarativeMacroExpander { )), }, transparency(ast::AnyHasAttrs::from(macro_rules)) - .unwrap_or(Transparency::SemiTransparent), + .unwrap_or(Transparency::SemiOpaque), ), ast::Macro::MacroDef(macro_def) => ( match macro_def.body() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index bd6f7e4f2b77..ce7650d07711 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -54,7 +54,7 @@ pub fn span_with_mixed_site_ctxt( expn_id: MacroCallId, edition: Edition, ) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent, edition) + span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiOpaque, edition) } fn span_with_ctxt_from_mark( @@ -82,7 +82,7 @@ pub(super) fn apply_mark( } let call_site_ctxt = db.lookup_intern_macro_call(call_id.into()).ctxt; - let mut call_site_ctxt = if transparency == Transparency::SemiTransparent { + let mut call_site_ctxt = if transparency == Transparency::SemiOpaque { call_site_ctxt.normalize_to_macros_2_0(db) } else { call_site_ctxt.normalize_to_macro_rules(db) @@ -117,16 +117,16 @@ fn apply_mark_internal( let call_id = Some(call_id); let mut opaque = ctxt.opaque(db); - let mut opaque_and_semitransparent = ctxt.opaque_and_semitransparent(db); + let mut opaque_and_semiopaque = ctxt.opaque_and_semiopaque(db); if transparency >= Transparency::Opaque { let parent = opaque; opaque = SyntaxContext::new(db, call_id, transparency, edition, parent, identity, identity); } - if transparency >= Transparency::SemiTransparent { - let parent = opaque_and_semitransparent; - opaque_and_semitransparent = + if transparency >= Transparency::SemiOpaque { + let parent = opaque_and_semiopaque; + opaque_and_semiopaque = SyntaxContext::new(db, call_id, transparency, edition, parent, |_| opaque, identity); } @@ -138,6 +138,6 @@ fn apply_mark_internal( edition, parent, |_| opaque, - |_| opaque_and_semitransparent, + |_| opaque_and_semiopaque, ) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 385c98ef8778..b49190237776 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -429,7 +429,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), rustc_attr!( rustc_macro_transparency, Normal, - template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing, + template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing, "used internally for testing macro hygiene", ), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 51e449fe5085..1712c28aa8ab 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -401,8 +401,8 @@ pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContext) -> O result_mark = Some(mark); iter.next(); } - // Then find the last semi-transparent mark from the end if it exists. - while let Some((mark, Transparency::SemiTransparent)) = iter.next() { + // Then find the last semi-opaque mark from the end if it exists. + while let Some((mark, Transparency::SemiOpaque)) = iter.next() { result_mark = Some(mark); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 6367521841ab..a9a5e96f75cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3708,7 +3708,7 @@ fn main() { } #[test] -fn macro_semitransparent_hygiene() { +fn macro_semiopaque_hygiene() { check_types( r#" macro_rules! m { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index bf123e13f94d..6ba7a42c1946 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -1808,5 +1808,5 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H }; let span_map = db.expansion_span_map(macro_file); let ctx = span_map.span_at(name.value.text_range().start()).ctx; - HygieneId::new(ctx.opaque_and_semitransparent(db)) + HygieneId::new(ctx.opaque_and_semiopaque(db)) } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index b6efc599f181..6181413a46db 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -442,7 +442,6 @@ define_symbols! { rustc_skip_array_during_method_dispatch, rustc_skip_during_method_dispatch, rustc_force_inline, - semitransparent, shl_assign, shl, shr_assign, diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index ea4f4c5efb42..fdfa94dfee4e 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -46,7 +46,7 @@ const _: () = { edition: Edition, parent: SyntaxContext, opaque: SyntaxContext, - opaque_and_semitransparent: SyntaxContext, + opaque_and_semiopaque: SyntaxContext, } impl PartialEq for SyntaxContextData { @@ -214,7 +214,7 @@ const _: () = { edition: T2, parent: T3, opaque: impl FnOnce(SyntaxContext) -> SyntaxContext, - opaque_and_semitransparent: impl FnOnce(SyntaxContext) -> SyntaxContext, + opaque_and_semiopaque: impl FnOnce(SyntaxContext) -> SyntaxContext, ) -> Self where Db: ?Sized + salsa::Database, @@ -241,7 +241,7 @@ const _: () = { edition: zalsa_::interned::Lookup::into_owned(data.2), parent: zalsa_::interned::Lookup::into_owned(data.3), opaque: opaque(zalsa_::FromId::from_id(id)), - opaque_and_semitransparent: opaque_and_semitransparent( + opaque_and_semiopaque: opaque_and_semiopaque( zalsa_::FromId::from_id(id), ), }, @@ -301,7 +301,7 @@ const _: () = { } } - /// This context, but with all transparent and semi-transparent expansions filtered away. + /// This context, but with all transparent and semi-opaque expansions filtered away. pub fn opaque(self, db: &'db Db) -> SyntaxContext where Db: ?Sized + zalsa_::Database, @@ -317,7 +317,7 @@ const _: () = { } /// This context, but with all transparent expansions filtered away. - pub fn opaque_and_semitransparent(self, db: &'db Db) -> SyntaxContext + pub fn opaque_and_semiopaque(self, db: &'db Db) -> SyntaxContext where Db: ?Sized + zalsa_::Database, { @@ -325,7 +325,7 @@ const _: () = { Some(id) => { let zalsa = db.zalsa(); let fields = SyntaxContext::ingredient(zalsa).data(zalsa, id); - fields.opaque_and_semitransparent + fields.opaque_and_semiopaque } None => self, } @@ -405,7 +405,7 @@ impl<'db> SyntaxContext { #[inline] pub fn normalize_to_macro_rules(self, db: &'db dyn salsa::Database) -> SyntaxContext { - self.opaque_and_semitransparent(db) + self.opaque_and_semiopaque(db) } pub fn is_opaque(self, db: &'db dyn salsa::Database) -> bool { @@ -476,13 +476,13 @@ pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. Transparent, - /// Identifier produced by a semi-transparent expansion may be resolved + /// Identifier produced by a semi-opaque expansion may be resolved /// either at call-site or at definition-site. /// If it's a local variable, label or `$crate` then it's resolved at def-site. /// Otherwise it's resolved at call-site. /// `macro_rules` macros behave like this, built-in macros currently behave like this too, /// but that's an implementation detail. - SemiTransparent, + SemiOpaque, /// Identifier produced by an opaque expansion is always resolved at definition-site. /// Def-site spans in procedural macros, identifiers from `macro` by default use this. Opaque, diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 01274a9835f4..c3429356d9e5 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -546,11 +546,11 @@ pub mod ptr { // endregion:non_null // region:addr_of - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro addr_of($place:expr) { &raw const $place } - #[rustc_macro_transparency = "semitransparent"] + #[rustc_macro_transparency = "semiopaque"] pub macro addr_of_mut($place:expr) { &raw mut $place } From 1eb605f6346055b91acbb23cdaa81284abe4aa70 Mon Sep 17 00:00:00 2001 From: Clara Engler Date: Thu, 8 Jan 2026 19:41:24 +0100 Subject: [PATCH 269/340] Query associated_item_def_ids when needed This commit moves a query to `associated_item_defs` from above an error condition caused independently of it to below it. It looks generally cleaner and might potentially save some runtime in case the error condition is met, rendering `items` to be left unused, yet still queried. --- compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 38ae7852ca99..984a812246eb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -79,13 +79,12 @@ impl<'tcx> InherentCollect<'tcx> { } if self.tcx.features().rustc_attrs() { - let items = self.tcx.associated_item_def_ids(impl_def_id); - if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } + let items = self.tcx.associated_item_def_ids(impl_def_id); for &impl_item in items { if !find_attr!( self.tcx.get_all_attrs(impl_item), From 68365697b3ab5e57c7a4e1cc4878e9a77ef002ae Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 19:33:24 +0100 Subject: [PATCH 270/340] A `return` in an iterator closure should not trigger `never_loop` The iterator never loops when the closure used in, e.g., `.any()`, panics, not when it diverges as a regular `return` lets the iterator continue. --- clippy_lints/src/loops/never_loop.rs | 4 ++-- tests/ui/never_loop_iterator_reduction.rs | 9 ++++++++- tests/ui/never_loop_iterator_reduction.stderr | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index a037af3433c3..e7b9b1cd3881 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -4,8 +4,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::{snippet, snippet_with_context}; -use clippy_utils::sym; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; +use clippy_utils::{contains_return, sym}; use rustc_errors::Applicability; use rustc_hir::{ Block, Closure, Destination, Expr, ExprKind, HirId, InlineAsm, InlineAsmOperand, Node, Pat, Stmt, StmtKind, @@ -82,7 +82,7 @@ pub(super) fn check_iterator_reduction<'tcx>( ) { let closure_body = cx.tcx.hir_body(closure.body).value; let body_ty = cx.typeck_results().expr_ty(closure_body); - if body_ty.is_never() { + if body_ty.is_never() && !contains_return(closure_body) { span_lint_and_then( cx, NEVER_LOOP, diff --git a/tests/ui/never_loop_iterator_reduction.rs b/tests/ui/never_loop_iterator_reduction.rs index 6b07b91db29a..27f1766b841d 100644 --- a/tests/ui/never_loop_iterator_reduction.rs +++ b/tests/ui/never_loop_iterator_reduction.rs @@ -1,8 +1,9 @@ //@no-rustfix #![warn(clippy::never_loop)] +#![expect(clippy::needless_return)] fn main() { - // diverging closure: should trigger + // diverging closure with no `return`: should trigger [0, 1].into_iter().for_each(|x| { //~^ never_loop @@ -14,4 +15,10 @@ fn main() { [0, 1].into_iter().for_each(|x| { let _ = x + 1; }); + + // `return` should NOT trigger even though it is diverging + [0, 1].into_iter().for_each(|x| { + println!("x = {x}"); + return; + }); } diff --git a/tests/ui/never_loop_iterator_reduction.stderr b/tests/ui/never_loop_iterator_reduction.stderr index b76ee283146c..92483c85432d 100644 --- a/tests/ui/never_loop_iterator_reduction.stderr +++ b/tests/ui/never_loop_iterator_reduction.stderr @@ -1,5 +1,5 @@ error: this iterator reduction never loops (closure always diverges) - --> tests/ui/never_loop_iterator_reduction.rs:6:5 + --> tests/ui/never_loop_iterator_reduction.rs:7:5 | LL | / [0, 1].into_iter().for_each(|x| { LL | | From a9749be514923d929a75f8d0a16013ac0e68c887 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 5 Jan 2026 10:47:04 -0800 Subject: [PATCH 271/340] mgca: Type-check fields of ADT constructor expr const args --- .../rustc_trait_selection/src/traits/wf.rs | 26 ++++++++++- .../mgca/adt_expr_arg_simple.rs | 2 +- .../mgca/adt_expr_fields_type_check.rs | 35 ++++++++++++--- .../mgca/adt_expr_fields_type_check.stderr | 45 +++++++++++++++++++ .../printing_valtrees_supports_non_values.rs | 4 +- ...inting_valtrees_supports_non_values.stderr | 10 ++--- 6 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 394095508393..58a35bb9ad8c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1051,7 +1051,31 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { | ty::ConstKind::Placeholder(..) => { // These variants are trivially WF, so nothing to do here. } - ty::ConstKind::Value(..) => { + ty::ConstKind::Value(val) => { + // FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased + if tcx.features().min_generic_const_args() + && let ty::Adt(adt_def, args) = val.ty.kind() + { + let adt_val = val.destructure_adt_const(); + let variant_def = adt_def.variant(adt_val.variant); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( + |(field_def, &field_val)| { + let field_ty = tcx.type_of(field_def.did).instantiate(tcx, args); + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + // FIXME: Enforce that values are structurally-matchable. } } diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs index ffb763da325c..16479ba3f64f 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs @@ -12,7 +12,7 @@ fn foo>() {} trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn bar() { diff --git a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs index eafc8382966b..496a424bac65 100644 --- a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs +++ b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs @@ -1,17 +1,38 @@ -//@ check-pass -// FIXME(mgca): This should error - #![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] #[derive(Eq, PartialEq, std::marker::ConstParamTy)] -struct Foo { field: T } +struct S1 { + f1: T, + f2: isize, +} -fn accepts>() {} +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct S2(T, isize); + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +enum En { + Var1(bool, T), + Var2 { field: i64 }, +} + +fn accepts_1>() {} +fn accepts_2>() {} +fn accepts_3>() {} fn bar() { - // `N` is not of type `u8` but we don't actually check this anywhere yet - accepts::<{ Foo:: { field: N }}>(); + accepts_1::<{ S1:: { f1: N, f2: N } }>(); + //~^ ERROR the constant `N` is not of type `u8` + //~| ERROR the constant `N` is not of type `isize` + accepts_2::<{ S2::(N, N) }>(); + //~^ ERROR the constant `N` is not of type `u8` + //~| ERROR the constant `N` is not of type `isize` + accepts_3::<{ En::Var1::(N, N) }>(); + //~^ ERROR the constant `N` is not of type `u8` + accepts_3::<{ En::Var2:: { field: N } }>(); + //~^ ERROR the constant `N` is not of type `i64` + accepts_3::<{ En::Var2:: { field: const { false } } }>(); + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr new file mode 100644 index 000000000000..81f7c5366b46 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr @@ -0,0 +1,45 @@ +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:24:19 + | +LL | accepts_1::<{ S1:: { f1: N, f2: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `isize` + --> $DIR/adt_expr_fields_type_check.rs:24:19 + | +LL | accepts_1::<{ S1:: { f1: N, f2: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:27:19 + | +LL | accepts_2::<{ S2::(N, N) }>(); + | ^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `isize` + --> $DIR/adt_expr_fields_type_check.rs:27:19 + | +LL | accepts_2::<{ S2::(N, N) }>(); + | ^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `N` is not of type `u8` + --> $DIR/adt_expr_fields_type_check.rs:30:19 + | +LL | accepts_3::<{ En::Var1::(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool` + +error: the constant `N` is not of type `i64` + --> $DIR/adt_expr_fields_type_check.rs:32:19 + | +LL | accepts_3::<{ En::Var2:: { field: N } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found `bool` + +error[E0308]: mismatched types + --> $DIR/adt_expr_fields_type_check.rs:34:51 + | +LL | accepts_3::<{ En::Var2:: { field: const { false } } }>(); + | ^^^^^ expected `i64`, found `bool` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs index 484d6f14a82a..819323d9cbec 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs @@ -9,7 +9,7 @@ struct Foo; trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn foo() {} @@ -27,7 +27,7 @@ fn baz() { fn main() {} fn test_ice_missing_bound() { - foo::<{Option::Some::{0: ::ASSOC}}>(); + foo::<{ Option::Some:: { 0: ::ASSOC } }>(); //~^ ERROR the trait bound `T: Trait` is not satisfied //~| ERROR the constant `Option::::Some(_)` is not of type `Foo` } diff --git a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr index bd2162468944..0184aebf157a 100644 --- a/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr +++ b/tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr @@ -25,8 +25,8 @@ LL | fn foo() {} error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/printing_valtrees_supports_non_values.rs:30:5 | -LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` +LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | help: consider restricting type parameter `T` with trait `Trait` | @@ -34,10 +34,10 @@ LL | fn test_ice_missing_bound() { | +++++++ error: the constant `Option::::Some(_)` is not of type `Foo` - --> $DIR/printing_valtrees_supports_non_values.rs:30:12 + --> $DIR/printing_valtrees_supports_non_values.rs:30:13 | -LL | foo::<{Option::Some::{0: ::ASSOC}}>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` +LL | foo::<{ Option::Some:: { 0: ::ASSOC } }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option` | note: required by a const generic parameter in `foo` --> $DIR/printing_valtrees_supports_non_values.rs:15:8 From 156b08184ebeadfc2968bfc454defaab44df20cd Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 8 Jan 2026 20:04:50 +0100 Subject: [PATCH 272/340] fix(single_range_in_vec_init): don't apply the suggestion automatically --- clippy_lints/src/single_range_in_vec_init.rs | 2 +- tests/ui/single_range_in_vec_init_unfixable.rs | 12 ++++++++++++ .../ui/single_range_in_vec_init_unfixable.stderr | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/ui/single_range_in_vec_init_unfixable.rs create mode 100644 tests/ui/single_range_in_vec_init_unfixable.stderr diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 92d1b112198f..e4906eb0c777 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -98,7 +98,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) { - let mut applicability = Applicability::MachineApplicable; + let mut applicability = Applicability::MaybeIncorrect; let (start_snippet, _) = snippet_with_context(cx, start.expr.span, span.ctxt(), "..", &mut applicability); let (end_snippet, _) = snippet_with_context(cx, end.expr.span, span.ctxt(), "..", &mut applicability); diff --git a/tests/ui/single_range_in_vec_init_unfixable.rs b/tests/ui/single_range_in_vec_init_unfixable.rs new file mode 100644 index 000000000000..33378b386f34 --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.rs @@ -0,0 +1,12 @@ +//@no-rustfix +#![warn(clippy::single_range_in_vec_init)] + +use std::ops::Range; + +fn issue16306(v: &[i32]) { + fn takes_range_slice(_: &[Range]) {} + + let len = v.len(); + takes_range_slice(&[0..len as i64]); + //~^ single_range_in_vec_init +} diff --git a/tests/ui/single_range_in_vec_init_unfixable.stderr b/tests/ui/single_range_in_vec_init_unfixable.stderr new file mode 100644 index 000000000000..b10af21ed21c --- /dev/null +++ b/tests/ui/single_range_in_vec_init_unfixable.stderr @@ -0,0 +1,16 @@ +error: an array of `Range` that is only one element + --> tests/ui/single_range_in_vec_init_unfixable.rs:10:24 + | +LL | takes_range_slice(&[0..len as i64]); + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::single-range-in-vec-init` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_range_in_vec_init)]` +help: if you wanted a `Vec` that contains the entire range, try + | +LL - takes_range_slice(&[0..len as i64]); +LL + takes_range_slice(&(0..len as i64).collect::>()); + | + +error: aborting due to 1 previous error + From 1c2cb16e8232843004ee277c1819d2d5e1c03e11 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 8 Jan 2026 11:09:07 -0800 Subject: [PATCH 273/340] mgca: Type-check fields of tuple expr const args --- .../rustc_middle/src/ty/consts/valtree.rs | 3 +- .../rustc_trait_selection/src/traits/wf.rs | 64 +++++++++++++------ .../mgca/adt_expr_arg_tuple_expr_fail.rs | 26 ++++++++ .../mgca/adt_expr_arg_tuple_expr_fail.stderr | 38 +++++++++++ .../mgca/adt_expr_arg_tuple_expr_simple.rs | 2 +- 5 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 6501ddeed6fa..5a5bf7d38ea4 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -191,8 +191,7 @@ impl<'tcx> Value<'tcx> { } } - /// Destructures array, ADT or tuple constants into the constants - /// of their fields. + /// Destructures ADT constants into the constants of their fields. pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> { let fields = self.to_branch(); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 58a35bb9ad8c..d383cb9d91dd 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1053,27 +1053,49 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::ConstKind::Value(val) => { // FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased - if tcx.features().min_generic_const_args() - && let ty::Adt(adt_def, args) = val.ty.kind() - { - let adt_val = val.destructure_adt_const(); - let variant_def = adt_def.variant(adt_val.variant); - let cause = self.cause(ObligationCauseCode::WellFormed(None)); - self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( - |(field_def, &field_val)| { - let field_ty = tcx.type_of(field_def.did).instantiate(tcx, args); - let predicate = ty::PredicateKind::Clause( - ty::ClauseKind::ConstArgHasType(field_val, field_ty), - ); - traits::Obligation::with_depth( - tcx, - cause.clone(), - self.recursion_depth, - self.param_env, - predicate, - ) - }, - )); + if tcx.features().min_generic_const_args() { + match val.ty.kind() { + ty::Adt(adt_def, args) => { + let adt_val = val.destructure_adt_const(); + let variant_def = adt_def.variant(adt_val.variant); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map( + |(field_def, &field_val)| { + let field_ty = + tcx.type_of(field_def.did).instantiate(tcx, args); + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + ty::Tuple(field_tys) => { + let field_vals = val.to_branch(); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.extend(field_tys.iter().zip(field_vals).map( + |(field_ty, &field_val)| { + let predicate = ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(field_val, field_ty), + ); + traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + predicate, + ) + }, + )); + } + _ => {} + } } // FIXME: Enforce that values are structurally-matchable. diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs new file mode 100644 index 000000000000..5f0d6c924bd1 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs @@ -0,0 +1,26 @@ +#![feature(min_generic_const_args, adt_const_params, unsized_const_params)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn takes_tuple() {} +fn takes_nested_tuple() {} + +fn generic_caller() { + takes_tuple::<{ (N, N2) }>(); + //~^ ERROR the constant `N` is not of type `u32` + takes_tuple::<{ (N, T::ASSOC) }>(); + //~^ ERROR the constant `N` is not of type `u32` + //~| ERROR the constant `::ASSOC` is not of type `u32` + + takes_nested_tuple::<{ (N, (N, N2)) }>(); + //~^ ERROR the constant `N` is not of type `u32` + takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + //~^ ERROR the constant `N` is not of type `u32` + //~| ERROR the constant `::ASSOC` is not of type `u32` +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr new file mode 100644 index 000000000000..9d80ebeaa680 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr @@ -0,0 +1,38 @@ +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:13:21 + | +LL | takes_tuple::<{ (N, N2) }>(); + | ^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21 + | +LL | takes_tuple::<{ (N, T::ASSOC) }>(); + | ^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `::ASSOC` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21 + | +LL | takes_tuple::<{ (N, T::ASSOC) }>(); + | ^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:19:28 + | +LL | takes_nested_tuple::<{ (N, (N, N2)) }>(); + | ^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `N` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28 + | +LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + | ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: the constant `::ASSOC` is not of type `u32` + --> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28 + | +LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>(); + | ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs index 60c4c6e952cf..3fde431e27e2 100644 --- a/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs +++ b/tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs @@ -5,7 +5,7 @@ trait Trait { #[type_const] - const ASSOC: usize; + const ASSOC: u32; } fn takes_tuple() {} From 742d276dc1d9f21c2196a057e2ac4bcaf70e3cc5 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 8 Jan 2026 20:24:49 +0100 Subject: [PATCH 274/340] make attrs actually use `Target::GenericParam` --- compiler/rustc_ast_lowering/src/lib.rs | 9 ++++--- .../src/attributes/stability.rs | 3 ++- .../rustc_attr_parsing/src/target_checking.rs | 24 +++++++++++++++++++ compiler/rustc_hir/src/lib.rs | 2 +- ...id-attributes-on-const-params-78957.stderr | 12 +++++----- tests/ui/force-inlining/invalid.stderr | 2 +- .../unused/unused_attributes-must_use.stderr | 2 +- tests/ui/pin-ergonomics/pin_v2-attr.rs | 4 ++-- tests/ui/pin-ergonomics/pin_v2-attr.stderr | 4 ++-- tests/ui/scalable-vectors/invalid.rs | 2 +- tests/ui/scalable-vectors/invalid.stderr | 2 +- 11 files changed, 47 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a81d2297ef85..6f8dab21e2b6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1986,8 +1986,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param); - hir::GenericParam { + let param_attrs = ¶m.attrs; + let param_span = param.span(); + let param = hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), name, @@ -1996,7 +1997,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), source, - } + }; + self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(¶m)); + param } fn lower_generic_param_kind( diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6d4f77ef1751..8d27e2e276dd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,6 +1,7 @@ use std::num::NonZero; use rustc_errors::ErrorGuaranteed; +use rustc_hir::target::GenericParamKind; use rustc_hir::{ DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, StableSince, Target, UnstableReason, VERSION_PLACEHOLDER, @@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::TyAlias), Allow(Target::Variant), Allow(Target::Field), - Allow(Target::Param), + Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }), Allow(Target::Static), Allow(Target::ForeignFn), Allow(Target::ForeignStatic), diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index e86ecb451fc2..88fa3e436292 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -310,5 +310,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = { Allow(Target::Crate), Allow(Target::Delegation { mac: false }), Allow(Target::Delegation { mac: true }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Const, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Const, + has_default: true, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Lifetime, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Lifetime, + has_default: true, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Type, + has_default: false, + }), + Allow(Target::GenericParam { + kind: rustc_hir::target::GenericParamKind::Type, + has_default: true, + }), ] }; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index fa46c0f085a2..9c2fec867785 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -32,7 +32,7 @@ pub mod lints; pub mod pat_util; mod stability; mod stable_hash_impls; -mod target; +pub mod target; pub mod weak_lang_items; #[cfg(test)] diff --git a/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr b/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr index f8010b4ea687..5fc7e7fef75d 100644 --- a/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr +++ b/tests/ui/const-generics/invalid-attributes-on-const-params-78957.stderr @@ -1,4 +1,4 @@ -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on const parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:6:16 | LL | pub struct Foo<#[inline] const N: usize>; @@ -6,7 +6,7 @@ LL | pub struct Foo<#[inline] const N: usize>; | = help: `#[inline]` can only be applied to functions -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on lifetime parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:14:17 | LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); @@ -14,7 +14,7 @@ LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); | = help: `#[inline]` can only be applied to functions -error: `#[inline]` attribute cannot be used on function params +error: `#[inline]` attribute cannot be used on type parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:22:17 | LL | pub struct Foo3<#[inline] T>(PhantomData); @@ -40,7 +40,7 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | pub struct Baz3<#[repr(C)] T>(PhantomData); | ^ - not a struct, enum, or union -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on const parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:8:16 | LL | pub struct Bar<#[cold] const N: usize>; @@ -54,7 +54,7 @@ note: the lint level is defined here LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on lifetime parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:16:17 | LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); @@ -63,7 +63,7 @@ LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[cold]` can only be applied to functions -error: `#[cold]` attribute cannot be used on function params +error: `#[cold]` attribute cannot be used on type parameters --> $DIR/invalid-attributes-on-const-params-78957.rs:24:17 | LL | pub struct Bar3<#[cold] T>(PhantomData); diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index df3b646b6cec..ce4f1d77ad2d 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -152,7 +152,7 @@ LL | #[rustc_force_inline] | = help: `#[rustc_force_inline]` can only be applied to functions -error: `#[rustc_force_inline]` attribute cannot be used on function params +error: `#[rustc_force_inline]` attribute cannot be used on type parameters --> $DIR/invalid.rs:72:10 | LL | enum Bar<#[rustc_force_inline] T> { diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 9b9a6a9c9f3d..3192c0994548 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -93,7 +93,7 @@ LL | #[must_use] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[must_use]` can be applied to data types, functions, traits, and unions -error: `#[must_use]` attribute cannot be used on function params +error: `#[must_use]` attribute cannot be used on type parameters --> $DIR/unused_attributes-must_use.rs:77:8 | LL | fn qux<#[must_use] T>(_: T) {} diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.rs b/tests/ui/pin-ergonomics/pin_v2-attr.rs index cfafe4b0b899..ba25d3587edd 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.rs +++ b/tests/ui/pin-ergonomics/pin_v2-attr.rs @@ -25,8 +25,8 @@ union Union { // disallowed enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { - //~^ ERROR `#[pin_v2]` attribute cannot be used on function params - //~| ERROR `#[pin_v2]` attribute cannot be used on function params + //~^ ERROR `#[pin_v2]` attribute cannot be used on type parameters + //~| ERROR `#[pin_v2]` attribute cannot be used on type parameters #[pin_v2] //~ ERROR `#[pin_v2]` attribute cannot be used on enum variants UnitVariant, TupleVariant(#[pin_v2] T), //~ ERROR `#[pin_v2]` attribute cannot be used on struct fields diff --git a/tests/ui/pin-ergonomics/pin_v2-attr.stderr b/tests/ui/pin-ergonomics/pin_v2-attr.stderr index 81e086f5a7ef..c297afa87a73 100644 --- a/tests/ui/pin-ergonomics/pin_v2-attr.stderr +++ b/tests/ui/pin-ergonomics/pin_v2-attr.stderr @@ -20,7 +20,7 @@ LL | #![pin_v2] | = help: `#[pin_v2]` can be applied to data types and unions -error: `#[pin_v2]` attribute cannot be used on function params +error: `#[pin_v2]` attribute cannot be used on type parameters --> $DIR/pin_v2-attr.rs:27:10 | LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { @@ -28,7 +28,7 @@ LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { | = help: `#[pin_v2]` can be applied to data types and unions -error: `#[pin_v2]` attribute cannot be used on function params +error: `#[pin_v2]` attribute cannot be used on type parameters --> $DIR/pin_v2-attr.rs:27:23 | LL | enum Foo<#[pin_v2] T, #[pin_v2] U = ()> { diff --git a/tests/ui/scalable-vectors/invalid.rs b/tests/ui/scalable-vectors/invalid.rs index beb3ad66b78b..90e9839c9e11 100644 --- a/tests/ui/scalable-vectors/invalid.rs +++ b/tests/ui/scalable-vectors/invalid.rs @@ -48,7 +48,7 @@ type Foo = u32; #[rustc_scalable_vector(4)] //~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enums enum Bar<#[rustc_scalable_vector(4)] T> { -//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on type parameters #[rustc_scalable_vector(4)] //~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enum variants Baz(std::marker::PhantomData), diff --git a/tests/ui/scalable-vectors/invalid.stderr b/tests/ui/scalable-vectors/invalid.stderr index 43be84a8b005..d73b5abf7030 100644 --- a/tests/ui/scalable-vectors/invalid.stderr +++ b/tests/ui/scalable-vectors/invalid.stderr @@ -92,7 +92,7 @@ LL | #[rustc_scalable_vector(4)] | = help: `#[rustc_scalable_vector]` can only be applied to structs -error: `#[rustc_scalable_vector]` attribute cannot be used on function params +error: `#[rustc_scalable_vector]` attribute cannot be used on type parameters --> $DIR/invalid.rs:50:10 | LL | enum Bar<#[rustc_scalable_vector(4)] T> { From dc505a51a4adea72efe1f1b08af6bf75b45ffdca Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 1 Jan 2026 19:24:41 +0100 Subject: [PATCH 275/340] Hash all spans relatively to their parent Co-authored-by: Camille Gillot --- .../rustc_middle/src/query/on_disk_cache.rs | 46 +++++++++++-------- compiler/rustc_query_system/src/ich/hcx.rs | 6 +-- .../rustc_span/src/caching_source_map_view.rs | 8 ++-- compiler/rustc_span/src/lib.rs | 37 ++++++++++----- 4 files changed, 58 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index c882d5d499bd..29cceb708850 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::hygiene::{ }; use rustc_span::source_map::Spanned; use rustc_span::{ - BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, Pos, - RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, + BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, RelativeBytePos, + SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol, }; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; @@ -652,7 +652,10 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { let dto = u32::decode(self); let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked(); - (enclosing.lo + BytePos::from_u32(dlo), enclosing.lo + BytePos::from_u32(dto)) + ( + BytePos(enclosing.lo.0.wrapping_add(dlo)), + BytePos(enclosing.lo.0.wrapping_add(dto)), + ) } TAG_FULL_SPAN => { let file_lo_index = SourceFileIndex::decode(self); @@ -894,30 +897,33 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { return TAG_PARTIAL_SPAN.encode(self); } - if let Some(parent) = span_data.parent { - let enclosing = self.tcx.source_span_untracked(parent).data_untracked(); - if enclosing.contains(span_data) { - TAG_RELATIVE_SPAN.encode(self); - (span_data.lo - enclosing.lo).to_u32().encode(self); - (span_data.hi - enclosing.lo).to_u32().encode(self); - return; - } + let parent = + span_data.parent.map(|parent| self.tcx.source_span_untracked(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span_data) + { + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo.0.wrapping_sub(parent.lo.0)).encode(self); + (span_data.hi.0.wrapping_sub(parent.lo.0)).encode(self); + return; } - let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo); - let partial_span = match &pos { - Some((file_lo, _, _)) => !file_lo.contains(span_data.hi), - None => true, + let Some((file_lo, line_lo, col_lo)) = + self.source_map.byte_pos_to_line_and_col(span_data.lo) + else { + return TAG_PARTIAL_SPAN.encode(self); }; - if partial_span { - return TAG_PARTIAL_SPAN.encode(self); + if let Some(parent) = parent + && file_lo.contains(parent.lo) + { + TAG_RELATIVE_SPAN.encode(self); + (span_data.lo.0.wrapping_sub(parent.lo.0)).encode(self); + (span_data.hi.0.wrapping_sub(parent.lo.0)).encode(self); + return; } - let (file_lo, line_lo, col_lo) = pos.unwrap(); - let len = span_data.hi - span_data.lo; - let source_file_index = self.source_file_index(file_lo); TAG_FULL_SPAN.encode(self); diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index be838f689e53..840f0b35266d 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -5,9 +5,7 @@ use rustc_hir::definitions::DefPathHash; use rustc_session::Session; use rustc_session::cstore::Untracked; use rustc_span::source_map::SourceMap; -use rustc_span::{ - BytePos, CachingSourceMapView, DUMMY_SP, Span, SpanData, StableSourceFileId, Symbol, -}; +use rustc_span::{BytePos, CachingSourceMapView, DUMMY_SP, SourceFile, Span, SpanData, Symbol}; use crate::ich; @@ -118,7 +116,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.source_map().span_data_to_lines_and_cols(span) } diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index 41cfaa3ee34e..11507a3d9e45 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -2,7 +2,7 @@ use std::ops::Range; use std::sync::Arc; use crate::source_map::SourceMap; -use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData, StableSourceFileId}; +use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData}; #[derive(Clone)] struct CacheEntry { @@ -114,7 +114,7 @@ impl<'sm> CachingSourceMapView<'sm> { pub fn span_data_to_lines_and_cols( &mut self, span_data: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)> { + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)> { self.time_stamp += 1; // Check if lo and hi are in the cached lines. @@ -136,7 +136,7 @@ impl<'sm> CachingSourceMapView<'sm> { let lo = &self.line_cache[lo_cache_idx as usize]; let hi = &self.line_cache[hi_cache_idx as usize]; return Some(( - lo.file.stable_id, + &lo.file, lo.line_number, span_data.lo - lo.line.start, hi.line_number, @@ -224,7 +224,7 @@ impl<'sm> CachingSourceMapView<'sm> { assert_eq!(lo.file_index, hi.file_index); Some(( - lo.file.stable_id, + &lo.file, lo.line_number, span_data.lo - lo.line.start, hi.line_number, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d3e0e303d0c6..1c430099835b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2831,7 +2831,7 @@ pub trait HashStableContext { fn span_data_to_lines_and_cols( &mut self, span: &SpanData, - ) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>; + ) -> Option<(&SourceFile, usize, BytePos, usize, BytePos)>; fn hashing_controls(&self) -> HashingControls; } @@ -2849,6 +2849,8 @@ where /// codepoint offsets. For the purpose of the hash that's sufficient. /// Also, hashing filenames is expensive so we avoid doing it twice when the /// span starts and ends in the same file, which is almost always the case. + /// + /// IMPORTANT: changes to this method should be reflected in implementations of `SpanEncoder`. fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; @@ -2867,15 +2869,17 @@ where return; } - if let Some(parent) = span.parent { - let def_span = ctx.def_span(parent).data_untracked(); - if def_span.contains(span) { - // This span is enclosed in a definition: only hash the relative position. - Hash::hash(&TAG_RELATIVE_SPAN, hasher); - (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher); - (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher); - return; - } + let parent = span.parent.map(|parent| ctx.def_span(parent).data_untracked()); + if let Some(parent) = parent + && parent.contains(span) + { + // This span is enclosed in a definition: only hash the relative position. + // This catches a subset of the cases from the `file.contains(parent.lo)`, + // But we can do this check cheaply without the expensive `span_data_to_lines_and_cols` query. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + (span.lo - parent.lo).to_u32().hash_stable(ctx, hasher); + (span.hi - parent.lo).to_u32().hash_stable(ctx, hasher); + return; } // If this is not an empty or invalid span, we want to hash the last @@ -2887,8 +2891,19 @@ where return; }; + if let Some(parent) = parent + && file.contains(parent.lo) + { + // This span is relative to another span in the same file, + // only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + Hash::hash(&(span.lo.0.wrapping_sub(parent.lo.0)), hasher); + Hash::hash(&(span.hi.0.wrapping_sub(parent.lo.0)), hasher); + return; + } + Hash::hash(&TAG_VALID_SPAN, hasher); - Hash::hash(&file, hasher); + Hash::hash(&file.stable_id, hasher); // Hash both the length and the end location (line/column) of a span. If we // hash only the length, for example, then two otherwise equal spans with From c502d7fce0e057eee00bfab471360ea751ef3762 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 16:53:50 +0100 Subject: [PATCH 276/340] Fix trait method anchor disappearing before user can click on it --- src/librustdoc/html/static/css/rustdoc.css | 4 +++- tests/rustdoc-gui/anchor-navigable.goml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b93e921dd5b7..b770a0e2a0e4 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1200,9 +1200,11 @@ nav.sub { display: initial; } .anchor { + --anchor-link-shift: 0.5em; display: none; position: absolute; - left: -0.5em; + left: calc(var(--anchor-link-shift) * -1); + padding-right: var(--anchor-link-shift); background: none !important; } .anchor.field { diff --git a/tests/rustdoc-gui/anchor-navigable.goml b/tests/rustdoc-gui/anchor-navigable.goml index 61d7c89d434f..db7fc3bbf182 100644 --- a/tests/rustdoc-gui/anchor-navigable.goml +++ b/tests/rustdoc-gui/anchor-navigable.goml @@ -7,5 +7,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" // We check that ".item-info" is bigger than its content. move-cursor-to: ".impl" -assert-property: (".impl > a.anchor", {"offsetWidth": "8"}) +assert-property: (".impl > a.anchor", {"offsetWidth": "16"}) assert-css: (".impl > a.anchor", {"left": "-8px"}) From bfb117ac744d6e1dd73b25eb46066bf3a36380c7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 17:09:07 +0100 Subject: [PATCH 277/340] Clean up `tests/rustdoc-gui/anchors.goml` test code --- tests/rustdoc-gui/anchors.goml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 0e8c834a7a77..371a4583c7b2 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -14,9 +14,9 @@ define-function: ( assert-css: ("#toggle-all-docs", {"color": |main_color|}) assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|}) assert-css: ( - ".rightside a.src", - {"color": |src_link_color|, "text-decoration": "none"}, - ALL, + ".rightside a.src", + {"color": |src_link_color|, "text-decoration": "none"}, + ALL, ) compare-elements-css: ( ".rightside a.src", @@ -31,25 +31,23 @@ define-function: ( move-cursor-to: ".main-heading a.src" assert-css: ( - ".main-heading a.src", - {"color": |src_link_color|, "text-decoration": "underline"}, + ".main-heading a.src", + {"color": |src_link_color|, "text-decoration": "underline"}, ) move-cursor-to: ".impl-items .rightside a.src" assert-css: ( - ".impl-items .rightside a.src", - {"color": |src_link_color|, "text-decoration": "none"}, + ".impl-items .rightside a.src", + {"color": |src_link_color|, "text-decoration": "none"}, ) move-cursor-to: ".impl-items a.rightside.src" assert-css: ( - ".impl-items a.rightside.src", - {"color": |src_link_color|, "text-decoration": "none"}, + ".impl-items a.rightside.src", + {"color": |src_link_color|, "text-decoration": "none"}, ) go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // Since we changed page, we need to set the theme again. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + call-function: ("switch-theme", {"theme": |theme|}) assert-css: ("#top-doc-prose-title", {"color": |title_color|}) From 16fbf6a27b5962b818f4c6ca14d391c6911ed6a8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jan 2026 17:41:42 +0100 Subject: [PATCH 278/340] Add check for trait impl method anchor --- tests/rustdoc-gui/anchors.goml | 16 ++++++++++++++++ tests/rustdoc-gui/src/staged_api/lib.rs | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 371a4583c7b2..eaec73f50e97 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -45,6 +45,22 @@ define-function: ( {"color": |src_link_color|, "text-decoration": "none"}, ) + // Now we ensure that the `§` anchor is "reachable" for users on trait methods. + // To ensure the anchor is not hovered, we move the cursor to another item. + move-cursor-to: "#search-button" + // By default, the anchor is not displayed. + wait-for-css: ("#method\.vroum .anchor", {"display": "none"}) + // Once we move the cursor to the method, the anchor should appear. + move-cursor-to: "#method\.vroum .code-header" + assert-css-false: ("#method\.vroum .anchor", {"display": "none"}) + // Now we move the cursor to the anchor to check there is no gap between the method and the + // anchor, making the anchor disappear and preventing users to click on it. + // To make it work, we need to first move it between the method and the anchor. + store-position: ("#method\.vroum .code-header", {"x": method_x, "y": method_y}) + move-cursor-to: (|method_x| - 2, |method_y|) + // Anchor should still be displayed. + assert-css-false: ("#method\.vroum .anchor", {"display": "none"}) + go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html" // Since we changed page, we need to set the theme again. call-function: ("switch-theme", {"theme": |theme|}) diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs index 9b5ad1c5ff32..7304d2f02ab1 100644 --- a/tests/rustdoc-gui/src/staged_api/lib.rs +++ b/tests/rustdoc-gui/src/staged_api/lib.rs @@ -4,6 +4,10 @@ #![stable(feature = "some_feature", since = "1.3.5")] #![doc(rust_logo)] +pub trait X { + fn vroum(); +} + #[stable(feature = "some_feature", since = "1.3.5")] pub struct Foo {} @@ -13,3 +17,7 @@ impl Foo { #[stable(feature = "some_other_feature", since = "1.3.6")] pub fn yo() {} } + +impl X for Foo { + fn vroum() {} +} From 945e7c78d2624e9647c8c608284f23e7a2fea32e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jan 2026 13:56:16 +0100 Subject: [PATCH 279/340] Use functions more in rustdoc GUI tests --- tests/rustdoc-gui/copy-code.goml | 11 +++-- tests/rustdoc-gui/font-serif-change.goml | 7 ++- tests/rustdoc-gui/notable-trait.goml | 11 ++--- tests/rustdoc-gui/search-filter.goml | 6 +-- ...setting-auto-hide-content-large-items.goml | 5 +- .../setting-auto-hide-item-methods-docs.goml | 5 +- ...tting-auto-hide-trait-implementations.goml | 5 +- .../setting-go-to-only-result.goml | 11 +++-- tests/rustdoc-gui/settings.goml | 14 ++---- tests/rustdoc-gui/sidebar-mobile.goml | 13 +---- .../sidebar-resize-close-popover.goml | 7 ++- tests/rustdoc-gui/sidebar-resize-setting.goml | 4 +- tests/rustdoc-gui/source-code-wrapping.goml | 7 ++- tests/rustdoc-gui/theme-change.goml | 10 +--- tests/rustdoc-gui/theme-defaults.goml | 7 ++- tests/rustdoc-gui/utils.goml | 49 +++++++++++-------- 16 files changed, 78 insertions(+), 94 deletions(-) diff --git a/tests/rustdoc-gui/copy-code.goml b/tests/rustdoc-gui/copy-code.goml index 14421ab746f5..eb003ef5e1ca 100644 --- a/tests/rustdoc-gui/copy-code.goml +++ b/tests/rustdoc-gui/copy-code.goml @@ -1,5 +1,6 @@ // Checks that the "copy code" button is not triggering JS error and its display // isn't broken. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" define-function: ( @@ -47,15 +48,15 @@ assert: |copy_height| > 0 && |copy_width| > 0 // First we ensure that the clipboard is empty. assert-clipboard: "" + // We make the line numbers appear. -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "block"}) -// We make the line numbers appear. +call-function: ("open-settings-menu", {}) click: "#line-numbers" wait-for-local-storage: {"rustdoc-line-numbers": "true" } + // We close the settings menu. -click: "rustdoc-toolbar .settings-menu" -wait-for-css-false: ("#settings", {"display": "block"}) +call-function: ("close-settings-menu", {}) + // We ensure that there are actually line numbers generated in the DOM. assert-text: (".example-wrap pre.rust code span[data-nosnippet]", "1") // We make the copy button appear. diff --git a/tests/rustdoc-gui/font-serif-change.goml b/tests/rustdoc-gui/font-serif-change.goml index 1e9f21c35416..32e95cdc6ee1 100644 --- a/tests/rustdoc-gui/font-serif-change.goml +++ b/tests/rustdoc-gui/font-serif-change.goml @@ -1,4 +1,5 @@ // Ensures that the font serif change is working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" // By default, it should be the serif fonts. @@ -8,8 +9,7 @@ assert-css: ("body", {"font-family": |serif_font|}) assert-css: ("p code", {"font-family": |serif_code_font|}) // We now switch to the sans serif font -click: "main .settings-menu" -wait-for: "#sans-serif-fonts" +call-function: ("open-settings-menu", {}) click: "#sans-serif-fonts" store-value: (font, '"Fira Sans", sans-serif') @@ -23,8 +23,7 @@ assert-css: ("body", {"font-family": |font|}) assert-css: ("p code", {"font-family": |code_font|}) // We switch back to the serif font -click: "main .settings-menu" -wait-for: "#sans-serif-fonts" +call-function: ("open-settings-menu", {}) click: "#sans-serif-fonts" assert-css: ("body", {"font-family": |serif_font|}) diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 6bd4661ac8f4..839988021fce 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -82,15 +82,15 @@ call-function: ("check-notable-tooltip-position", { "i_x": 528, }) +go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" +// This is needed to ensure that the text color is computed. +show-text: true + // Now check the colors. define-function: ( "check-colors", [theme, header_color, content_color, type_color, trait_color, link_color], block { - go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" - // This is needed to ensure that the text color is computed. - show-text: true - call-function: ("switch-theme", {"theme": |theme|}) assert-css: ( @@ -251,7 +251,6 @@ reload: assert-count: ("//*[@class='tooltip popover']", 0) click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" assert-count: ("//*[@class='tooltip popover']", 1) -click: "rustdoc-toolbar .settings-menu a" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-count: ("//*[@class='tooltip popover']", 0) assert-false: "#method\.create_an_iterator_from_read .tooltip:focus" diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index d92d522c119d..6bd7eaa92063 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -70,9 +70,7 @@ assert-css: ("#crate-search", { }) // We now check the dark theme. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" -click: "#theme-dark" +call-function: ("switch-theme", {"theme": "dark"}) wait-for-css: ("#crate-search", { "border": "1px solid #e0e0e0", "color": "#ddd", @@ -80,7 +78,7 @@ wait-for-css: ("#crate-search", { }) // And finally we check the ayu theme. -click: "#theme-ayu" +call-function: ("switch-theme", {"theme": "ayu"}) wait-for-css: ("#crate-search", { "border": "1px solid #5c6773", "color": "#c5c5c5", diff --git a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml index 342bd726694e..dbf80ae34912 100644 --- a/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml +++ b/tests/rustdoc-gui/setting-auto-hide-content-large-items.goml @@ -1,6 +1,8 @@ // This test ensures that the "Auto-hide item contents for large items" setting is working as // expected. +include: "utils.goml" + // We need to disable this check because `trait.impl/test_docs/trait.Iterator.js` doesn't exist. fail-on-request-error: false @@ -9,8 +11,7 @@ define-function: ( [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-large-items", {"checked": |setting_attribute_value|}) assert-attribute: (".item-decl .type-contents-toggle", {"open": |toggle_attribute_value|}) } diff --git a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml index 02d4ce8855fd..89c1a8b0e98e 100644 --- a/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml +++ b/tests/rustdoc-gui/setting-auto-hide-item-methods-docs.goml @@ -1,13 +1,14 @@ // This test ensures that the "Auto-hide item methods' documentation" setting is working as // expected. +include: "utils.goml" + define-function: ( "check-setting", [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-method-docs", {"checked": |setting_attribute_value|}) assert-attribute: (".toggle.method-toggle", {"open": |toggle_attribute_value|}) } diff --git a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml index 4af1e829b31c..81c26bfb7f3a 100644 --- a/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml +++ b/tests/rustdoc-gui/setting-auto-hide-trait-implementations.goml @@ -1,12 +1,13 @@ // Checks that the setting "auto hide trait implementations" is working as expected. +include: "utils.goml" + define-function: ( "check-setting", [storage_value, setting_attribute_value, toggle_attribute_value], block { assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#auto-hide-trait-implementations", {"checked": |setting_attribute_value|}) assert-attribute: ("#trait-implementations-list > details", {"open": |toggle_attribute_value|}, ALL) } diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml index 5a9c81e0b836..72c1e2bf59ca 100644 --- a/tests/rustdoc-gui/setting-go-to-only-result.goml +++ b/tests/rustdoc-gui/setting-go-to-only-result.goml @@ -1,12 +1,14 @@ -// Checks that the setting "Directly go to item in search if there is only one result " is working as expected. +// Checks that the setting "Directly go to item in search if there is only one result " is working +// as expected. + +include: "utils.goml" define-function: ( "check-setting", [storage_value, setting_attribute_value], block { assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|} - click: "rustdoc-toolbar .settings-menu" - wait-for: "#settings" + call-function: ("open-settings-menu", {}) assert-property: ("#go-to-only-result", {"checked": |setting_attribute_value|}) } ) @@ -25,8 +27,7 @@ wait-for: "#search" assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS) // Now we change its value. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) click: "#go-to-only-result" assert-local-storage: {"rustdoc-go-to-only-result": "true"} diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 7a163103b5ab..85994be468d3 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -1,20 +1,18 @@ // This test ensures that the settings menu display is working as expected and that // the settings page is also rendered as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" show-text: true // needed when we check for colors below. // First, we check that the settings page doesn't exist. assert-false: "#settings" -// We now click on the settings button. -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) // Store the line margin to compare with the settings.html later. store-css: (".setting-line", {"margin": setting_line_margin}) // Let's close it by clicking on the same button. -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "none"}) +call-function: ("close-settings-menu", {}) // Let's check that pressing "ESCAPE" is closing it. click: "rustdoc-toolbar .settings-menu" @@ -28,8 +26,7 @@ write: "test" // To be SURE that the search will be run. press-key: 'Enter' wait-for: "#alternative-display #search" -click: "rustdoc-toolbar .settings-menu" -wait-for-css: ("#settings", {"display": "block"}) +call-function: ("open-settings-menu", {}) // Ensure that the search is still displayed. wait-for: "#alternative-display #search" assert: "#main-content.hidden" @@ -41,8 +38,7 @@ set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false" // We reload the page so the local storage settings are being used. reload: -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) // We check that the "Use system theme" is disabled. assert-property: ("#theme-system-preference", {"checked": "false"}) diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 1fa5521baac9..3183650b555a 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -65,8 +65,7 @@ define-function: ( "check-colors", [theme, color, background], block { - call-function: ("switch-theme-mobile", {"theme": |theme|}) - reload: + call-function: ("switch-theme", {"theme": |theme|}) // Open the sidebar menu. click: ".sidebar-menu-toggle" @@ -86,13 +85,3 @@ call-function: ("check-colors", { "color": "#c5c5c5", "background": "#14191f", }) -call-function: ("check-colors", { - "theme": "dark", - "color": "#ddd", - "background": "#505050", -}) -call-function: ("check-colors", { - "theme": "light", - "color": "black", - "background": "#F5F5F5", -}) diff --git a/tests/rustdoc-gui/sidebar-resize-close-popover.goml b/tests/rustdoc-gui/sidebar-resize-close-popover.goml index d3fea9b0f400..ac8f7e9c65fa 100644 --- a/tests/rustdoc-gui/sidebar-resize-close-popover.goml +++ b/tests/rustdoc-gui/sidebar-resize-close-popover.goml @@ -1,9 +1,9 @@ // Checks sidebar resizing close the Settings popover +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "199"}) show-text: true -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) // normal resizing drag-and-drop: ((205, 100), (185, 100)) @@ -12,8 +12,7 @@ assert-css: ("#settings", {"display": "none"}) // Now same thing, but for source code go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) assert-property: (".sidebar", {"clientWidth": "49"}) drag-and-drop: ((52, 100), (185, 100)) diff --git a/tests/rustdoc-gui/sidebar-resize-setting.goml b/tests/rustdoc-gui/sidebar-resize-setting.goml index a4572c670f81..132f5f387b29 100644 --- a/tests/rustdoc-gui/sidebar-resize-setting.goml +++ b/tests/rustdoc-gui/sidebar-resize-setting.goml @@ -1,11 +1,11 @@ // Checks sidebar resizing stays synced with the setting +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-property: (".sidebar", {"clientWidth": "199"}) show-text: true // Verify that the "hide" option is unchecked -click: "rustdoc-toolbar .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) assert-css: ("#settings", {"display": "block"}) assert-property: ("#hide-sidebar", {"checked": "false"}) press-key: "Escape" diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml index c1fc2835c89a..6dc56672da80 100644 --- a/tests/rustdoc-gui/source-code-wrapping.goml +++ b/tests/rustdoc-gui/source-code-wrapping.goml @@ -1,4 +1,5 @@ // Checks that the interactions with the source code pages are working as expected. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" show-text: true set-window-size: (1000, 1000) @@ -13,8 +14,7 @@ define-function: ( ) store-size: (".rust code", {"width": width, "height": height}) -click: "main .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) call-function: ("click-code-wrapping", {"expected": "true"}) wait-for-size-false: (".rust code", {"width": |width|, "height": |height|}) store-size: (".rust code", {"width": new_width, "height": new_height}) @@ -28,8 +28,7 @@ assert-size: (".rust code", {"width": |width|, "height": |height|}) // Now let's check in docs code examples. go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html" -click: "main .settings-menu" -wait-for: "#settings" +call-function: ("open-settings-menu", {}) store-property: (".example-wrap .rust code", {"scrollWidth": rust_width, "scrollHeight": rust_height}) store-property: (".example-wrap .language-text code", {"scrollWidth": txt_width, "scrollHeight": txt_height}) diff --git a/tests/rustdoc-gui/theme-change.goml b/tests/rustdoc-gui/theme-change.goml index 3860596e3433..14b32baac57e 100644 --- a/tests/rustdoc-gui/theme-change.goml +++ b/tests/rustdoc-gui/theme-change.goml @@ -7,8 +7,7 @@ store-value: (background_light, "white") store-value: (background_dark, "#353535") store-value: (background_ayu, "#0f1419") -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-ayu" +call-function: ("open-settings-menu", {}) click: "#theme-ayu" // should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": |background_ayu| }) @@ -22,10 +21,6 @@ click: "#theme-dark" wait-for-css: ("body", { "background-color": |background_dark| }) assert-local-storage: { "rustdoc-theme": "dark" } -set-local-storage: { - "rustdoc-preferred-light-theme": "light", - "rustdoc-preferred-dark-theme": "light", -} go-to: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" @@ -75,8 +70,7 @@ store-value: (background_dark, "#353535") store-value: (background_ayu, "#0f1419") store-value: (background_custom_theme, "red") -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-ayu" +call-function: ("open-settings-menu", {}) click: "#theme-ayu" // should be the ayu theme so let's check the color. wait-for-css: ("body", { "background-color": |background_ayu| }) diff --git a/tests/rustdoc-gui/theme-defaults.goml b/tests/rustdoc-gui/theme-defaults.goml index 12c17166e874..b7ba64a4adaa 100644 --- a/tests/rustdoc-gui/theme-defaults.goml +++ b/tests/rustdoc-gui/theme-defaults.goml @@ -1,7 +1,7 @@ // Ensure that the theme picker always starts with the actual defaults. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-system-preference" +call-function: ("open-settings-menu", {}) assert: "#theme-system-preference:checked" assert: "#preferred-light-theme-light:checked" assert: "#preferred-dark-theme-dark:checked" @@ -16,8 +16,7 @@ set-local-storage: { "rustdoc-theme": "ayu" } go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -click: "rustdoc-toolbar .settings-menu" -wait-for: "#theme-system-preference" +call-function: ("open-settings-menu", {}) assert: "#theme-system-preference:checked" assert: "#preferred-light-theme-light:checked" assert-false: "#preferred-dark-theme-dark:checked" diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index a40f9fc6fdd7..c0625ead2f1a 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -1,11 +1,35 @@ // This file contains code to be re-used by other tests. +define-function: ( + "click-settings-button", + [], + block { + store-count: ("rustdoc-topbar", __topbar_count) + store-value: (__topbar_display, "none") + // The `rustdoc-topbar` element is created with JS when the window size is below a given + // size, however if the window size gets bigger again, the element isn't deleted, just + // hidden, so we need to check for both that it exists and is visible. + if: (|__topbar_count| != 0, block { + store-css: ("rustdoc-topbar", {"display": __topbar_display}) + }) + + // Open the settings menu. + if: (|__topbar_display| != "none", block { + // In mobile mode, this is instead the "topbar" the settings button is located into. + click: "rustdoc-topbar .settings-menu" + }) + else: block { + // We're not in mobile mode so clicking on the "normal" sidebar. + click: "rustdoc-toolbar .settings-menu" + } + } +) + define-function: ( "open-settings-menu", [], block { - // Open the settings menu. - click: "rustdoc-toolbar .settings-menu" + call-function: ("click-settings-button", {}) // Wait for the popover to appear... wait-for-css: ("#settings", {"display": "block"}) } @@ -15,7 +39,8 @@ define-function: ( "close-settings-menu", [], block { - click: "rustdoc-toolbar .settings-menu" + call-function: ("click-settings-button", {}) + // Wait for the popover to disappear... wait-for-css-false: ("#settings", {"display": "block"}) } ) @@ -34,24 +59,6 @@ define-function: ( }, ) -// FIXME: To be removed once `browser-ui-test` has conditions. -define-function: ( - "switch-theme-mobile", - [theme], - block { - // Open the settings menu. - click: "rustdoc-topbar .settings-menu" - // Wait for the popover to appear... - wait-for-css: ("#settings", {"display": "block"}) - // Change the setting. - click: "#theme-"+ |theme| - click: "rustdoc-topbar .settings-menu" - wait-for-css-false: ("#settings", {"display": "block"}) - // Ensure that the local storage was correctly updated. - assert-local-storage: {"rustdoc-theme": |theme|} - }, -) - define-function: ( "perform-search", [query], From 5466c6b25506f16fb6f030481d0e02a180c54a07 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 8 Jan 2026 14:48:56 -0600 Subject: [PATCH 280/340] Move feature(multiple_supertrait_upcastable) to the actual feature gates section (from the internal feature gates section) and give it a tracking issue. --- compiler/rustc_feature/src/unstable.rs | 4 ++-- .../feature-gate-multiple_supertrait_upcastable.stderr | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 387a01967ae5..8959bc586af7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -233,8 +233,6 @@ declare_features! ( (internal, link_cfg, "1.14.0", None), /// Allows using `?Trait` trait bounds in more contexts. (internal, more_maybe_bounds, "1.82.0", None), - /// Allows the `multiple_supertrait_upcastable` lint. - (unstable, multiple_supertrait_upcastable, "1.69.0", None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! (internal, negative_bounds, "1.71.0", None), /// Set the maximum pattern complexity allowed (not limited by default). @@ -569,6 +567,8 @@ declare_features! ( (unstable, more_qualified_paths, "1.54.0", Some(86935)), /// The `movrs` target feature on x86. (unstable, movrs_target_feature, "1.88.0", Some(137976)), + /// Allows the `multiple_supertrait_upcastable` lint. + (unstable, multiple_supertrait_upcastable, "1.69.0", Some(150833)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), /// Allows `mut ref` and `mut ref mut` identifier patterns. diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr index 0c7e68a599cd..0fd987e40289 100644 --- a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr +++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr @@ -5,6 +5,7 @@ LL | #![deny(multiple_supertrait_upcastable)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `multiple_supertrait_upcastable` lint is unstable + = note: see issue #150833 for more information = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: `#[warn(unknown_lints)]` on by default @@ -16,6 +17,7 @@ LL | #![warn(multiple_supertrait_upcastable)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the `multiple_supertrait_upcastable` lint is unstable + = note: see issue #150833 for more information = help: add `#![feature(multiple_supertrait_upcastable)]` 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 3c136cc9e18c0f0bb848ff0a147aeb8ffa4ce20d Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 00:40:31 +0000 Subject: [PATCH 281/340] Fix broken documentation links to SipHash The documentation of `SipHasher` previously linked to a page about SipHash on https://131002.net, a domain registered to Jean-Philippe Aumasson, one of the co-authors of the original SipHash paper (alongside Daniel J Bernstein). That domain now redirects to another of Mr Aumasson's domains, https://www.aumasson.jp, but which does not host a similar page dedicated to SipHash. Instead, his site links to a GitHub repository containing a C implementation together with links to the original research paper. Mr Bernstein's own site, https://cr.yp.to, only hosts a copy of the research paper. Therefore the GitHub repository appears to be the most official and complete reference to which we can link. --- library/core/src/hash/sip.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 780e522c48eb..4f2e8a22d180 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -10,7 +10,7 @@ use crate::{cmp, ptr}; /// This is currently the default hashing function used by standard library /// (e.g., `collections::HashMap` uses it by default). /// -/// See: +/// See: #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -21,7 +21,7 @@ pub struct SipHasher13 { /// An implementation of SipHash 2-4. /// -/// See: +/// See: #[unstable(feature = "hashmap_internals", issue = "none")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -31,7 +31,7 @@ struct SipHasher24 { /// An implementation of SipHash 2-4. /// -/// See: +/// See: /// /// SipHash is a general-purpose hashing function: it runs at a good /// speed (competitive with Spooky and City) and permits strong _keyed_ From 5932078c79d7171d23dcf892e129ef5154410b62 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 22 Dec 2025 04:31:14 -0800 Subject: [PATCH 282/340] =?UTF-8?q?Stop=20emitting=20UbChecks=20on=20every?= =?UTF-8?q?=20Vec=E2=86=92Slice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spotted this in PR148766's test changes. It doesn't seem like this ubcheck would catch anything useful; let's see if skipping it helps perf. --- library/alloc/src/vec/mod.rs | 12 +- library/core/src/slice/cmp.rs | 13 +- ...ng_operand.test.GVN.64bit.panic-abort.diff | 22 +- ..._conditions.JumpThreading.panic-abort.diff | 458 +++++------------- ...conditions.JumpThreading.panic-unwind.diff | 458 +++++------------- ...ace.PreCodegen.after.64bit.panic-abort.mir | 26 +- ...d_constant.main.GVN.64bit.panic-abort.diff | 72 ++- ..._to_slice.PreCodegen.after.panic-abort.mir | 33 +- ...to_slice.PreCodegen.after.panic-unwind.mir | 33 +- 9 files changed, 310 insertions(+), 817 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d3da7efe4ddf..379e964f0a0c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1747,7 +1747,11 @@ impl Vec { // * We only construct `&mut` references to `self.buf` through `&mut self` methods; borrow- // check ensures that it is not possible to mutably alias `self.buf` within the // returned lifetime. - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + unsafe { + // normally this would use `slice::from_raw_parts`, but it's + // instantiated often enough that avoiding the UB check is worth it + &*core::intrinsics::aggregate_raw_ptr::<*const [T], _, _>(self.as_ptr(), self.len) + } } /// Extracts a mutable slice of the entire vector. @@ -1779,7 +1783,11 @@ impl Vec { // * We only construct references to `self.buf` through `&self` and `&mut self` methods; // borrow-check ensures that it is not possible to construct a reference to `self.buf` // within the returned lifetime. - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + unsafe { + // normally this would use `slice::from_raw_parts_mut`, but it's + // instantiated often enough that avoiding the UB check is worth it + &mut *core::intrinsics::aggregate_raw_ptr::<*mut [T], _, _>(self.as_mut_ptr(), self.len) + } } /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index fd1ca23fb79c..dfc0b565195e 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -13,13 +13,14 @@ impl const PartialEq<[U]> for [T] where T: [const] PartialEq, { + // It's not worth trying to inline the loops underneath here *in MIR*, + // and preventing it encourages more useful inlining upstream, + // such as in `::eq`. + // The codegen backend can still inline it later if needed. + #[rustc_no_mir_inline] fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) } - - fn ne(&self, other: &[U]) -> bool { - SlicePartialEq::not_equal(self, other) - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -99,10 +100,6 @@ impl PartialOrd for [T] { #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } } // Generic slice equality diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 408ff60712e1..1b75a2bcba8b 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -26,12 +26,12 @@ scope 4 { debug _x => _8; } - scope 18 (inlined foo) { + scope 19 (inlined foo) { let mut _27: *const [()]; } } - scope 16 (inlined slice_from_raw_parts::<()>) { - scope 17 (inlined std::ptr::from_raw_parts::<[()], ()>) { + scope 17 (inlined slice_from_raw_parts::<()>) { + scope 18 (inlined std::ptr::from_raw_parts::<[()], ()>) { } } } @@ -49,19 +49,21 @@ scope 7 { let _21: std::ptr::NonNull<[u8]>; scope 8 { - scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { - scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { - scope 13 (inlined NonNull::<[u8]>::cast::) { + scope 12 (inlined NonNull::<[u8]>::as_mut_ptr) { + scope 13 (inlined NonNull::<[u8]>::as_non_null_ptr) { + scope 14 (inlined NonNull::<[u8]>::cast::) { let mut _25: *mut [u8]; - scope 14 (inlined NonNull::<[u8]>::as_ptr) { + scope 15 (inlined NonNull::<[u8]>::as_ptr) { } } } - scope 15 (inlined NonNull::::as_ptr) { + scope 16 (inlined NonNull::::as_ptr) { } } } scope 10 (inlined ::allocate) { + scope 11 (inlined std::alloc::Global::alloc_impl) { + } } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { @@ -192,8 +194,8 @@ + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; StorageDead(_24); StorageLive(_19); -- _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; -+ _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; +- _19 = std::alloc::Global::alloc_impl_runtime(copy _18, const false) -> [return: bb7, unwind unreachable]; ++ _19 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; } bb7: { 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 8777ac426d78..0875d437296d 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 @@ -48,8 +48,8 @@ let _29: &str; scope 7 (inlined String::as_str) { let _30: &[u8]; - let mut _31: &std::vec::Vec; scope 8 (inlined Vec::::as_slice) { + let _31: *const [u8]; let mut _32: *const u8; let mut _33: usize; scope 9 (inlined Vec::::as_ptr) { @@ -71,161 +71,83 @@ } } } - scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _35: (); - let mut _36: *mut (); - let _37: *const [u8]; - scope 19 (inlined ub_checks::check_language_ub) { - scope 20 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 21 (inlined std::mem::size_of::) { - } - scope 22 (inlined std::mem::align_of::) { - } - scope 23 (inlined slice_from_raw_parts::) { - scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 25 (inlined from_utf8_unchecked) { + scope 18 (inlined from_utf8_unchecked) { } } - scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 19 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 20 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 21 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 29 (inlined core::str::traits::::eq) { - let mut _38: &&[u8]; - let _39: &[u8]; - let mut _40: &&[u8]; - let _41: &[u8]; - scope 30 (inlined core::str::::as_bytes) { + scope 22 (inlined core::str::traits::::eq) { + let mut _35: &&[u8]; + let _36: &[u8]; + let mut _37: &&[u8]; + let _38: &[u8]; + scope 23 (inlined core::str::::as_bytes) { } - scope 31 (inlined core::str::::as_bytes) { + scope 24 (inlined core::str::::as_bytes) { } - scope 32 (inlined std::cmp::impls::::eq) { - scope 33 (inlined core::slice::cmp::::eq) { - scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _42: bool; - let mut _43: usize; - let mut _44: usize; - let _45: usize; - let mut _46: i32; - let mut _47: *const u8; - let mut _48: *const u8; - scope 35 { - scope 37 (inlined core::slice::::as_ptr) { - let mut _50: *const [u8]; - } - scope 38 (inlined core::slice::::as_ptr) { - let mut _51: *const [u8]; - } - } - scope 36 (inlined std::mem::size_of_val::<[u8]>) { - let mut _49: *const [u8]; - } - } - } + scope 25 (inlined std::cmp::impls::::eq) { } } } } - scope 39 (inlined std::cmp::impls:: for &String>::eq) { - let mut _52: &std::string::String; - let mut _53: &str; - scope 40 (inlined >::eq) { - scope 41 (inlined #[track_caller] >::index) { - let _54: &str; - scope 42 (inlined String::as_str) { - let _55: &[u8]; - let mut _56: &std::vec::Vec; - scope 43 (inlined Vec::::as_slice) { - let mut _57: *const u8; - let mut _58: usize; - scope 44 (inlined Vec::::as_ptr) { - scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _59: std::ptr::NonNull; - scope 48 (inlined Unique::::cast::) { - scope 49 (inlined NonNull::::cast::) { - scope 50 (inlined NonNull::::as_ptr) { + scope 26 (inlined std::cmp::impls:: for &String>::eq) { + let mut _39: &std::string::String; + let mut _40: &str; + scope 27 (inlined >::eq) { + scope 28 (inlined #[track_caller] >::index) { + let _41: &str; + scope 29 (inlined String::as_str) { + let _42: &[u8]; + scope 30 (inlined Vec::::as_slice) { + let _43: *const [u8]; + let mut _44: *const u8; + let mut _45: usize; + scope 31 (inlined Vec::::as_ptr) { + scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _46: std::ptr::NonNull; + scope 35 (inlined Unique::::cast::) { + scope 36 (inlined NonNull::::cast::) { + scope 37 (inlined NonNull::::as_ptr) { } } } - scope 51 (inlined Unique::::as_non_null_ptr) { + scope 38 (inlined Unique::::as_non_null_ptr) { } } - scope 52 (inlined NonNull::::as_ptr) { + scope 39 (inlined NonNull::::as_ptr) { } } } } - scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _60: (); - let mut _61: *mut (); - let _62: *const [u8]; - scope 54 (inlined ub_checks::check_language_ub) { - scope 55 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 56 (inlined std::mem::size_of::) { - } - scope 57 (inlined std::mem::align_of::) { - } - scope 58 (inlined slice_from_raw_parts::) { - scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 60 (inlined from_utf8_unchecked) { + scope 40 (inlined from_utf8_unchecked) { } } - scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 64 (inlined core::str::traits::::eq) { - let mut _63: &&[u8]; - let _64: &[u8]; - let mut _65: &&[u8]; - let _66: &[u8]; - scope 65 (inlined core::str::::as_bytes) { + scope 44 (inlined core::str::traits::::eq) { + let mut _47: &&[u8]; + let _48: &[u8]; + let mut _49: &&[u8]; + let _50: &[u8]; + scope 45 (inlined core::str::::as_bytes) { } - scope 66 (inlined core::str::::as_bytes) { + scope 46 (inlined core::str::::as_bytes) { } - scope 67 (inlined std::cmp::impls::::eq) { - scope 68 (inlined core::slice::cmp::::eq) { - scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _67: bool; - let mut _68: usize; - let mut _69: usize; - let _70: usize; - let mut _71: i32; - let mut _72: *const u8; - let mut _73: *const u8; - scope 70 { - scope 72 (inlined core::slice::::as_ptr) { - let mut _75: *const [u8]; - } - scope 73 (inlined core::slice::::as_ptr) { - let mut _76: *const [u8]; - } - } - scope 71 (inlined std::mem::size_of_val::<[u8]>) { - let mut _74: *const [u8]; - } - } - } + scope 47 (inlined std::cmp::impls::::eq) { } } } @@ -253,7 +175,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb18; -+ goto -> bb37; ++ goto -> bb23; } bb4: { @@ -272,15 +194,27 @@ _27 = copy (*_8); _28 = copy (*_10); StorageLive(_29); - StorageLive(_35); StorageLive(_30); - StorageLive(_34); + StorageLive(_31); StorageLive(_32); + StorageLive(_34); _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _32 = copy _34 as *const u8 (Transmute); + StorageDead(_34); StorageLive(_33); _33 = copy (((*_27).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb21, otherwise: bb19]; + _31 = *const [u8] from (copy _32, move _33); + StorageDead(_33); + StorageDead(_32); + _30 = &(*_31); + StorageDead(_31); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_36); + StorageLive(_38); + _36 = copy _29 as &[u8] (Transmute); + _38 = copy _28 as &[u8] (Transmute); + _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb19, unwind unreachable]; } bb5: { @@ -311,27 +245,39 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_52); - StorageLive(_53); - _52 = copy (*_15); - _53 = copy (*_17); - StorageLive(_54); - StorageLive(_60); - StorageLive(_55); - StorageLive(_59); - StorageLive(_57); - _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _57 = copy _59 as *const u8 (Transmute); - StorageLive(_58); - _58 = copy (((*_52).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb29, otherwise: bb27]; + StorageLive(_39); + StorageLive(_40); + _39 = copy (*_15); + _40 = copy (*_17); + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_46); + _46 = copy ((((((*_39).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _44 = copy _46 as *const u8 (Transmute); + StorageDead(_46); + StorageLive(_45); + _45 = copy (((*_39).0: std::vec::Vec).1: usize); + _43 = *const [u8] from (copy _44, move _45); + StorageDead(_45); + StorageDead(_44); + _42 = &(*_43); + StorageDead(_43); + _41 = copy _42 as &str (Transmute); + StorageDead(_42); + StorageLive(_48); + StorageLive(_50); + _48 = copy _41 as &[u8] (Transmute); + _50 = copy _40 as &[u8] (Transmute); + _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb20, unwind unreachable]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb18; -+ goto -> bb39; ++ goto -> bb21; } bb8: { @@ -354,14 +300,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb18; -+ goto -> bb37; ++ goto -> bb23; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb18; -+ goto -> bb39; ++ goto -> bb21; } bb11: { @@ -406,223 +352,39 @@ } bb19: { - StorageLive(_36); - _36 = copy _34 as *mut () (Transmute); - _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb20, unwind unreachable]; - } - - bb20: { + StorageDead(_38); StorageDead(_36); - goto -> bb21; - } - - bb21: { - StorageLive(_37); - _37 = *const [u8] from (copy _32, copy _33); - _30 = &(*_37); - StorageDead(_37); - StorageDead(_33); - StorageDead(_32); - StorageDead(_34); - _29 = copy _30 as &str (Transmute); - StorageDead(_30); - StorageLive(_39); - StorageLive(_41); - _39 = copy _29 as &[u8] (Transmute); - _41 = copy _28 as &[u8] (Transmute); - StorageLive(_45); - StorageLive(_50); - StorageLive(_51); - StorageLive(_42); - StorageLive(_43); - _43 = PtrMetadata(copy _39); - StorageLive(_44); - _44 = PtrMetadata(copy _41); - _42 = Ne(move _43, move _44); - switchInt(move _42) -> [0: bb24, otherwise: bb23]; - } - - bb22: { - StorageDead(_51); - StorageDead(_50); - StorageDead(_45); - StorageDead(_41); - StorageDead(_39); - StorageDead(_35); StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb23: { - StorageDead(_44); - StorageDead(_43); - _7 = const false; - StorageDead(_42); -- goto -> bb22; -+ goto -> bb35; - } - - bb24: { - StorageDead(_44); - StorageDead(_43); - StorageDead(_42); - StorageLive(_49); - _49 = &raw const (*_39); - _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb26, unwind unreachable]; - } - - bb25: { + bb20: { + StorageDead(_50); StorageDead(_48); - StorageDead(_47); - _7 = Eq(move _46, const 0_i32); - StorageDead(_46); - goto -> bb22; - } - - bb26: { - StorageDead(_49); - StorageLive(_46); - StorageLive(_47); - _50 = &raw const (*_39); - _47 = copy _50 as *const u8 (PtrToPtr); - StorageLive(_48); - _51 = &raw const (*_41); - _48 = copy _51 as *const u8 (PtrToPtr); - _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb25, unwind unreachable]; - } - - bb27: { - StorageLive(_61); - _61 = copy _59 as *mut () (Transmute); - _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb28, unwind unreachable]; - } - - bb28: { - StorageDead(_61); - goto -> bb29; - } - - bb29: { - StorageLive(_62); - _62 = *const [u8] from (copy _57, copy _58); - _55 = &(*_62); - StorageDead(_62); - StorageDead(_58); - StorageDead(_57); - StorageDead(_59); - _54 = copy _55 as &str (Transmute); - StorageDead(_55); - StorageLive(_64); - StorageLive(_66); - _64 = copy _54 as &[u8] (Transmute); - _66 = copy _53 as &[u8] (Transmute); - StorageLive(_70); - StorageLive(_75); - StorageLive(_76); - StorageLive(_67); - StorageLive(_68); - _68 = PtrMetadata(copy _64); - StorageLive(_69); - _69 = PtrMetadata(copy _66); - _67 = Ne(move _68, move _69); - switchInt(move _67) -> [0: bb32, otherwise: bb31]; - } - - bb30: { - StorageDead(_76); - StorageDead(_75); - StorageDead(_70); - StorageDead(_66); - StorageDead(_64); - StorageDead(_60); - StorageDead(_54); - StorageDead(_53); - StorageDead(_52); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); switchInt(move _14) -> [0: bb9, otherwise: bb8]; - } - - bb31: { - StorageDead(_69); - StorageDead(_68); - _14 = const false; - StorageDead(_67); -- goto -> bb30; -+ goto -> bb36; - } - - bb32: { - StorageDead(_69); - StorageDead(_68); - StorageDead(_67); - StorageLive(_74); - _74 = &raw const (*_64); - _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb34, unwind unreachable]; - } - - bb33: { - StorageDead(_73); - StorageDead(_72); - _14 = Eq(move _71, const 0_i32); - StorageDead(_71); - goto -> bb30; - } - - bb34: { - StorageDead(_74); - StorageLive(_71); - StorageLive(_72); - _75 = &raw const (*_64); - _72 = copy _75 as *const u8 (PtrToPtr); - StorageLive(_73); - _76 = &raw const (*_66); - _73 = copy _76 as *const u8 (PtrToPtr); - _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb33, unwind unreachable]; + } + -+ bb35: { -+ StorageDead(_51); -+ StorageDead(_50); -+ StorageDead(_45); -+ StorageDead(_41); -+ StorageDead(_39); -+ StorageDead(_35); -+ StorageDead(_29); -+ StorageDead(_28); -+ StorageDead(_27); -+ goto -> bb6; -+ } -+ -+ bb36: { -+ StorageDead(_76); -+ StorageDead(_75); -+ StorageDead(_70); -+ StorageDead(_66); -+ StorageDead(_64); -+ StorageDead(_60); -+ StorageDead(_54); -+ StorageDead(_53); -+ StorageDead(_52); -+ goto -> bb9; -+ } -+ -+ bb37: { ++ bb21: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb38, otherwise: bb15]; ++ switchInt(move _24) -> [1: bb22, otherwise: bb15]; + } + -+ bb38: { -+ goto -> bb17; -+ } -+ -+ bb39: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb40, otherwise: bb15]; -+ } -+ -+ bb40: { ++ bb22: { + goto -> bb15; ++ } ++ ++ bb23: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb24, otherwise: bb15]; ++ } ++ ++ bb24: { ++ 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 822d33c89391..b942eeed37e0 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 @@ -48,8 +48,8 @@ let _29: &str; scope 7 (inlined String::as_str) { let _30: &[u8]; - let mut _31: &std::vec::Vec; scope 8 (inlined Vec::::as_slice) { + let _31: *const [u8]; let mut _32: *const u8; let mut _33: usize; scope 9 (inlined Vec::::as_ptr) { @@ -71,161 +71,83 @@ } } } - scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _35: (); - let mut _36: *mut (); - let _37: *const [u8]; - scope 19 (inlined ub_checks::check_language_ub) { - scope 20 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 21 (inlined std::mem::size_of::) { - } - scope 22 (inlined std::mem::align_of::) { - } - scope 23 (inlined slice_from_raw_parts::) { - scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 25 (inlined from_utf8_unchecked) { + scope 18 (inlined from_utf8_unchecked) { } } - scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 19 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 20 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 21 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 29 (inlined core::str::traits::::eq) { - let mut _38: &&[u8]; - let _39: &[u8]; - let mut _40: &&[u8]; - let _41: &[u8]; - scope 30 (inlined core::str::::as_bytes) { + scope 22 (inlined core::str::traits::::eq) { + let mut _35: &&[u8]; + let _36: &[u8]; + let mut _37: &&[u8]; + let _38: &[u8]; + scope 23 (inlined core::str::::as_bytes) { } - scope 31 (inlined core::str::::as_bytes) { + scope 24 (inlined core::str::::as_bytes) { } - scope 32 (inlined std::cmp::impls::::eq) { - scope 33 (inlined core::slice::cmp::::eq) { - scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _42: bool; - let mut _43: usize; - let mut _44: usize; - let _45: usize; - let mut _46: i32; - let mut _47: *const u8; - let mut _48: *const u8; - scope 35 { - scope 37 (inlined core::slice::::as_ptr) { - let mut _50: *const [u8]; - } - scope 38 (inlined core::slice::::as_ptr) { - let mut _51: *const [u8]; - } - } - scope 36 (inlined std::mem::size_of_val::<[u8]>) { - let mut _49: *const [u8]; - } - } - } + scope 25 (inlined std::cmp::impls::::eq) { } } } } - scope 39 (inlined std::cmp::impls:: for &String>::eq) { - let mut _52: &std::string::String; - let mut _53: &str; - scope 40 (inlined >::eq) { - scope 41 (inlined #[track_caller] >::index) { - let _54: &str; - scope 42 (inlined String::as_str) { - let _55: &[u8]; - let mut _56: &std::vec::Vec; - scope 43 (inlined Vec::::as_slice) { - let mut _57: *const u8; - let mut _58: usize; - scope 44 (inlined Vec::::as_ptr) { - scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { - let mut _59: std::ptr::NonNull; - scope 48 (inlined Unique::::cast::) { - scope 49 (inlined NonNull::::cast::) { - scope 50 (inlined NonNull::::as_ptr) { + scope 26 (inlined std::cmp::impls:: for &String>::eq) { + let mut _39: &std::string::String; + let mut _40: &str; + scope 27 (inlined >::eq) { + scope 28 (inlined #[track_caller] >::index) { + let _41: &str; + scope 29 (inlined String::as_str) { + let _42: &[u8]; + scope 30 (inlined Vec::::as_slice) { + let _43: *const [u8]; + let mut _44: *const u8; + let mut _45: usize; + scope 31 (inlined Vec::::as_ptr) { + scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _46: std::ptr::NonNull; + scope 35 (inlined Unique::::cast::) { + scope 36 (inlined NonNull::::cast::) { + scope 37 (inlined NonNull::::as_ptr) { } } } - scope 51 (inlined Unique::::as_non_null_ptr) { + scope 38 (inlined Unique::::as_non_null_ptr) { } } - scope 52 (inlined NonNull::::as_ptr) { + scope 39 (inlined NonNull::::as_ptr) { } } } } - scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - let _60: (); - let mut _61: *mut (); - let _62: *const [u8]; - scope 54 (inlined ub_checks::check_language_ub) { - scope 55 (inlined ub_checks::check_language_ub::runtime) { - } - } - scope 56 (inlined std::mem::size_of::) { - } - scope 57 (inlined std::mem::align_of::) { - } - scope 58 (inlined slice_from_raw_parts::) { - scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - } - } - } } - scope 60 (inlined from_utf8_unchecked) { + scope 40 (inlined from_utf8_unchecked) { } } - scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 64 (inlined core::str::traits::::eq) { - let mut _63: &&[u8]; - let _64: &[u8]; - let mut _65: &&[u8]; - let _66: &[u8]; - scope 65 (inlined core::str::::as_bytes) { + scope 44 (inlined core::str::traits::::eq) { + let mut _47: &&[u8]; + let _48: &[u8]; + let mut _49: &&[u8]; + let _50: &[u8]; + scope 45 (inlined core::str::::as_bytes) { } - scope 66 (inlined core::str::::as_bytes) { + scope 46 (inlined core::str::::as_bytes) { } - scope 67 (inlined std::cmp::impls::::eq) { - scope 68 (inlined core::slice::cmp::::eq) { - scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { - let mut _67: bool; - let mut _68: usize; - let mut _69: usize; - let _70: usize; - let mut _71: i32; - let mut _72: *const u8; - let mut _73: *const u8; - scope 70 { - scope 72 (inlined core::slice::::as_ptr) { - let mut _75: *const [u8]; - } - scope 73 (inlined core::slice::::as_ptr) { - let mut _76: *const [u8]; - } - } - scope 71 (inlined std::mem::size_of_val::<[u8]>) { - let mut _74: *const [u8]; - } - } - } + scope 47 (inlined std::cmp::impls::::eq) { } } } @@ -253,7 +175,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb19; -+ goto -> bb41; ++ goto -> bb27; } bb4: { @@ -272,15 +194,27 @@ _27 = copy (*_8); _28 = copy (*_10); StorageLive(_29); - StorageLive(_35); StorageLive(_30); - StorageLive(_34); + StorageLive(_31); StorageLive(_32); + StorageLive(_34); _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _32 = copy _34 as *const u8 (Transmute); + StorageDead(_34); StorageLive(_33); _33 = copy (((*_27).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb25, otherwise: bb23]; + _31 = *const [u8] from (copy _32, move _33); + StorageDead(_33); + StorageDead(_32); + _30 = &(*_31); + StorageDead(_31); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_36); + StorageLive(_38); + _36 = copy _29 as &[u8] (Transmute); + _38 = copy _28 as &[u8] (Transmute); + _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb23, unwind: bb22]; } bb5: { @@ -311,27 +245,39 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_52); - StorageLive(_53); - _52 = copy (*_15); - _53 = copy (*_17); - StorageLive(_54); - StorageLive(_60); - StorageLive(_55); - StorageLive(_59); - StorageLive(_57); - _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); - _57 = copy _59 as *const u8 (Transmute); - StorageLive(_58); - _58 = copy (((*_52).0: std::vec::Vec).1: usize); - switchInt(UbChecks) -> [0: bb33, otherwise: bb31]; + StorageLive(_39); + StorageLive(_40); + _39 = copy (*_15); + _40 = copy (*_17); + StorageLive(_41); + StorageLive(_42); + StorageLive(_43); + StorageLive(_44); + StorageLive(_46); + _46 = copy ((((((*_39).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _44 = copy _46 as *const u8 (Transmute); + StorageDead(_46); + StorageLive(_45); + _45 = copy (((*_39).0: std::vec::Vec).1: usize); + _43 = *const [u8] from (copy _44, move _45); + StorageDead(_45); + StorageDead(_44); + _42 = &(*_43); + StorageDead(_43); + _41 = copy _42 as &str (Transmute); + StorageDead(_42); + StorageLive(_48); + StorageLive(_50); + _48 = copy _41 as &[u8] (Transmute); + _50 = copy _40 as &[u8] (Transmute); + _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb24, unwind: bb22]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb19; -+ goto -> bb43; ++ goto -> bb25; } bb8: { @@ -354,14 +300,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb19; -+ goto -> bb41; ++ goto -> bb27; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb19; -+ goto -> bb43; ++ goto -> bb25; } bb11: { @@ -423,223 +369,39 @@ } bb23: { - StorageLive(_36); - _36 = copy _34 as *mut () (Transmute); - _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb24, unwind unreachable]; - } - - bb24: { + StorageDead(_38); StorageDead(_36); - goto -> bb25; - } - - bb25: { - StorageLive(_37); - _37 = *const [u8] from (copy _32, copy _33); - _30 = &(*_37); - StorageDead(_37); - StorageDead(_33); - StorageDead(_32); - StorageDead(_34); - _29 = copy _30 as &str (Transmute); - StorageDead(_30); - StorageLive(_39); - StorageLive(_41); - _39 = copy _29 as &[u8] (Transmute); - _41 = copy _28 as &[u8] (Transmute); - StorageLive(_45); - StorageLive(_50); - StorageLive(_51); - StorageLive(_42); - StorageLive(_43); - _43 = PtrMetadata(copy _39); - StorageLive(_44); - _44 = PtrMetadata(copy _41); - _42 = Ne(move _43, move _44); - switchInt(move _42) -> [0: bb28, otherwise: bb27]; - } - - bb26: { - StorageDead(_51); - StorageDead(_50); - StorageDead(_45); - StorageDead(_41); - StorageDead(_39); - StorageDead(_35); StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb27: { - StorageDead(_44); - StorageDead(_43); - _7 = const false; - StorageDead(_42); -- goto -> bb26; -+ goto -> bb39; - } - - bb28: { - StorageDead(_44); - StorageDead(_43); - StorageDead(_42); - StorageLive(_49); - _49 = &raw const (*_39); - _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb30, unwind unreachable]; - } - - bb29: { + bb24: { + StorageDead(_50); StorageDead(_48); - StorageDead(_47); - _7 = Eq(move _46, const 0_i32); - StorageDead(_46); - goto -> bb26; - } - - bb30: { - StorageDead(_49); - StorageLive(_46); - StorageLive(_47); - _50 = &raw const (*_39); - _47 = copy _50 as *const u8 (PtrToPtr); - StorageLive(_48); - _51 = &raw const (*_41); - _48 = copy _51 as *const u8 (PtrToPtr); - _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb29, unwind unreachable]; - } - - bb31: { - StorageLive(_61); - _61 = copy _59 as *mut () (Transmute); - _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb32, unwind unreachable]; - } - - bb32: { - StorageDead(_61); - goto -> bb33; - } - - bb33: { - StorageLive(_62); - _62 = *const [u8] from (copy _57, copy _58); - _55 = &(*_62); - StorageDead(_62); - StorageDead(_58); - StorageDead(_57); - StorageDead(_59); - _54 = copy _55 as &str (Transmute); - StorageDead(_55); - StorageLive(_64); - StorageLive(_66); - _64 = copy _54 as &[u8] (Transmute); - _66 = copy _53 as &[u8] (Transmute); - StorageLive(_70); - StorageLive(_75); - StorageLive(_76); - StorageLive(_67); - StorageLive(_68); - _68 = PtrMetadata(copy _64); - StorageLive(_69); - _69 = PtrMetadata(copy _66); - _67 = Ne(move _68, move _69); - switchInt(move _67) -> [0: bb36, otherwise: bb35]; - } - - bb34: { - StorageDead(_76); - StorageDead(_75); - StorageDead(_70); - StorageDead(_66); - StorageDead(_64); - StorageDead(_60); - StorageDead(_54); - StorageDead(_53); - StorageDead(_52); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); switchInt(move _14) -> [0: bb9, otherwise: bb8]; - } - - bb35: { - StorageDead(_69); - StorageDead(_68); - _14 = const false; - StorageDead(_67); -- goto -> bb34; -+ goto -> bb40; - } - - bb36: { - StorageDead(_69); - StorageDead(_68); - StorageDead(_67); - StorageLive(_74); - _74 = &raw const (*_64); - _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb38, unwind unreachable]; - } - - bb37: { - StorageDead(_73); - StorageDead(_72); - _14 = Eq(move _71, const 0_i32); - StorageDead(_71); - goto -> bb34; - } - - bb38: { - StorageDead(_74); - StorageLive(_71); - StorageLive(_72); - _75 = &raw const (*_64); - _72 = copy _75 as *const u8 (PtrToPtr); - StorageLive(_73); - _76 = &raw const (*_66); - _73 = copy _76 as *const u8 (PtrToPtr); - _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb37, unwind unreachable]; + } + -+ bb39: { -+ StorageDead(_51); -+ StorageDead(_50); -+ StorageDead(_45); -+ StorageDead(_41); -+ StorageDead(_39); -+ StorageDead(_35); -+ StorageDead(_29); -+ StorageDead(_28); -+ StorageDead(_27); -+ goto -> bb6; -+ } -+ -+ bb40: { -+ StorageDead(_76); -+ StorageDead(_75); -+ StorageDead(_70); -+ StorageDead(_66); -+ StorageDead(_64); -+ StorageDead(_60); -+ StorageDead(_54); -+ StorageDead(_53); -+ StorageDead(_52); -+ goto -> bb9; -+ } -+ -+ bb41: { ++ bb25: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb42, otherwise: bb16]; ++ switchInt(move _24) -> [1: bb26, otherwise: bb16]; + } + -+ bb42: { -+ goto -> bb18; -+ } -+ -+ bb43: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb44, otherwise: bb16]; -+ } -+ -+ bb44: { ++ bb26: { + goto -> bb16; ++ } ++ ++ bb27: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb28, otherwise: bb16]; ++ } ++ ++ bb28: { ++ goto -> bb18; } } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 791d6b71a6f7..013361d1d2fb 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -25,17 +25,21 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { } } scope 18 (inlined ::deallocate) { - let mut _9: *mut u8; - scope 19 (inlined Layout::size) { - } - scope 20 (inlined NonNull::::as_ptr) { - } - scope 21 (inlined std::alloc::dealloc) { - let mut _10: usize; - scope 22 (inlined Layout::size) { - } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { + scope 19 (inlined std::alloc::Global::deallocate_impl) { + scope 20 (inlined std::alloc::Global::deallocate_impl_runtime) { + let mut _9: *mut u8; + scope 21 (inlined Layout::size) { + } + scope 22 (inlined NonNull::::as_ptr) { + } + scope 23 (inlined std::alloc::dealloc) { + let mut _10: usize; + scope 24 (inlined Layout::size) { + } + scope 25 (inlined Layout::align) { + scope 26 (inlined std::ptr::Alignment::as_usize) { + } + } } } } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 1dbe9394e709..b45a0f4a9bdd 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -9,33 +9,33 @@ let mut _4: *mut [u8]; let mut _5: std::ptr::NonNull<[u8]>; let mut _6: std::result::Result, std::alloc::AllocError>; - let mut _7: &std::alloc::Global; - let mut _8: std::alloc::Layout; + let mut _7: std::alloc::Layout; scope 1 { debug layout => _1; - let mut _9: &std::alloc::Global; scope 2 { debug ptr => _3; } scope 5 (inlined ::allocate) { - } - scope 6 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { - let mut _12: isize; - let _13: std::alloc::AllocError; - let mut _14: !; - let mut _15: &dyn std::fmt::Debug; - let _16: &std::alloc::AllocError; - scope 7 { + scope 6 (inlined std::alloc::Global::alloc_impl) { } + } + scope 7 (inlined #[track_caller] Result::, std::alloc::AllocError>::unwrap) { + let mut _10: isize; + let _11: std::alloc::AllocError; + let mut _12: !; + let mut _13: &dyn std::fmt::Debug; + let _14: &std::alloc::AllocError; scope 8 { } + scope 9 { + } } - scope 9 (inlined NonNull::<[u8]>::as_ptr) { + scope 10 (inlined NonNull::<[u8]>::as_ptr) { } } scope 3 (inlined #[track_caller] Option::::unwrap) { - let mut _10: isize; - let mut _11: !; + let mut _8: isize; + let mut _9: !; scope 4 { } } @@ -46,10 +46,10 @@ StorageLive(_2); - _2 = Option::::None; + _2 = const Option::::None; - StorageLive(_10); -- _10 = discriminant(_2); -- switchInt(move _10) -> [0: bb2, 1: bb3, otherwise: bb1]; -+ _10 = const 0_isize; + StorageLive(_8); +- _8 = discriminant(_2); +- switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1]; ++ _8 = const 0_isize; + switchInt(const 0_isize) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -58,48 +58,44 @@ } bb2: { - _11 = option::unwrap_failed() -> unwind unreachable; + _9 = option::unwrap_failed() -> unwind unreachable; } bb3: { - _1 = move ((_2 as Some).0: std::alloc::Layout); + _1 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; - StorageDead(_10); + StorageDead(_8); StorageDead(_2); StorageLive(_3); StorageLive(_4); StorageLive(_5); StorageLive(_6); StorageLive(_7); - _9 = const main::promoted[0]; - _7 = copy _9; - StorageLive(_8); -- _8 = copy _1; -- _6 = std::alloc::Global::alloc_impl(move _7, move _8, const false) -> [return: bb4, unwind unreachable]; -+ _8 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; -+ _6 = std::alloc::Global::alloc_impl(copy _9, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; +- _7 = copy _1; +- _6 = std::alloc::Global::alloc_impl_runtime(move _7, const false) -> [return: bb4, unwind unreachable]; ++ _7 = const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}; ++ _6 = std::alloc::Global::alloc_impl_runtime(const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_8); StorageDead(_7); - StorageLive(_12); - StorageLive(_16); - _12 = discriminant(_6); - switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; + StorageLive(_10); + StorageLive(_14); + _10 = discriminant(_6); + switchInt(move _10) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - StorageLive(_15); - _16 = &_13; - _15 = copy _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); - _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; + StorageLive(_13); + _14 = &_11; + _13 = copy _14 as &dyn std::fmt::Debug (PointerCoercion(Unsize, Implicit)); + _12 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _13) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_16); - StorageDead(_12); + StorageDead(_14); + StorageDead(_10); StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 2eee8a97db0d..8308ecbad716 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -9,6 +9,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; let mut _3: *const u8; let mut _4: usize; + let _5: *const [u8]; scope 3 (inlined Vec::::as_ptr) { debug self => _1; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { @@ -29,43 +30,23 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - debug data => _3; - debug len => _4; - let _5: *const [u8]; - scope 13 (inlined core::ub_checks::check_language_ub) { - scope 14 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 15 (inlined std::mem::size_of::) { - } - scope 16 (inlined std::mem::align_of::) { - } - scope 17 (inlined slice_from_raw_parts::) { - debug data => _3; - debug len => _4; - scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _3; - } - } - } } } bb0: { - StorageLive(_2); + StorageLive(_5); StorageLive(_3); + StorageLive(_2); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_2); StorageLive(_4); _4 = copy ((*_1).1: usize); - StorageLive(_5); - _5 = *const [u8] from (copy _3, copy _4); - _0 = &(*_5); - StorageDead(_5); + _5 = *const [u8] from (copy _3, move _4); StorageDead(_4); StorageDead(_3); - StorageDead(_2); + _0 = &(*_5); + StorageDead(_5); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 2eee8a97db0d..8308ecbad716 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -9,6 +9,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { debug self => _1; let mut _3: *const u8; let mut _4: usize; + let _5: *const [u8]; scope 3 (inlined Vec::::as_ptr) { debug self => _1; scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { @@ -29,43 +30,23 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { } } } - scope 12 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { - debug data => _3; - debug len => _4; - let _5: *const [u8]; - scope 13 (inlined core::ub_checks::check_language_ub) { - scope 14 (inlined core::ub_checks::check_language_ub::runtime) { - } - } - scope 15 (inlined std::mem::size_of::) { - } - scope 16 (inlined std::mem::align_of::) { - } - scope 17 (inlined slice_from_raw_parts::) { - debug data => _3; - debug len => _4; - scope 18 (inlined std::ptr::from_raw_parts::<[u8], u8>) { - debug data_pointer => _3; - } - } - } } } bb0: { - StorageLive(_2); + StorageLive(_5); StorageLive(_3); + StorageLive(_2); _2 = copy (((((*_1).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); _3 = copy _2 as *const u8 (Transmute); + StorageDead(_2); StorageLive(_4); _4 = copy ((*_1).1: usize); - StorageLive(_5); - _5 = *const [u8] from (copy _3, copy _4); - _0 = &(*_5); - StorageDead(_5); + _5 = *const [u8] from (copy _3, move _4); StorageDead(_4); StorageDead(_3); - StorageDead(_2); + _0 = &(*_5); + StorageDead(_5); return; } } From c48df5dcf189c730edc2eb1cf93117af584cceee Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 23 Dec 2025 22:42:03 -0800 Subject: [PATCH 283/340] Move the `rustc_no_mir_inline` down a level --- library/core/src/slice/cmp.rs | 21 ++++++-- ..._conditions.JumpThreading.panic-abort.diff | 52 ++++++++++--------- ...conditions.JumpThreading.panic-unwind.diff | 52 ++++++++++--------- 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index dfc0b565195e..c3ff928a3277 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -13,11 +13,7 @@ impl const PartialEq<[U]> for [T] where T: [const] PartialEq, { - // It's not worth trying to inline the loops underneath here *in MIR*, - // and preventing it encourages more useful inlining upstream, - // such as in `::eq`. - // The codegen backend can still inline it later if needed. - #[rustc_no_mir_inline] + #[inline] fn eq(&self, other: &[U]) -> bool { SlicePartialEq::equal(self, other) } @@ -108,6 +104,11 @@ impl const SlicePartialEq for [A] where A: [const] PartialEq, { + // It's not worth trying to inline the loops underneath here *in MIR*, + // and preventing it encourages more useful inlining upstream, + // such as in `::eq`. + // The codegen backend can still inline it later if needed. + #[rustc_no_mir_inline] default fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; @@ -137,6 +138,16 @@ impl const SlicePartialEq for [A] where A: [const] BytewiseEq, { + // This is usually a pretty good backend inlining candidate because the + // intrinsic tends to just be `memcmp`. However, as of 2025-12 letting + // MIR inline this makes reuse worse because it means that, for example, + // `String::eq` doesn't inline, whereas by keeping this from inling all + // the wrappers until the call to this disappear. If the heuristics have + // changed and this is no longer fruitful, though, please do remove it. + // In the mean time, it's fine to not inline it in MIR because the backend + // will still inline it if it things it's important to do so. + #[rustc_no_mir_inline] + #[inline] fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { return false; 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 0875d437296d..3cf28f4b60af 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 @@ -92,62 +92,66 @@ scope 24 (inlined core::str::::as_bytes) { } scope 25 (inlined std::cmp::impls::::eq) { + scope 26 (inlined core::slice::cmp::::eq) { + } } } } } - scope 26 (inlined std::cmp::impls:: for &String>::eq) { + scope 27 (inlined std::cmp::impls:: for &String>::eq) { let mut _39: &std::string::String; let mut _40: &str; - scope 27 (inlined >::eq) { - scope 28 (inlined #[track_caller] >::index) { + scope 28 (inlined >::eq) { + scope 29 (inlined #[track_caller] >::index) { let _41: &str; - scope 29 (inlined String::as_str) { + scope 30 (inlined String::as_str) { let _42: &[u8]; - scope 30 (inlined Vec::::as_slice) { + scope 31 (inlined Vec::::as_slice) { let _43: *const [u8]; let mut _44: *const u8; let mut _45: usize; - scope 31 (inlined Vec::::as_ptr) { - scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + scope 32 (inlined Vec::::as_ptr) { + scope 33 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 35 (inlined Unique::::cast::) { - scope 36 (inlined NonNull::::cast::) { - scope 37 (inlined NonNull::::as_ptr) { + scope 36 (inlined Unique::::cast::) { + scope 37 (inlined NonNull::::cast::) { + scope 38 (inlined NonNull::::as_ptr) { } } } - scope 38 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined Unique::::as_non_null_ptr) { } } - scope 39 (inlined NonNull::::as_ptr) { + scope 40 (inlined NonNull::::as_ptr) { } } } } } - scope 40 (inlined from_utf8_unchecked) { + scope 41 (inlined from_utf8_unchecked) { } } - scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 44 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 44 (inlined core::str::traits::::eq) { + scope 45 (inlined core::str::traits::::eq) { let mut _47: &&[u8]; let _48: &[u8]; let mut _49: &&[u8]; let _50: &[u8]; - scope 45 (inlined core::str::::as_bytes) { - } scope 46 (inlined core::str::::as_bytes) { } - scope 47 (inlined std::cmp::impls::::eq) { + scope 47 (inlined core::str::::as_bytes) { + } + scope 48 (inlined std::cmp::impls::::eq) { + scope 49 (inlined core::slice::cmp::::eq) { + } } } } @@ -214,7 +218,7 @@ StorageLive(_38); _36 = copy _29 as &[u8] (Transmute); _38 = copy _28 as &[u8] (Transmute); - _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb19, unwind unreachable]; + _7 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _36, move _38) -> [return: bb19, unwind unreachable]; } bb5: { @@ -270,7 +274,7 @@ StorageLive(_50); _48 = copy _41 as &[u8] (Transmute); _50 = copy _40 as &[u8] (Transmute); - _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb20, unwind unreachable]; + _14 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _48, move _50) -> [return: bb20, unwind unreachable]; } bb7: { 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 b942eeed37e0..2f0d83f92792 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 @@ -92,62 +92,66 @@ scope 24 (inlined core::str::::as_bytes) { } scope 25 (inlined std::cmp::impls::::eq) { + scope 26 (inlined core::slice::cmp::::eq) { + } } } } } - scope 26 (inlined std::cmp::impls:: for &String>::eq) { + scope 27 (inlined std::cmp::impls:: for &String>::eq) { let mut _39: &std::string::String; let mut _40: &str; - scope 27 (inlined >::eq) { - scope 28 (inlined #[track_caller] >::index) { + scope 28 (inlined >::eq) { + scope 29 (inlined #[track_caller] >::index) { let _41: &str; - scope 29 (inlined String::as_str) { + scope 30 (inlined String::as_str) { let _42: &[u8]; - scope 30 (inlined Vec::::as_slice) { + scope 31 (inlined Vec::::as_slice) { let _43: *const [u8]; let mut _44: *const u8; let mut _45: usize; - scope 31 (inlined Vec::::as_ptr) { - scope 32 (inlined alloc::raw_vec::RawVec::::ptr) { - scope 33 (inlined alloc::raw_vec::RawVecInner::ptr::) { - scope 34 (inlined alloc::raw_vec::RawVecInner::non_null::) { + scope 32 (inlined Vec::::as_ptr) { + scope 33 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 34 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 35 (inlined alloc::raw_vec::RawVecInner::non_null::) { let mut _46: std::ptr::NonNull; - scope 35 (inlined Unique::::cast::) { - scope 36 (inlined NonNull::::cast::) { - scope 37 (inlined NonNull::::as_ptr) { + scope 36 (inlined Unique::::cast::) { + scope 37 (inlined NonNull::::cast::) { + scope 38 (inlined NonNull::::as_ptr) { } } } - scope 38 (inlined Unique::::as_non_null_ptr) { + scope 39 (inlined Unique::::as_non_null_ptr) { } } - scope 39 (inlined NonNull::::as_ptr) { + scope 40 (inlined NonNull::::as_ptr) { } } } } } - scope 40 (inlined from_utf8_unchecked) { + scope 41 (inlined from_utf8_unchecked) { } } - scope 41 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 42 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 42 (inlined #[track_caller] core::str::traits:: for str>::index) { - scope 43 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + scope 43 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 44 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { } } - scope 44 (inlined core::str::traits::::eq) { + scope 45 (inlined core::str::traits::::eq) { let mut _47: &&[u8]; let _48: &[u8]; let mut _49: &&[u8]; let _50: &[u8]; - scope 45 (inlined core::str::::as_bytes) { - } scope 46 (inlined core::str::::as_bytes) { } - scope 47 (inlined std::cmp::impls::::eq) { + scope 47 (inlined core::str::::as_bytes) { + } + scope 48 (inlined std::cmp::impls::::eq) { + scope 49 (inlined core::slice::cmp::::eq) { + } } } } @@ -214,7 +218,7 @@ StorageLive(_38); _36 = copy _29 as &[u8] (Transmute); _38 = copy _28 as &[u8] (Transmute); - _7 = <[u8] as PartialEq>::eq(move _36, move _38) -> [return: bb23, unwind: bb22]; + _7 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _36, move _38) -> [return: bb23, unwind: bb22]; } bb5: { @@ -270,7 +274,7 @@ StorageLive(_50); _48 = copy _41 as &[u8] (Transmute); _50 = copy _40 as &[u8] (Transmute); - _14 = <[u8] as PartialEq>::eq(move _48, move _50) -> [return: bb24, unwind: bb22]; + _14 = <[u8] as core::slice::cmp::SlicePartialEq>::equal(move _48, move _50) -> [return: bb24, unwind: bb22]; } bb7: { From 45e0fbf7c5ffa5b8d36f9708e3a735908c6f28b4 Mon Sep 17 00:00:00 2001 From: tison Date: Fri, 9 Jan 2026 09:58:08 +0800 Subject: [PATCH 284/340] Implement partial_sort_unstable for slice Signed-off-by: tison Co-Authored-By: Orson Peters Signed-off-by: tison --- library/alloctests/tests/lib.rs | 2 + library/alloctests/tests/sort/mod.rs | 1 + library/alloctests/tests/sort/partial.rs | 84 ++++++++ library/core/src/slice/mod.rs | 213 ++++++++++++++++++++ library/core/src/slice/sort/unstable/mod.rs | 57 +++++- 5 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 library/alloctests/tests/sort/partial.rs diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 34c65bf787c8..36eb0c3fa2c7 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -20,6 +20,8 @@ #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_drain_sorted)] #![feature(slice_ptr_get)] +#![feature(slice_range)] +#![feature(slice_partial_sort_unstable)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/alloctests/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs index 0e2494ca9d34..e2e141a02b59 100644 --- a/library/alloctests/tests/sort/mod.rs +++ b/library/alloctests/tests/sort/mod.rs @@ -12,6 +12,7 @@ pub trait Sort { mod ffi_types; mod known_good_stable_sort; +mod partial; mod patterns; mod tests; mod zipf; diff --git a/library/alloctests/tests/sort/partial.rs b/library/alloctests/tests/sort/partial.rs new file mode 100644 index 000000000000..c7248990c70c --- /dev/null +++ b/library/alloctests/tests/sort/partial.rs @@ -0,0 +1,84 @@ +use std::fmt::Debug; +use std::ops::{Range, RangeBounds}; +use std::slice; + +use super::patterns; + +fn check_is_partial_sorted>(v: &mut [T], range: R) { + let Range { start, end } = slice::range(range, ..v.len()); + v.partial_sort_unstable(start..end); + + let max_before = v[..start].iter().max().into_iter(); + let sorted_range = v[start..end].into_iter(); + let min_after = v[end..].iter().min().into_iter(); + let seq = max_before.chain(sorted_range).chain(min_after); + assert!(seq.is_sorted()); +} + +fn check_is_partial_sorted_ranges(v: &[T]) { + let len = v.len(); + + check_is_partial_sorted::(&mut v.to_vec(), ..); + check_is_partial_sorted::(&mut v.to_vec(), 0..0); + check_is_partial_sorted::(&mut v.to_vec(), len..len); + + if len > 0 { + check_is_partial_sorted::(&mut v.to_vec(), len - 1..len - 1); + check_is_partial_sorted::(&mut v.to_vec(), 0..1); + check_is_partial_sorted::(&mut v.to_vec(), len - 1..len); + + for mid in 1..len { + check_is_partial_sorted::(&mut v.to_vec(), 0..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid..len); + check_is_partial_sorted::(&mut v.to_vec(), mid..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid - 1..mid + 1); + check_is_partial_sorted::(&mut v.to_vec(), mid - 1..mid); + check_is_partial_sorted::(&mut v.to_vec(), mid..mid + 1); + } + + let quarters = [0, len / 4, len / 2, (3 * len) / 4, len]; + for &start in &quarters { + for &end in &quarters { + if start < end { + check_is_partial_sorted::(&mut v.to_vec(), start..end); + } + } + } + } +} + +#[test] +fn basic_impl() { + check_is_partial_sorted::(&mut [], ..); + check_is_partial_sorted::<(), _>(&mut [], ..); + check_is_partial_sorted::<(), _>(&mut [()], ..); + check_is_partial_sorted::<(), _>(&mut [(), ()], ..); + check_is_partial_sorted::<(), _>(&mut [(), (), ()], ..); + check_is_partial_sorted::(&mut [], ..); + + check_is_partial_sorted::(&mut [77], ..); + check_is_partial_sorted::(&mut [2, 3], ..); + check_is_partial_sorted::(&mut [2, 3, 6], ..); + check_is_partial_sorted::(&mut [2, 3, 99, 6], ..); + check_is_partial_sorted::(&mut [2, 7709, 400, 90932], ..); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], ..); + + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..0); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..1); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 0..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 7..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 6..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 5..7); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 5..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 4..5); + check_is_partial_sorted::(&mut [15, -1, 3, -1, -3, -1, 7], 4..6); +} + +#[test] +fn random_patterns() { + check_is_partial_sorted_ranges(&patterns::random(10)); + check_is_partial_sorted_ranges(&patterns::random(50)); + check_is_partial_sorted_ranges(&patterns::random(100)); + check_is_partial_sorted_ranges(&patterns::random(1000)); +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 889fd4cd65df..762921a85fc6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3244,6 +3244,219 @@ impl [T] { sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } + /// Partially sorts the slice in ascending order **without** preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `T` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable(0..0); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable(2..2); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable(2..3); + /// for i in 0..2 { + /// assert!(v[i] <= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] <= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable(1..4); + /// assert_eq!(&v[1..4], [-3, 1, 2]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable(..); + /// assert_eq!(v, [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [`sort_unstable`]: slice::sort_unstable + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable(&mut self, range: R) + where + T: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, T::lt); + } + + /// Partially sorts the slice in ascending order with a comparison function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the `compare` does not implement a total order, or if + /// the `compare` itself panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by(0..0, |a, b| b.cmp(a)); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by(2..2, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by(2..3, |a, b| b.cmp(a)); + /// for i in 0..2 { + /// assert!(v[i] >= v[2]); + /// } + /// for i in 3..v.len() { + /// assert!(v[2] >= v[i]); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by(1..4, |a, b| b.cmp(a)); + /// assert_eq!(&v[1..4], [2, 1, -3]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by(.., |a, b| b.cmp(a)); + /// assert_eq!(v, [4, 2, 1, -3, -5]); + /// ``` + /// + /// [`sort_unstable_by`]: slice::sort_unstable_by + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by(&mut self, range: R, mut compare: F) + where + F: FnMut(&T, &T) -> Ordering, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| compare(a, b) == Less); + } + + /// Partially sorts the slice in ascending order with a key extraction function, **without** + /// preserving the initial order of equal elements. + /// + /// Upon completion, for the specified range `start..end`, it's guaranteed that: + /// + /// 1. Every element in `self[..start]` is smaller than or equal to + /// 2. Every element in `self[start..end]`, which is sorted, and smaller than or equal to + /// 3. Every element in `self[end..]`. + /// + /// This partial sort is unstable, meaning it may reorder equal elements in the specified range. + /// It may reorder elements outside the specified range as well, but the guarantees above still hold. + /// + /// This partial sort is in-place (i.e., does not allocate), and *O*(*n* + *k* \* log(*k*)) worst-case, + /// where *n* is the length of the slice and *k* is the length of the specified range. + /// + /// See the documentation of [`sort_unstable_by_key`] for implementation notes. + /// + /// # Panics + /// + /// May panic if the implementation of [`Ord`] for `K` does not implement a total order, or if + /// the [`Ord`] implementation panics, or if the specified range is out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partial_sort_unstable)] + /// + /// let mut v = [4i32, -5, 1, -3, 2]; + /// + /// // empty range at the beginning, nothing changed + /// v.partial_sort_unstable_by_key(0..0, |k| k.abs()); + /// assert_eq!(v, [4, -5, 1, -3, 2]); + /// + /// // empty range in the middle, partitioning the slice + /// v.partial_sort_unstable_by_key(2..2, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // single element range, same as select_nth_unstable + /// v.partial_sort_unstable_by_key(2..3, |k| k.abs()); + /// for i in 0..2 { + /// assert!(v[i].abs() <= v[2].abs()); + /// } + /// for i in 3..v.len() { + /// assert!(v[2].abs() <= v[i].abs()); + /// } + /// + /// // partial sort a subrange + /// v.partial_sort_unstable_by_key(1..4, |k| k.abs()); + /// assert_eq!(&v[1..4], [2, -3, 4]); + /// + /// // partial sort the whole range, same as sort_unstable + /// v.partial_sort_unstable_by_key(.., |k| k.abs()); + /// assert_eq!(v, [1, 2, -3, 4, -5]); + /// ``` + /// + /// [`sort_unstable_by_key`]: slice::sort_unstable_by_key + #[unstable(feature = "slice_partial_sort_unstable", issue = "149046")] + #[inline] + pub fn partial_sort_unstable_by_key(&mut self, range: R, mut f: F) + where + F: FnMut(&T) -> K, + K: Ord, + R: RangeBounds, + { + sort::unstable::partial_sort(self, range, |a, b| f(a).lt(&f(b))); + } + /// Reorders the slice such that the element at `index` is at a sort-order position. All /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to /// it. diff --git a/library/core/src/slice/sort/unstable/mod.rs b/library/core/src/slice/sort/unstable/mod.rs index d4df8d3a264d..7ca95a3b1b19 100644 --- a/library/core/src/slice/sort/unstable/mod.rs +++ b/library/core/src/slice/sort/unstable/mod.rs @@ -1,11 +1,13 @@ //! This module contains the entry points for `slice::sort_unstable`. use crate::mem::SizedTypeProperties; +use crate::ops::{Range, RangeBounds}; +use crate::slice::sort::select::partition_at_index; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::find_existing_run; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::insertion_sort_shift_left; -use crate::{cfg_select, intrinsics}; +use crate::{cfg_select, intrinsics, slice}; pub(crate) mod heapsort; pub(crate) mod quicksort; @@ -17,7 +19,10 @@ pub(crate) mod quicksort; /// Upholds all safety properties outlined here: /// #[inline(always)] -pub fn sort bool>(v: &mut [T], is_less: &mut F) { +pub fn sort(v: &mut [T], is_less: &mut F) +where + F: FnMut(&T, &T) -> bool, +{ // Arrays of zero-sized types are always all-equal, and thus sorted. if T::IS_ZST { return; @@ -52,6 +57,54 @@ pub fn sort bool>(v: &mut [T], is_less: &mut F) { } } +/// Unstable partial sort the range `start..end`, after which it's guaranteed that: +/// +/// 1. Every element in `v[..start]` is smaller than or equal to +/// 2. Every element in `v[start..end]`, which is sorted, and smaller than or equal to +/// 3. Every element in `v[end..]`. +#[inline] +pub fn partial_sort(v: &mut [T], range: R, mut is_less: F) +where + F: FnMut(&T, &T) -> bool, + R: RangeBounds, +{ + // Arrays of zero-sized types are always all-equal, and thus sorted. + if T::IS_ZST { + return; + } + + let len = v.len(); + let Range { start, end } = slice::range(range, ..len); + + if end - start <= 1 { + // Empty range or single element. This case can be resolved in at most + // single partition_at_index call, without further sorting. + + if end == 0 || start == len { + // Do nothing if it is an empty range at start or end: all guarantees + // are already upheld. + return; + } + + partition_at_index(v, start, &mut is_less); + return; + } + + // A heuristic factor to decide whether to partition the slice or not. + // If the range bound is close to the edges of the slice, it's not worth + // partitioning first. + const PARTITION_THRESHOLD: usize = 8; + let mut v = v; + if end + PARTITION_THRESHOLD <= len { + v = partition_at_index(v, end - 1, &mut is_less).0; + } + if start >= PARTITION_THRESHOLD { + v = partition_at_index(v, start, &mut is_less).2; + } + + sort(v, &mut is_less); +} + /// See [`sort`] /// /// Deliberately don't inline the main sorting routine entrypoint to ensure the From 484ea769d3db73b912ef05367ade53fee874e023 Mon Sep 17 00:00:00 2001 From: paradoxicalguy Date: Wed, 31 Dec 2025 06:49:53 +0000 Subject: [PATCH 285/340] adding minicore to test file to avoid duplicating lang error --- tests/assembly-llvm/rust-abi-arg-attr.rs | 42 ++---------------------- tests/auxiliary/minicore.rs | 18 ++++++++++ 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/tests/assembly-llvm/rust-abi-arg-attr.rs b/tests/assembly-llvm/rust-abi-arg-attr.rs index 4f3673ccfc3b..2d13feb021ba 100644 --- a/tests/assembly-llvm/rust-abi-arg-attr.rs +++ b/tests/assembly-llvm/rust-abi-arg-attr.rs @@ -1,3 +1,4 @@ +//@ add-minicore //@ assembly-output: emit-asm //@ revisions: riscv64 riscv64-zbb loongarch64 //@ compile-flags: -C opt-level=3 @@ -14,45 +15,8 @@ #![no_std] #![no_core] // FIXME: Migrate these code after PR #130693 is landed. - -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} - -#[lang = "copy"] -trait Copy {} - -impl Copy for i8 {} -impl Copy for u32 {} -impl Copy for i32 {} - -#[lang = "neg"] -trait Neg { - type Output; - - fn neg(self) -> Self::Output; -} - -impl Neg for i8 { - type Output = i8; - - fn neg(self) -> Self::Output { - -self - } -} - -#[lang = "Ordering"] -#[repr(i8)] -enum Ordering { - Less = -1, - Equal = 0, - Greater = 1, -} +extern crate minicore; +use minicore::*; #[rustc_intrinsic] fn three_way_compare(lhs: T, rhs: T) -> Ordering; diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 288a5b50dd5e..d349262b2559 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -210,6 +210,14 @@ impl Neg for isize { } } +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + loop {} + } +} + #[lang = "sync"] trait Sync {} impl_marker_trait!( @@ -280,6 +288,16 @@ pub enum c_void { __variant2, } +#[lang = "Ordering"] +#[repr(i8)] +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +impl Copy for Ordering {} + #[lang = "const_param_ty"] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy_ {} From a97825c3f3afd60746a018628a70eea68b7890ff Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Tue, 6 Jan 2026 21:14:57 -0500 Subject: [PATCH 286/340] 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 b54051b15052..8c133afcd5e0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit b54051b1505281ec7a45a250140a0ff25d33f319 +Subproject commit 8c133afcd5e0d69932fe11f5907683723f8d361d From 97fc739602cb8e0800734a86bb40331e1bb73f20 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 10:31:18 +0530 Subject: [PATCH 287/340] std: sys: fs: uefi: Implement File::tell - Just a call to get_position - Tested with OVMF on QEMU Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..3b10986f17f9 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -364,7 +364,7 @@ impl File { } pub fn tell(&self) -> io::Result { - unsupported() + self.0.position() } pub fn duplicate(&self) -> io::Result { @@ -734,6 +734,14 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + pub(crate) fn position(&self) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut pos = 0; + + let r = unsafe { ((*file_ptr).get_position)(file_ptr, &mut pos) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(pos) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.protocol.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; From 0495a7347454772a93be512cd5de7118d407a0f8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 7 Jan 2026 13:04:10 +1100 Subject: [PATCH 288/340] Prepare for `thir::Pat` nodes having multiple user-type ascriptions --- .../src/builder/matches/mod.rs | 41 ++++++++++--------- .../src/builder/matches/user_ty.rs | 29 ++++++++----- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 9080e2ba801b..aaca6936dcd2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -879,6 +879,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &ProjectedUserTypesNode<'_>, ), ) { + // Ascriptions correspond to user-written types like `let A::<'a>(_): A<'static> = ...;`. + // + // Caution: Pushing user types here is load-bearing even for + // patterns containing no bindings, to ensure that the type ends + // up represented in MIR _somewhere_. + let user_tys = match pattern.kind { + PatKind::AscribeUserType { ref ascription, .. } => { + let base_user_tys = std::iter::once(ascription) + .map(|thir::Ascription { annotation, variance: _ }| { + // Note that the variance doesn't apply here, as we are tracking the effect + // of user types on any bindings contained with subpattern. + self.canonical_user_type_annotations.push(annotation.clone()) + }) + .collect(); + &user_tys.push_user_types(base_user_tys) + } + _ => user_tys, + }; + // Avoid having to write the full method name at each recursive call. let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| { this.visit_primary_bindings_special(subpat, user_tys, f) @@ -924,25 +943,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } => { - // This corresponds to something like - // - // ``` - // let A::<'a>(_): A<'static> = ...; - // ``` - // - // Note that the variance doesn't apply here, as we are tracking the effect - // of `user_ty` on any bindings contained with subpattern. - - // Caution: Pushing this user type here is load-bearing even for - // patterns containing no bindings, to ensure that the type ends - // up represented in MIR _somewhere_. - let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); - let subpattern_user_tys = user_tys.push_user_type(base_user_ty); - visit_subpat(self, subpattern, &subpattern_user_tys, f) + PatKind::AscribeUserType { ref subpattern, ascription: _ } => { + // The ascription was already handled above, so just recurse to the subpattern. + visit_subpat(self, subpattern, user_tys, f) } PatKind::ExpandedConstant { ref subpattern, .. } => { diff --git a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs index df9f93ac328a..2dcfd3772902 100644 --- a/compiler/rustc_mir_build/src/builder/matches/user_ty.rs +++ b/compiler/rustc_mir_build/src/builder/matches/user_ty.rs @@ -8,15 +8,20 @@ use std::assert_matches::assert_matches; use std::iter; use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_data_structures::smallvec::SmallVec; use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections}; use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex}; use rustc_span::Symbol; +/// A single `thir::Pat` node should almost never have more than 0-2 user types. +/// We can store up to 4 inline in the same size as an ordinary `Vec`. +pub(crate) type UserTypeIndices = SmallVec<[UserTypeAnnotationIndex; 4]>; + /// One of a list of "operations" that can be used to lazily build projections /// of user-specified types. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) enum ProjectedUserTypesOp { - PushUserType { base: UserTypeAnnotationIndex }, + PushUserTypes { base_types: UserTypeIndices }, Index, Subslice { from: u64, to: u64 }, @@ -32,9 +37,10 @@ pub(crate) enum ProjectedUserTypesNode<'a> { } impl<'a> ProjectedUserTypesNode<'a> { - pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self { - // Pushing a base user type always causes the chain to become non-empty. - Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } } + pub(crate) fn push_user_types(&'a self, base_types: UserTypeIndices) -> Self { + assert!(!base_types.is_empty()); + // Pushing one or more base user types always causes the chain to become non-empty. + Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserTypes { base_types } } } /// Push another projection op onto the chain, but only if it is already non-empty. @@ -94,16 +100,19 @@ impl<'a> ProjectedUserTypesNode<'a> { return None; } - let ops_reversed = self.iter_ops_reversed().cloned().collect::>(); + let ops_reversed = self.iter_ops_reversed().collect::>(); // The "first" op should always be `PushUserType`. // Other projections are only added if there is at least one user type. - assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserType { .. })); + assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserTypes { .. })); let mut projections = vec![]; for op in ops_reversed.into_iter().rev() { - match op { - ProjectedUserTypesOp::PushUserType { base } => { - projections.push(UserTypeProjection { base, projs: vec![] }) + match *op { + ProjectedUserTypesOp::PushUserTypes { ref base_types } => { + assert!(!base_types.is_empty()); + for &base in base_types { + projections.push(UserTypeProjection { base, projs: vec![] }) + } } ProjectedUserTypesOp::Index => { From f85b898c45bccef0142485d0d092ab66688b4641 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 14:34:55 +1100 Subject: [PATCH 289/340] Prefer to return `Box` instead of `thir::PatKind` This will allow extra data to be attached to the `Pat` before it is returned. --- .../src/thir/pattern/const_to_pat.rs | 14 ++- .../rustc_mir_build/src/thir/pattern/mod.rs | 96 ++++++++++++------- 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2da9a43f71d8..76b742aa6e45 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -174,10 +174,10 @@ impl<'tcx> ConstToPat<'tcx> { } }; - // Convert the valtree to a const. - let inlined_const_as_pat = self.valtree_to_pat(valtree, ty); + // Lower the valtree to a THIR pattern. + let mut thir_pat = self.valtree_to_pat(valtree, ty); - if !inlined_const_as_pat.references_error() { + if !thir_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. if !type_has_partial_eq_impl(self.tcx, typing_env, ty).has_impl { let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty }); @@ -188,8 +188,12 @@ impl<'tcx> ConstToPat<'tcx> { // Wrap the pattern in a marker node to indicate that it is the result of lowering a // constant. This is used for diagnostics. - let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def }; - Box::new(Pat { kind, ty, span: self.span }) + thir_pat = Box::new(Pat { + ty: thir_pat.ty, + span: thir_pat.span, + kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, + }); + thir_pat } fn field_pats( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 4128508955cb..01986d946d45 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -167,9 +167,10 @@ impl<'tcx> PatCtxt<'tcx> { // Return None in that case; the caller will use NegInfinity or PosInfinity instead. let Some(expr) = expr else { return Ok(None) }; - // Lower the endpoint into a temporary `PatKind` that will then be + // Lower the endpoint into a temporary `thir::Pat` that will then be // deconstructed to obtain the constant value and other data. - let mut kind: PatKind<'tcx> = self.lower_pat_expr(pat, expr); + let endpoint_pat: Box> = self.lower_pat_expr(pat, expr); + let box Pat { mut kind, .. } = endpoint_pat; // Unpeel any ascription or inline-const wrapper nodes. loop { @@ -250,7 +251,7 @@ impl<'tcx> PatCtxt<'tcx> { lo_expr: Option<&'tcx hir::PatExpr<'tcx>>, hi_expr: Option<&'tcx hir::PatExpr<'tcx>>, end: RangeEnd, - ) -> Result, ErrorGuaranteed> { + ) -> Result>, ErrorGuaranteed> { let ty = self.typeck_results.node_type(pat.hir_id); let span = pat.span; @@ -306,27 +307,34 @@ impl<'tcx> PatCtxt<'tcx> { return Err(e); } } + let mut thir_pat = Box::new(Pat { ty, span, kind }); // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. for ascription in ascriptions { - let subpattern = Box::new(Pat { span, ty, kind }); - kind = PatKind::AscribeUserType { ascription, subpattern }; + thir_pat = Box::new(Pat { + ty, + span, + kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, + }); } // `PatKind::ExpandedConstant` wrappers from range endpoints used to // also be preserved here, but that was only needed for unsafeck of // inline `const { .. }` patterns, which were removed by // . - Ok(kind) + Ok(thir_pat) } #[instrument(skip(self), level = "debug")] fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { - let mut ty = self.typeck_results.node_type(pat.hir_id); - let mut span = pat.span; + let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; + // Some of these match arms return a `Box` early, while others + // evaluate to a `PatKind` that will become a `Box` at the end of + // this function. let kind = match pat.kind { hir::PatKind::Missing => PatKind::Missing, @@ -334,10 +342,13 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Never => PatKind::Never, - hir::PatKind::Expr(value) => self.lower_pat_expr(pat, value), + hir::PatKind::Expr(value) => return self.lower_pat_expr(pat, value), hir::PatKind::Range(lo_expr, hi_expr, end) => { - self.lower_pattern_range(pat, lo_expr, hi_expr, end).unwrap_or_else(PatKind::Error) + match self.lower_pattern_range(pat, lo_expr, hi_expr, end) { + Ok(thir_pat) => return thir_pat, + Err(e) => PatKind::Error(e), + } } hir::PatKind::Deref(subpattern) => { @@ -360,7 +371,7 @@ impl<'tcx> PatCtxt<'tcx> { }, hir::PatKind::Slice(prefix, slice, suffix) => { - self.slice_or_array_pattern(pat, prefix, slice, suffix) + return self.slice_or_array_pattern(pat, prefix, slice, suffix); } hir::PatKind::Tuple(pats, ddpos) => { @@ -372,8 +383,9 @@ impl<'tcx> PatCtxt<'tcx> { } hir::PatKind::Binding(explicit_ba, id, ident, sub) => { + let mut thir_pat_span = span; if let Some(ident_span) = ident.span.find_ancestor_inside(span) { - span = span.with_hi(ident_span.hi()); + thir_pat_span = span.with_hi(ident_span.hi()); } let mode = *self @@ -389,22 +401,23 @@ impl<'tcx> PatCtxt<'tcx> { // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; + let mut thir_pat_ty = ty; if let hir::ByRef::Yes(pinnedness, _) = mode.0 { match pinnedness { hir::Pinnedness::Pinned if let Some(pty) = ty.pinned_ty() && let &ty::Ref(_, rty, _) = pty.kind() => { - ty = rty; + thir_pat_ty = rty; } hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => { - ty = rty; + thir_pat_ty = rty; } _ => bug!("`ref {}` has wrong type {}", ident, ty), } }; - PatKind::Binding { + let kind = PatKind::Binding { mode, name: ident.name, var: LocalVarId(id), @@ -412,7 +425,10 @@ impl<'tcx> PatCtxt<'tcx> { subpattern: self.lower_opt_pattern(sub), is_primary: id == pat.hir_id, is_shorthand: false, - } + }; + // We might have modified the type or span, so use the modified + // values in the THIR pattern node. + return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind }); } hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => { @@ -422,7 +438,7 @@ impl<'tcx> PatCtxt<'tcx> { }; let variant_def = adt_def.variant_of_res(res); let subpatterns = self.lower_tuple_subpats(pats, variant_def.fields.len(), ddpos); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Struct(ref qpath, fields, _) => { @@ -439,7 +455,7 @@ impl<'tcx> PatCtxt<'tcx> { }) .collect(); - self.lower_variant_or_leaf(pat, None, res, subpatterns) + return self.lower_variant_or_leaf(pat, None, res, subpatterns); } hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) }, @@ -450,6 +466,8 @@ impl<'tcx> PatCtxt<'tcx> { hir::PatKind::Err(guar) => PatKind::Error(guar), }; + // For pattern kinds that haven't already returned, create a `thir::Pat` + // with the HIR pattern node's type and span. Box::new(Pat { span, ty, kind }) } @@ -482,13 +500,14 @@ impl<'tcx> PatCtxt<'tcx> { prefix: &'tcx [hir::Pat<'tcx>], slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], - ) -> PatKind<'tcx> { + ) -> Box> { let ty = self.typeck_results.node_type(pat.hir_id); + let span = pat.span; let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); - match ty.kind() { + let kind = match ty.kind() { // Matching a slice, `[T]`. ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. @@ -499,8 +518,9 @@ impl<'tcx> PatCtxt<'tcx> { assert!(len >= prefix.len() as u64 + suffix.len() as u64); PatKind::Array { prefix, slice, suffix } } - _ => span_bug!(pat.span, "bad slice pattern type {ty:?}"), - } + _ => span_bug!(span, "bad slice pattern type {ty:?}"), + }; + Box::new(Pat { ty, span, kind }) } fn lower_variant_or_leaf( @@ -509,7 +529,7 @@ impl<'tcx> PatCtxt<'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, res: Res, subpatterns: Vec>, - ) -> PatKind<'tcx> { + ) -> Box> { // Check whether the caller should have provided an `expr` for this pattern kind. assert_matches!( (pat.kind, expr), @@ -533,7 +553,7 @@ impl<'tcx> PatCtxt<'tcx> { res => res, }; - let mut kind = match res { + let kind = match res { Res::Def(DefKind::Variant, variant_id) => { let enum_id = self.tcx.parent(variant_id); let adt_def = self.tcx.adt_def(enum_id); @@ -542,7 +562,7 @@ impl<'tcx> PatCtxt<'tcx> { ty::Adt(_, args) | ty::FnDef(_, args) => args, ty::Error(e) => { // Avoid ICE (#50585) - return PatKind::Error(*e); + return Box::new(Pat { ty, span, kind: PatKind::Error(*e) }); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -583,21 +603,26 @@ impl<'tcx> PatCtxt<'tcx> { PatKind::Error(e) } }; + let mut thir_pat = Box::new(Pat { ty, span, kind }); if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { - debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); + debug!(?thir_pat, ?user_ty, ?span, "lower_variant_or_leaf: applying ascription"); let annotation = CanonicalUserTypeAnnotation { user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results.node_type(hir_id), }; - kind = PatKind::AscribeUserType { - subpattern: Box::new(Pat { span, ty, kind }), - ascription: Ascription { annotation, variance: ty::Covariant }, - }; + thir_pat = Box::new(Pat { + ty, + span, + kind: PatKind::AscribeUserType { + subpattern: thir_pat, + ascription: Ascription { annotation, variance: ty::Covariant }, + }, + }); } - kind + thir_pat } fn user_args_applied_to_ty_of_hir_id( @@ -632,8 +657,7 @@ impl<'tcx> PatCtxt<'tcx> { _ => { // The path isn't the name of a constant, so it must actually // be a unit struct or unit variant (e.g. `Option::None`). - let kind = self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); - return Box::new(Pat { span, ty, kind }); + return self.lower_variant_or_leaf(pat, Some(expr), res, vec![]); } }; @@ -674,10 +698,10 @@ impl<'tcx> PatCtxt<'tcx> { &mut self, pat: &'tcx hir::Pat<'tcx>, // Pattern that directly contains `expr` expr: &'tcx hir::PatExpr<'tcx>, - ) -> PatKind<'tcx> { + ) -> Box> { assert_matches!(pat.kind, hir::PatKind::Expr(..) | hir::PatKind::Range(..)); match &expr.kind { - hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath).kind, + hir::PatExprKind::Path(qpath) => self.lower_path(pat, expr, qpath), hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, @@ -691,7 +715,7 @@ impl<'tcx> PatCtxt<'tcx> { let pat_ty = self.typeck_results.node_type(pat.hir_id); let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; let constant = self.tcx.at(expr.span).lit_to_const(lit_input); - self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span).kind + self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span) } } } From bd7704830331f0feb1fd8b43e18fd535663acadb Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 18:20:31 +1100 Subject: [PATCH 290/340] Initial plumbing for `thir::PatExtra` --- compiler/rustc_middle/src/thir.rs | 18 +++++++- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 5 ++- .../rustc_mir_build/src/thir/pattern/mod.rs | 24 +++++++---- compiler/rustc_mir_build/src/thir/print.rs | 42 ++++++++++++++++++- 5 files changed, 78 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3683c1cfb7dd..3ddb5a1523d0 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -643,10 +643,26 @@ pub struct FieldPat<'tcx> { pub pattern: Pat<'tcx>, } +/// Additional per-node data that is not present on most THIR pattern nodes. +#[derive(Clone, Debug, Default, HashStable, TypeVisitable)] +pub struct PatExtra<'tcx> { + /// If present, this node represents a named constant that was lowered to + /// a pattern using `const_to_pat`. + /// + /// This is used by some diagnostics for non-exhaustive matches, to map + /// the pattern node back to the `DefId` of its original constant. + pub expanded_const: Option, + + /// User-written types that must be preserved into MIR so that they can be + /// checked. + pub ascriptions: Vec>, +} + #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, + pub extra: Option>>, pub kind: PatKind<'tcx>, } @@ -1119,7 +1135,7 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 64); + static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 48); static_assert_size!(Stmt<'_>, 48); static_assert_size!(StmtKind<'_>, 48); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index d792bbe60c88..e0c044220b81 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -259,7 +259,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( pat: &'a Pat<'tcx>, mut callback: impl FnMut(&'a Pat<'tcx>), ) { - let Pat { kind, ty: _, span: _ } = pat; + let Pat { kind, ty: _, span: _, extra: _ } = pat; match kind { PatKind::Missing | PatKind::Wild diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 76b742aa6e45..98faf0ab613f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -90,7 +90,7 @@ impl<'tcx> ConstToPat<'tcx> { ); } } - Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) }) + Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()), extra: None }) } fn unevaluated_to_pat( @@ -192,6 +192,7 @@ impl<'tcx> ConstToPat<'tcx> { ty: thir_pat.ty, span: thir_pat.span, kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, + extra: None, }); thir_pat } @@ -355,7 +356,7 @@ impl<'tcx> ConstToPat<'tcx> { } }; - Box::new(Pat { span, ty, kind }) + Box::new(Pat { span, ty, kind, extra: None }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 01986d946d45..9c39a934c7ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -78,6 +78,7 @@ pub(super) fn pat_from_hir<'tcx>( ascription: Ascription { annotation, variance: ty::Covariant }, subpattern: thir_pat, }, + extra: None, }); } @@ -142,7 +143,7 @@ impl<'tcx> PatCtxt<'tcx> { } PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat }, }; - Box::new(Pat { span, ty: adjust.source, kind }) + Box::new(Pat { span, ty: adjust.source, kind, extra: None }) }); if let Some(s) = &mut self.rust_2024_migration @@ -307,7 +308,7 @@ impl<'tcx> PatCtxt<'tcx> { return Err(e); } } - let mut thir_pat = Box::new(Pat { ty, span, kind }); + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated @@ -317,6 +318,7 @@ impl<'tcx> PatCtxt<'tcx> { ty, span, kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, + extra: None, }); } // `PatKind::ExpandedConstant` wrappers from range endpoints used to @@ -428,7 +430,7 @@ impl<'tcx> PatCtxt<'tcx> { }; // We might have modified the type or span, so use the modified // values in the THIR pattern node. - return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind }); + return Box::new(Pat { ty: thir_pat_ty, span: thir_pat_span, kind, extra: None }); } hir::PatKind::TupleStruct(ref qpath, pats, ddpos) => { @@ -468,7 +470,7 @@ impl<'tcx> PatCtxt<'tcx> { // For pattern kinds that haven't already returned, create a `thir::Pat` // with the HIR pattern node's type and span. - Box::new(Pat { span, ty, kind }) + Box::new(Pat { span, ty, kind, extra: None }) } fn lower_tuple_subpats( @@ -520,7 +522,7 @@ impl<'tcx> PatCtxt<'tcx> { } _ => span_bug!(span, "bad slice pattern type {ty:?}"), }; - Box::new(Pat { ty, span, kind }) + Box::new(Pat { ty, span, kind, extra: None }) } fn lower_variant_or_leaf( @@ -562,7 +564,12 @@ impl<'tcx> PatCtxt<'tcx> { ty::Adt(_, args) | ty::FnDef(_, args) => args, ty::Error(e) => { // Avoid ICE (#50585) - return Box::new(Pat { ty, span, kind: PatKind::Error(*e) }); + return Box::new(Pat { + ty, + span, + kind: PatKind::Error(*e), + extra: None, + }); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -603,7 +610,7 @@ impl<'tcx> PatCtxt<'tcx> { PatKind::Error(e) } }; - let mut thir_pat = Box::new(Pat { ty, span, kind }); + let mut thir_pat = Box::new(Pat { ty, span, kind, extra: None }); if let Some(user_ty) = self.user_args_applied_to_ty_of_hir_id(hir_id) { debug!(?thir_pat, ?user_ty, ?span, "lower_variant_or_leaf: applying ascription"); @@ -619,6 +626,7 @@ impl<'tcx> PatCtxt<'tcx> { subpattern: thir_pat, ascription: Ascription { annotation, variance: ty::Covariant }, }, + extra: None, }); } @@ -685,7 +693,7 @@ impl<'tcx> PatCtxt<'tcx> { variance: ty::Contravariant, }, }; - pattern = Box::new(Pat { span, kind, ty }); + pattern = Box::new(Pat { span, kind, ty, extra: None }); } pattern diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5a2d6cfef1cc..d735ef2134ab 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -73,6 +73,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.fmt } + fn print_list( + &mut self, + label: &str, + list: &[T], + depth_lvl: usize, + print_fn: impl Fn(&mut Self, &T, usize), + ) { + if list.is_empty() { + print_indented!(self, format_args!("{label}: []"), depth_lvl); + } else { + print_indented!(self, format_args!("{label}: ["), depth_lvl); + for item in list { + print_fn(self, item, depth_lvl + 1) + } + print_indented!(self, "]", depth_lvl); + } + } + fn print_param(&mut self, param: &Param<'tcx>, depth_lvl: usize) { let Param { pat, ty, ty_span, self_kind, hir_id } = param; @@ -663,15 +681,37 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) { - let &Pat { ty, span, ref kind } = pat; + let &Pat { ty, span, ref kind, ref extra } = pat; print_indented!(self, "Pat: {", depth_lvl); print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1); print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + self.print_pat_extra(extra.as_deref(), depth_lvl + 1); self.print_pat_kind(kind, depth_lvl + 1); print_indented!(self, "}", depth_lvl); } + fn print_pat_extra(&mut self, extra: Option<&PatExtra<'tcx>>, depth_lvl: usize) { + let Some(extra) = extra else { + // Skip printing in the common case of a pattern node with no extra data. + return; + }; + + let PatExtra { expanded_const, ascriptions } = extra; + + print_indented!(self, "extra: PatExtra {", depth_lvl); + print_indented!(self, format_args!("expanded_const: {expanded_const:?}"), depth_lvl + 1); + self.print_list( + "ascriptions", + ascriptions, + depth_lvl + 1, + |this, ascription, depth_lvl| { + print_indented!(this, format_args!("{ascription:?}"), depth_lvl); + }, + ); + print_indented!(self, "}", depth_lvl); + } + fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) { print_indented!(self, "kind: PatKind {", depth_lvl); From 8516c64115ce3689e66a2ab95de77f978f7398b6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 6 Jan 2026 18:30:20 +1100 Subject: [PATCH 291/340] Replace `AscribeUserType` and `ExpandedConstant` with per-node data --- compiler/rustc_middle/src/thir.rs | 20 ----- compiler/rustc_middle/src/thir/visit.rs | 6 +- .../src/builder/custom/parse.rs | 24 ++---- .../src/builder/custom/parse/instruction.rs | 5 -- .../src/builder/matches/match_pair.rs | 41 ++++------ .../src/builder/matches/mod.rs | 67 ++++------------ .../rustc_mir_build/src/check_unsafety.rs | 2 - .../src/thir/pattern/check_match.rs | 13 +--- .../src/thir/pattern/const_to_pat.rs | 9 +-- .../rustc_mir_build/src/thir/pattern/mod.rs | 76 ++++++------------- compiler/rustc_mir_build/src/thir/print.rs | 14 ---- compiler/rustc_pattern_analysis/src/rustc.rs | 2 - 12 files changed, 68 insertions(+), 211 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3ddb5a1523d0..e538c2182924 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -778,11 +778,6 @@ pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, - AscribeUserType { - ascription: Ascription<'tcx>, - subpattern: Box>, - }, - /// `x`, `ref x`, `x @ P`, etc. Binding { name: Symbol, @@ -847,21 +842,6 @@ pub enum PatKind<'tcx> { value: ty::Value<'tcx>, }, - /// Wrapper node representing a named constant that was lowered to a pattern - /// using `const_to_pat`. - /// - /// This is used by some diagnostics for non-exhaustive matches, to map - /// the pattern node back to the `DefId` of its original constant. - /// - /// FIXME(#150498): Can we make this an `Option` field on `Pat` - /// instead, so that non-diagnostic code can ignore it more easily? - ExpandedConstant { - /// [DefId] of the constant item. - def_id: DefId, - /// The pattern that the constant lowered to. - subpattern: Box>, - }, - Range(Arc>), /// Matches against a slice, checking the length and extracting elements. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index e0c044220b81..b611b23e5261 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -269,11 +269,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( | PatKind::Never | PatKind::Error(_) => {} - PatKind::AscribeUserType { subpattern, .. } - | PatKind::Binding { subpattern: Some(subpattern), .. } + PatKind::Binding { subpattern: Some(subpattern), .. } | PatKind::Deref { subpattern } - | PatKind::DerefPattern { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern), + | PatKind::DerefPattern { subpattern, .. } => callback(subpattern), PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => { for field_pat in subpatterns { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index c6ef362c6ea5..3ae4b1fadee9 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -287,22 +287,14 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { self.parse_var(pattern) } - fn parse_var(&mut self, mut pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { - // Make sure we throw out any `AscribeUserType` we find - loop { - match &pat.kind { - PatKind::Binding { var, ty, .. } => break Ok((*var, *ty, pat.span)), - PatKind::AscribeUserType { subpattern, .. } => { - pat = subpattern; - } - _ => { - break Err(ParseError { - span: pat.span, - item_description: format!("{:?}", pat.kind), - expected: "local".to_string(), - }); - } - } + fn parse_var(&mut self, pat: &Pat<'tcx>) -> PResult<(LocalVarId, Ty<'tcx>, Span)> { + match &pat.kind { + PatKind::Binding { var, ty, .. } => Ok((*var, *ty, pat.span)), + _ => Err(ParseError { + span: pat.span, + item_description: format!("{:?}", pat.kind), + expected: "local".to_string(), + }), } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index ddaa61c6cc91..13082d408ec0 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -144,11 +144,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value } = subpattern.kind => - { - value - } _ => { return Err(ParseError { span: arm.pattern.span, diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index f0114c2193c3..8cee3ff27e8f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -133,6 +133,20 @@ impl<'tcx> MatchPairTree<'tcx> { } let place = place_builder.try_to_place(cx); + + // Apply any type ascriptions to the value at `match_pair.place`. + if let Some(place) = place + && let Some(extra) = &pattern.extra + { + for &Ascription { ref annotation, variance } in &extra.ascriptions { + extra_data.ascriptions.push(super::Ascription { + source: place, + annotation: annotation.clone(), + variance, + }); + } + } + let mut subpairs = Vec::new(); let testable_case = match pattern.kind { PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None, @@ -195,28 +209,6 @@ impl<'tcx> MatchPairTree<'tcx> { Some(TestableCase::Constant { value, kind: const_kind }) } - PatKind::AscribeUserType { - ascription: Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - MatchPairTree::for_pattern( - place_builder, - subpattern, - cx, - &mut subpairs, - extra_data, - ); - - // Apply the type ascription to the value at `match_pair.place` - if let Some(source) = place { - let annotation = annotation.clone(); - extra_data.ascriptions.push(super::Ascription { source, annotation, variance }); - } - - None - } - PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => { // In order to please the borrow checker, when lowering a pattern // like `x @ subpat` we must establish any bindings in `subpat` @@ -263,11 +255,6 @@ impl<'tcx> MatchPairTree<'tcx> { None } - PatKind::ExpandedConstant { subpattern: ref pattern, .. } => { - MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); - None - } - PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( &mut subpairs, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index aaca6936dcd2..590316a47554 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -576,7 +576,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer_id: ExprId, ) -> BlockAnd<()> { match irrefutable_pat.kind { - // Optimize the case of `let x = ...` to write directly into `x` + // Optimize `let x = ...` and `let x: T = ...` to write directly into `x`, + // and then require that `T == typeof(x)` if present. PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { let place = self.storage_live_binding( block, @@ -592,43 +593,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place); - self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); - block.unit() - } + let ascriptions: &[_] = + try { irrefutable_pat.extra.as_deref()?.ascriptions.as_slice() } + .unwrap_or_default(); + for thir::Ascription { annotation, variance: _ } in ascriptions { + let ty_source_info = self.source_info(annotation.span); - // Optimize the case of `let x: T = ...` to write directly - // into `x` and then require that `T == typeof(x)`. - PatKind::AscribeUserType { - ref subpattern, - ascription: thir::Ascription { ref annotation, variance: _ }, - } if let PatKind::Binding { - mode: BindingMode(ByRef::No, _), - var, - subpattern: None, - .. - } = subpattern.kind => - { - let place = self.storage_live_binding( - block, - var, - irrefutable_pat.span, - false, - OutsideGuard, - ScheduleDrops::Yes, - ); - block = self.expr_into_dest(place, block, initializer_id).into_block(); - - // Inject a fake read, see comments on `FakeReadCause::ForLet`. - let pattern_source_info = self.source_info(irrefutable_pat.span); - let cause_let = FakeReadCause::ForLet(None); - self.cfg.push_fake_read(block, pattern_source_info, cause_let, place); - - let ty_source_info = self.source_info(annotation.span); - - let base = self.canonical_user_type_annotations.push(annotation.clone()); - self.cfg.push( - block, - Statement::new( + let base = self.canonical_user_type_annotations.push(annotation.clone()); + let stmt = Statement::new( ty_source_info, StatementKind::AscribeUserType( Box::new((place, UserTypeProjection { base, projs: Vec::new() })), @@ -648,8 +620,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``. ty::Invariant, ), - ), - ); + ); + self.cfg.push(block, stmt); + } self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() @@ -884,9 +857,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Caution: Pushing user types here is load-bearing even for // patterns containing no bindings, to ensure that the type ends // up represented in MIR _somewhere_. - let user_tys = match pattern.kind { - PatKind::AscribeUserType { ref ascription, .. } => { - let base_user_tys = std::iter::once(ascription) + let user_tys = match pattern.extra.as_deref() { + Some(PatExtra { ascriptions, .. }) if !ascriptions.is_empty() => { + let base_user_tys = ascriptions + .iter() .map(|thir::Ascription { annotation, variance: _ }| { // Note that the variance doesn't apply here, as we are tracking the effect // of user types on any bindings contained with subpattern. @@ -943,15 +917,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f); } - PatKind::AscribeUserType { ref subpattern, ascription: _ } => { - // The ascription was already handled above, so just recurse to the subpattern. - visit_subpat(self, subpattern, user_tys, f) - } - - PatKind::ExpandedConstant { ref subpattern, .. } => { - visit_subpat(self, subpattern, user_tys, f) - } - PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_tys = user_tys.leaf(subpattern.field); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 4f03e3d965c6..68b8a842a2a6 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -342,8 +342,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::ExpandedConstant { .. } | - PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bf480cf601ee..d9a06de32bb0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -680,20 +680,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - // These next few matches want to peek through `AscribeUserType` to see - // the underlying pattern. - let mut unpeeled_pat = pat; - while let PatKind::AscribeUserType { ref subpattern, .. } = unpeeled_pat.kind { - unpeeled_pat = subpattern; - } - - if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, unpeeled_pat) { + if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, pat) { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); // When we encounter a constant as the binding name, point at the `const` definition. interpreted_as_const = Some(InterpretedAsConst { span, variable: variable.clone() }); interpreted_as_const_sugg = Some(InterpretedAsConstSugg { span: pat.span, variable }); - } else if let PatKind::Constant { .. } = unpeeled_pat.kind + } else if let PatKind::Constant { .. } = pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { // If the pattern to match is an integer literal: @@ -1213,7 +1206,7 @@ fn is_const_pat_that_looks_like_binding<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat<'tcx> // The pattern must be a named constant, and the name that appears in // the pattern's source text must resemble a plain identifier without any // `::` namespace separators or other non-identifier characters. - if let PatKind::ExpandedConstant { def_id, .. } = pat.kind + if let Some(def_id) = try { pat.extra.as_deref()?.expanded_const? } && matches!(tcx.def_kind(def_id), DefKind::Const) && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(pat.span) && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 98faf0ab613f..02409d2bae9f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -186,14 +186,9 @@ impl<'tcx> ConstToPat<'tcx> { } } - // Wrap the pattern in a marker node to indicate that it is the result of lowering a + // Mark the pattern to indicate that it is the result of lowering a named // constant. This is used for diagnostics. - thir_pat = Box::new(Pat { - ty: thir_pat.ty, - span: thir_pat.span, - kind: PatKind::ExpandedConstant { def_id: uv.def, subpattern: thir_pat }, - extra: None, - }); + thir_pat.extra.get_or_insert_default().expanded_const = Some(uv.def); thir_pat } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9c39a934c7ee..650650cbaac9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -71,15 +71,11 @@ pub(super) fn pat_from_hir<'tcx>( span: let_stmt_type.span, inferred_ty: typeck_results.node_type(let_stmt_type.hir_id), }; - thir_pat = Box::new(Pat { - ty: thir_pat.ty, - span: thir_pat.span, - kind: PatKind::AscribeUserType { - ascription: Ascription { annotation, variance: ty::Covariant }, - subpattern: thir_pat, - }, - extra: None, - }); + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } if let Some(m) = pcx.rust_2024_migration { @@ -171,23 +167,11 @@ impl<'tcx> PatCtxt<'tcx> { // Lower the endpoint into a temporary `thir::Pat` that will then be // deconstructed to obtain the constant value and other data. let endpoint_pat: Box> = self.lower_pat_expr(pat, expr); - let box Pat { mut kind, .. } = endpoint_pat; + let box Pat { ref kind, extra, .. } = endpoint_pat; - // Unpeel any ascription or inline-const wrapper nodes. - loop { - match kind { - PatKind::AscribeUserType { ascription, subpattern } => { - ascriptions.push(ascription); - kind = subpattern.kind; - } - PatKind::ExpandedConstant { def_id: _, subpattern } => { - // Expanded-constant nodes are currently only needed by - // diagnostics that don't apply to range patterns, so we - // can just discard them here. - kind = subpattern.kind; - } - _ => break, - } + // Preserve any ascriptions from endpoint constants. + if let Some(extra) = extra { + ascriptions.extend(extra.ascriptions); } // The unpeeled kind should now be a constant, giving us the endpoint value. @@ -313,15 +297,8 @@ impl<'tcx> PatCtxt<'tcx> { // If we are handling a range with associated constants (e.g. // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated // constants somewhere. Have them on the range pattern. - for ascription in ascriptions { - thir_pat = Box::new(Pat { - ty, - span, - kind: PatKind::AscribeUserType { ascription, subpattern: thir_pat }, - extra: None, - }); - } - // `PatKind::ExpandedConstant` wrappers from range endpoints used to + thir_pat.extra.get_or_insert_default().ascriptions.extend(ascriptions); + // IDs of expanded constants from range endpoints used to // also be preserved here, but that was only needed for unsafeck of // inline `const { .. }` patterns, which were removed by // . @@ -619,15 +596,11 @@ impl<'tcx> PatCtxt<'tcx> { span, inferred_ty: self.typeck_results.node_type(hir_id), }; - thir_pat = Box::new(Pat { - ty, - span, - kind: PatKind::AscribeUserType { - subpattern: thir_pat, - ascription: Ascription { annotation, variance: ty::Covariant }, - }, - extra: None, - }); + thir_pat + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Covariant }); } thir_pat @@ -684,16 +657,13 @@ impl<'tcx> PatCtxt<'tcx> { span, inferred_ty: self.typeck_results.node_type(id), }; - let kind = PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - annotation, - // Note that we use `Contravariant` here. See the - // `variance` field documentation for details. - variance: ty::Contravariant, - }, - }; - pattern = Box::new(Pat { span, kind, ty, extra: None }); + // Note that we use `Contravariant` here. See the + // `variance` field documentation for details. + pattern + .extra + .get_or_insert_default() + .ascriptions + .push(Ascription { annotation, variance: ty::Contravariant }); } pattern diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index d735ef2134ab..e12909305961 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -725,13 +725,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { PatKind::Never => { print_indented!(self, "Never", depth_lvl + 1); } - PatKind::AscribeUserType { ascription, subpattern } => { - print_indented!(self, "AscribeUserType: {", depth_lvl + 1); - print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); - print_indented!(self, "subpattern: ", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 3); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Binding { name, mode, var, ty, subpattern, is_primary, is_shorthand } => { print_indented!(self, "Binding {", depth_lvl + 1); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); @@ -796,13 +789,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, subpattern } => { - print_indented!(self, "ExpandedConstant {", depth_lvl + 1); - print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); - print_indented!(self, "subpattern:", depth_lvl + 2); - self.print_pat(subpattern, depth_lvl + 2); - print_indented!(self, "}", depth_lvl + 1); - } PatKind::Range(pat_range) => { print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d66c303b1726..721635ed48ff 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,8 +462,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let arity; let fields: Vec<_>; match &pat.kind { - PatKind::AscribeUserType { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; From 561b59255c7f9a9b6893a06b261ab08c4343b81e Mon Sep 17 00:00:00 2001 From: andjsrk Date: Fri, 9 Jan 2026 15:45:05 +0900 Subject: [PATCH 292/340] add test for binary ops --- ...can-have-side-effects-consider-operands.rs | 23 +++++++++++++++++++ ...have-side-effects-consider-operands.stderr | 13 +++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/binop/can-have-side-effects-consider-operands.rs create mode 100644 tests/ui/binop/can-have-side-effects-consider-operands.stderr diff --git a/tests/ui/binop/can-have-side-effects-consider-operands.rs b/tests/ui/binop/can-have-side-effects-consider-operands.rs new file mode 100644 index 000000000000..34eeb11c6add --- /dev/null +++ b/tests/ui/binop/can-have-side-effects-consider-operands.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![allow(unused)] + +// Test if `Expr::can_have_side_effects` considers operands of binary operators. + +fn drop_repeat_in_arm_body() { + // Built-in lint `dropping_copy_types` relies on `Expr::can_have_side_effects` + // (See rust-clippy#9482 and rust#113231) + + match () { + () => drop(5 % 3), // No side effects + //~^ WARNING calls to `std::mem::drop` with a value that implements `Copy` does nothing + } + match () { + () => drop(5 % calls_are_considered_side_effects()), // Definitely has side effects + } +} +fn calls_are_considered_side_effects() -> i32 { + 3 +} + +fn main() {} diff --git a/tests/ui/binop/can-have-side-effects-consider-operands.stderr b/tests/ui/binop/can-have-side-effects-consider-operands.stderr new file mode 100644 index 000000000000..ef3fc6b4be7e --- /dev/null +++ b/tests/ui/binop/can-have-side-effects-consider-operands.stderr @@ -0,0 +1,13 @@ +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/can-have-side-effects-consider-operands.rs:12:15 + | +LL | () => drop(5 % 3), // No side effects + | ^^^^^-----^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(dropping_copy_types)]` on by default + +warning: 1 warning emitted + From 7e433ebe7e7b6d3749ec1aed039ab4408d4ad051 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Fri, 9 Jan 2026 04:08:45 +0100 Subject: [PATCH 293/340] [miri] make closing stdio file descriptions noops std supports redirecting stdio file descriptors. --- src/tools/miri/src/shims/files.rs | 36 +++++++++++++++++++ .../tests/fail-dep/libc/fs/close_stdout.rs | 10 ------ .../fail-dep/libc/fs/close_stdout.stderr | 12 ------- src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 9 +++++ 4 files changed, 45 insertions(+), 22 deletions(-) delete mode 100644 src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs delete mode 100644 src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index f86933029341..694a5922b799 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -249,6 +249,15 @@ impl FileDescription for io::Stdin { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -279,6 +288,15 @@ impl FileDescription for io::Stdout { finish.call(ecx, result) } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -289,6 +307,15 @@ impl FileDescription for io::Stderr { "stderr" } + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } + fn write<'tcx>( self: FileDescriptionRef, _communicate_allowed: bool, @@ -436,6 +463,15 @@ impl FileDescription for NullOutput { // We just don't write anything, but report to the user that we did. finish.call(ecx, Ok(len)) } + + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + interp_ok(Ok(())) + } } /// Internal type of a file-descriptor - this is what [`FdTable`] expects diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs deleted file mode 100644 index 7911133f548f..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ignore-target: windows # No libc IO on Windows -//@compile-flags: -Zmiri-disable-isolation - -// FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) - -fn main() { - unsafe { - libc::close(1); //~ ERROR: cannot close stdout - } -} diff --git a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr deleted file mode 100644 index 84973ac020de..000000000000 --- a/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: unsupported operation: cannot close stdout - --> tests/fail-dep/libc/fs/close_stdout.rs:LL:CC - | -LL | libc::close(1); - | ^^^^^^^^^^^^^^ unsupported operation occurred here - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support - -note: 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-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 99685d6d976b..8c860b5db7ba 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -48,6 +48,7 @@ fn main() { test_nofollow_not_symlink(); #[cfg(target_os = "macos")] test_ioctl(); + test_close_stdout(); } fn test_file_open_unix_allow_two_args() { @@ -579,3 +580,11 @@ fn test_ioctl() { assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } + +fn test_close_stdout() { + // This is std library UB, but that's not relevant since we're + // only interacting with libc here. + unsafe { + libc::close(1); + } +} From 3c8265a29f3354edfe03b7bd326c68e4decc2a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 14:59:22 +0100 Subject: [PATCH 294/340] add test for 149981 --- tests/ui/eii/duplicate/eii_conflict_with_macro.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/ui/eii/duplicate/eii_conflict_with_macro.rs diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs new file mode 100644 index 000000000000..4012ea268799 --- /dev/null +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -0,0 +1,6 @@ +//@ compile-flags: --crate-type rlib +#![feature(extern_item_impls)] + +macro_rules! foo_impl {} +#[eii] +fn foo_impl() {} From 5e5c724194594c9af85d6678aef90ebc4a3428b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 18:24:15 +0100 Subject: [PATCH 295/340] turn panics into `span_delayed_bug` to make sure this pattern doesn't go unnoticed --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 11 +++++++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +--- compiler/rustc_metadata/src/eii.rs | 20 +++++++++++++++---- .../eii/duplicate/eii_conflict_with_macro.rs | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 74f4662118b6..2ad5792de3c0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -285,11 +285,16 @@ fn process_builtin_attrs( } AttributeKind::EiiImpls(impls) => { for i in impls { - let extern_item = find_attr!( + let Some(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"); + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; // 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 diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 725294dfd377..8cc3fab128e2 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1213,9 +1213,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { *span, ); } else { - panic!( - "EII impl macro {eii_macro:?} did not have an eii extern target attribute pointing to a foreign function" - ) + tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); } } } diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 5558ff930851..3f60f528776f 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -1,4 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::indexmap::map::Entry; use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; @@ -28,11 +29,22 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap 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(|| { + let registered_impls = match eiis.entry(i.eii_macro) { + Entry::Occupied(o) => &mut o.into_mut().1, + Entry::Vacant(v) => { // 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); + let Some(decl) = find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d) + else { + // skip if it doesn't have eii_extern_target (if we resolved to another macro that's not an EII) + tcx.dcx() + .span_delayed_bug(i.span, "resolved to something that's not an EII"); + continue; + }; + &mut v.insert((decl, Default::default())).1 + } + }; + + registered_impls.insert(id.into(), *i); } // if we find a new declaration, add it to the list without a known implementation diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs index 4012ea268799..deee2346552f 100644 --- a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -1,6 +1,6 @@ //@ compile-flags: --crate-type rlib #![feature(extern_item_impls)] -macro_rules! foo_impl {} +macro_rules! foo_impl { () => {} } #[eii] fn foo_impl() {} From e3cff18370d167b3e03eec8d31bf2f38709b7fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:15:41 +0100 Subject: [PATCH 296/340] dont resolve defaults anymore, store foreign item defid instead of macro --- compiler/rustc_ast/src/ast.rs | 13 +++ compiler/rustc_ast_lowering/src/item.rs | 96 +++++++++++-------- compiler/rustc_builtin_macros/src/eii.rs | 8 ++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 31 +++--- .../rustc_hir/src/attrs/data_structures.rs | 17 +++- .../src/check/compare_eii.rs | 12 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 35 +++---- compiler/rustc_metadata/src/eii.rs | 24 +++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 11 ++- compiler/rustc_passes/src/check_attr.rs | 16 +++- compiler/rustc_passes/src/eii.rs | 9 +- compiler/rustc_resolve/src/late.rs | 16 +++- 12 files changed, 188 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index d4407dbf7be7..6d3cea95e77d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3813,6 +3813,19 @@ pub struct Fn { pub struct EiiImpl { pub node_id: NodeId, pub eii_macro_path: Path, + /// This field is an implementation detail that prevents a lot of bugs. + /// See for an example. + /// + /// The problem is, that if we generate a declaration *together* with its default, + /// we generate both a declaration and an implementation. The generated implementation + /// uses the same mechanism to register itself as a user-defined implementation would, + /// despite being invisible to users. What does happen is a name resolution step. + /// The invisible default implementation has to find the declaration. + /// Both are generated at the same time, so we can skip that name resolution step. + /// + /// This field is that shortcut: we prefill the extern target to skip a name resolution step, + /// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user. + pub known_eii_macro_resolution: Option, pub impl_safety: Safety, pub span: Span, pub inner_span: Span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f8b98a5ece40..4b7995aa079e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; -use rustc_hir::attrs::{AttributeKind, EiiDecl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImplResolution}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ @@ -134,6 +134,55 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_eii_extern_target( + &mut self, + id: NodeId, + EiiExternTarget { extern_item_path, impl_unsafe, span }: &EiiExternTarget, + ) -> Option { + self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl { + eii_extern_target: did, + impl_unsafe: *impl_unsafe, + span: self.lower_span(*span), + }) + } + + fn lower_eii_impl( + &mut self, + EiiImpl { + node_id, + eii_macro_path, + impl_safety, + span, + inner_span, + is_default, + known_eii_macro_resolution, + }: &EiiImpl, + ) -> hir::attrs::EiiImpl { + let resolution = if let Some(target) = known_eii_macro_resolution + && let Some(decl) = self.lower_eii_extern_target(*node_id, target) + { + EiiImplResolution::Known( + decl, + // the expect is ok here since we always generate this path in the eii macro. + eii_macro_path.segments.last().expect("at least one segment").ident.name, + ) + } else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) { + EiiImplResolution::Macro(macro_did) + } else { + EiiImplResolution::Error( + self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"), + ) + }; + + hir::attrs::EiiImpl { + 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, + resolution, + } + } + fn generate_extra_attrs_for_item_kind( &mut self, id: NodeId, @@ -143,49 +192,14 @@ impl<'hir> LoweringContext<'_, 'hir> { 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(), + eii_impls.iter().map(|i| self.lower_eii_impl(i)).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), - }))] - }) + ItemKind::MacroDef(_, MacroDef { eii_extern_target: Some(target), .. }) => self + .lower_eii_extern_target(id, target) + .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))]) .unwrap_or_default(), + ItemKind::ExternCrate(..) | ItemKind::Use(..) | ItemKind::Static(..) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 9049639925dd..5105cdacd186 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -116,6 +116,7 @@ fn eii_( macro_name, eii_attr_span, item_span, + foreign_item_name, ))) } @@ -192,6 +193,7 @@ fn generate_default_impl( macro_name: Ident, eii_attr_span: Span, item_span: Span, + foreign_item_name: Ident, ) -> ast::Item { // FIXME: re-add some original attrs let attrs = ThinVec::new(); @@ -208,6 +210,11 @@ fn generate_default_impl( }, span: eii_attr_span, is_default: true, + known_eii_macro_resolution: Some(ast::EiiExternTarget { + extern_item_path: ast::Path::from_ident(foreign_item_name), + impl_unsafe, + span: item_span, + }), }); ast::Item { @@ -508,6 +515,7 @@ pub(crate) fn eii_shared_macro( impl_safety: meta_item.unsafety, span, is_default, + known_eii_macro_resolution: None, }); vec![item] diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2ad5792de3c0..8b8abfeb6a4f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,7 +3,9 @@ use std::str::FromStr; 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, Linkage, RtsanSetting, UsedBy}; +use rustc_hir::attrs::{ + AttributeKind, EiiImplResolution, InlineAttr, 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}; @@ -285,15 +287,22 @@ fn process_builtin_attrs( } AttributeKind::EiiImpls(impls) => { for i in impls { - let Some(extern_item) = find_attr!( - tcx.get_all_attrs(i.eii_macro), - AttributeKind::EiiExternTarget(target) => target.eii_extern_target - ) else { - tcx.dcx().span_delayed_bug( - i.span, - "resolved to something that's not an EII", - ); - continue; + let extern_item = match i.resolution { + EiiImplResolution::Macro(def_id) => { + let Some(extern_item) = find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::EiiExternTarget(target) => target.eii_extern_target + ) else { + tcx.dcx().span_delayed_bug( + i.span, + "resolved to something that's not an EII", + ); + continue; + }; + extern_item + } + EiiImplResolution::Known(decl, _) => decl.eii_extern_target, + EiiImplResolution::Error(_eg) => continue, }; // this is to prevent a bug where a single crate defines both the default and explicit implementation @@ -307,7 +316,7 @@ fn process_builtin_attrs( // 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) + && tcx.externally_implementable_items(LOCAL_CRATE).get(&extern_item).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default) { continue; } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index fa8998f0546d..5b2d73faef19 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -11,7 +11,7 @@ use rustc_error_messages::{DiagArgValue, IntoDiagArg}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::def_id::DefId; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; pub use rustc_target::spec::SanitizerSet; use thin_vec::ThinVec; @@ -19,9 +19,22 @@ use crate::attrs::pretty_printing::PrintAttribute; use crate::limit::Limit; use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; +#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum EiiImplResolution { + /// Usually, finding the extern item that an EII implementation implements means finding + /// the defid of the associated attribute macro, and looking at *its* attributes to find + /// what foreign item its associated with. + Macro(DefId), + /// Sometimes though, we already know statically and can skip some name resolution. + /// Stored together with the eii's name for diagnostics. + Known(EiiDecl, Symbol), + /// For when resolution failed, but we want to continue compilation + Error(ErrorGuaranteed), +} + #[derive(Copy, Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub struct EiiImpl { - pub eii_macro: DefId, + pub resolution: EiiImplResolution, pub impl_marked_unsafe: bool, pub span: Span, pub inner_span: Span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 4e7f47a92108..d8afee9aafc9 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -32,21 +32,21 @@ use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii}; pub(crate) fn compare_eii_function_types<'tcx>( tcx: TyCtxt<'tcx>, external_impl: LocalDefId, - declaration: DefId, + foreign_item: DefId, eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { - check_is_structurally_compatible(tcx, external_impl, declaration, eii_name, eii_attr_span)?; + check_is_structurally_compatible(tcx, external_impl, foreign_item, 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 }, + ObligationCauseCode::CompareEii { external_impl, declaration: foreign_item }, ); // 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 param_env = tcx.param_env(foreign_item); let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); @@ -62,7 +62,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( 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 = tcx.fn_sig(foreign_item).instantiate_identity(); let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig); debug!(?declaration_sig); @@ -103,7 +103,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( cause, param_env, terr, - (declaration, declaration_sig), + (foreign_item, declaration_sig), (external_impl, external_impl_sig), eii_attr_span, eii_name, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 8cc3fab128e2..cefd8c8f1443 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_abi::{ExternAbi, ScalableElt}; 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, EiiDecl, EiiImpl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -1196,25 +1196,28 @@ 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 + for EiiImpl { resolution, 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 { - tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); - } + let (foreign_item, name) = match resolution { + EiiImplResolution::Macro(def_id) => { + // 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(foreign_item) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::EiiExternTarget(EiiDecl {eii_extern_target: t, ..}) => *t) + { + (foreign_item, tcx.item_name(*def_id)) + } else { + tcx.dcx().span_delayed_bug(*span, "resolved to something that's not an EII"); + continue; + } + } + EiiImplResolution::Known(decl, name) => (decl.eii_extern_target, *name), + EiiImplResolution::Error(_eg) => continue, + }; + + let _ = compare_eii_function_types(tcx, def_id, foreign_item, name, *span); } } diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 3f60f528776f..425de9e62e50 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -1,6 +1,5 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::indexmap::map::Entry; -use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl}; +use rustc_hir::attrs::{AttributeKind, EiiDecl, EiiImpl, EiiImplResolution}; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; use rustc_middle::query::LocalCrate; @@ -10,7 +9,7 @@ use rustc_middle::ty::TyCtxt; pub(crate) type EiiMapEncodedKeyValue = (DefId, (EiiDecl, Vec<(DefId, EiiImpl)>)); pub(crate) type EiiMap = FxIndexMap< - DefId, // the defid of the macro that declared the eii + DefId, // the defid of the foreign item associated with the eii ( // the corresponding declaration EiiDecl, @@ -29,29 +28,34 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap for i in find_attr!(tcx.get_all_attrs(id), AttributeKind::EiiImpls(e) => e).into_iter().flatten() { - let registered_impls = match eiis.entry(i.eii_macro) { - Entry::Occupied(o) => &mut o.into_mut().1, - Entry::Vacant(v) => { + let decl = match i.resolution { + EiiImplResolution::Macro(macro_defid) => { // 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) - let Some(decl) = find_attr!(tcx.get_all_attrs(i.eii_macro), AttributeKind::EiiExternTarget(d) => *d) + let Some(decl) = find_attr!(tcx.get_all_attrs(macro_defid), AttributeKind::EiiExternTarget(d) => *d) else { // skip if it doesn't have eii_extern_target (if we resolved to another macro that's not an EII) tcx.dcx() .span_delayed_bug(i.span, "resolved to something that's not an EII"); continue; }; - &mut v.insert((decl, Default::default())).1 + decl } + EiiImplResolution::Known(decl, _) => decl, + EiiImplResolution::Error(_eg) => continue, }; - registered_impls.insert(id.into(), *i); + // FIXME(eii) remove extern target from encoded decl + eiis.entry(decl.eii_extern_target) + .or_insert_with(|| (decl, 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.entry(decl.eii_extern_target).or_insert((decl, Default::default())); } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c85327dc3db1..eedb88783ec0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1657,9 +1657,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { 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())) - })) + self.lazy_array(externally_implementable_items.iter().map( + |(foreign_item, (decl, impls))| { + ( + *foreign_item, + (decl.clone(), impls.iter().map(|(impl_did, i)| (*impl_did, *i)).collect()), + ) + }, + )) } #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f1cbb72554d2..5b3bdc07ec94 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -21,8 +21,8 @@ use rustc_feature::{ BuiltinAttribute, }; use rustc_hir::attrs::{ - AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, InlineAttr, MirDialect, MirPhase, - ReprAttr, SanitizerSet, + AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr, + MirDialect, MirPhase, ReprAttr, SanitizerSet, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; @@ -506,7 +506,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_eii_impl(&self, impls: &[EiiImpl], target: Target) { - for EiiImpl { span, inner_span, eii_macro, impl_marked_unsafe, is_default: _ } in impls { + for EiiImpl { span, inner_span, resolution, impl_marked_unsafe, is_default: _ } in impls { match target { Target::Fn => {} _ => { @@ -514,7 +514,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if find_attr!(self.tcx.get_all_attrs(*eii_macro), AttributeKind::EiiExternTarget(EiiDecl { impl_unsafe, .. }) if *impl_unsafe) + if let EiiImplResolution::Macro(eii_macro) = resolution + && 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 { @@ -758,9 +759,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { 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 { + let name = match i.resolution { + EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), + EiiImplResolution::Known(_, name) => name, + EiiImplResolution::Error(_eg) => continue, + }; self.dcx().emit_err(errors::EiiWithTrackCaller { attr_span, - name: self.tcx.item_name(i.eii_macro), + name, sig_span: sig.span, }); } diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index ab3f9f0d2182..7d6edb694d4b 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -81,7 +81,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } // 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 { + for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); let mut explicit_impls = Vec::new(); @@ -97,7 +97,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): // is instantly an error. if explicit_impls.len() > 1 { tcx.dcx().emit_err(DuplicateEiiImpls { - name: tcx.item_name(decl_did), + name: tcx.item_name(foreign_item), 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), @@ -116,7 +116,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } if default_impls.len() > 1 { - let decl_span = tcx.def_ident_span(decl_did).unwrap(); + let decl_span = tcx.def_ident_span(foreign_item).unwrap(); tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now"); } @@ -139,7 +139,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): 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), + // FIXME: shouldn't call `item_name` + name: tcx.item_name(foreign_item), span: decl.span, help: (), }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b4941a6f5b99..f64bd4a1aa19 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1069,8 +1069,20 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc 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); + for EiiImpl { node_id, eii_macro_path, known_eii_macro_resolution, .. } in &f.eii_impls + { + // See docs on the `known_eii_macro_resolution` field: + // if we already know the resolution statically, don't bother resolving it. + if let Some(target) = known_eii_macro_resolution { + self.smart_resolve_path( + *node_id, + &None, + &target.extern_item_path, + PathSource::Expr(None), + ); + } else { + self.smart_resolve_path(*node_id, &None, &eii_macro_path, PathSource::Macro); + } } } From 5ddda0c37bae5d6867d04ed5be5dae5729df7bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 16:43:24 +0100 Subject: [PATCH 297/340] fix up diagnostics referring to the right items --- compiler/rustc_ast/src/ast.rs | 3 +-- compiler/rustc_ast_lowering/src/item.rs | 21 ++++++++++--------- compiler/rustc_builtin_macros/src/eii.rs | 8 +------ .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 4 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_metadata/src/eii.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/eii.rs | 8 ++++--- compiler/rustc_resolve/src/late.rs | 2 +- tests/ui/eii/privacy2.stderr | 8 +++---- 11 files changed, 29 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6d3cea95e77d..fb2ccefe12a1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2117,10 +2117,9 @@ pub struct MacroDef { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] pub struct EiiExternTarget { - /// path to the extern item we're targetting + /// path to the extern item we're targeting pub extern_item_path: Path, pub impl_unsafe: bool, - pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4b7995aa079e..3a7308ef7c97 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -137,12 +137,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_eii_extern_target( &mut self, id: NodeId, - EiiExternTarget { extern_item_path, impl_unsafe, span }: &EiiExternTarget, + eii_name: Ident, + EiiExternTarget { extern_item_path, impl_unsafe }: &EiiExternTarget, ) -> Option { self.lower_path_simple_eii(id, extern_item_path).map(|did| EiiDecl { eii_extern_target: did, impl_unsafe: *impl_unsafe, - span: self.lower_span(*span), + name: eii_name, }) } @@ -159,13 +160,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }: &EiiImpl, ) -> hir::attrs::EiiImpl { let resolution = if let Some(target) = known_eii_macro_resolution - && let Some(decl) = self.lower_eii_extern_target(*node_id, target) - { - EiiImplResolution::Known( - decl, + && let Some(decl) = self.lower_eii_extern_target( + *node_id, // the expect is ok here since we always generate this path in the eii macro. - eii_macro_path.segments.last().expect("at least one segment").ident.name, - ) + eii_macro_path.segments.last().expect("at least one segment").ident, + target, + ) { + EiiImplResolution::Known(decl) } else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) { EiiImplResolution::Macro(macro_did) } else { @@ -195,8 +196,8 @@ impl<'hir> LoweringContext<'_, 'hir> { eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] } - ItemKind::MacroDef(_, MacroDef { eii_extern_target: Some(target), .. }) => self - .lower_eii_extern_target(id, target) + ItemKind::MacroDef(name, MacroDef { eii_extern_target: Some(target), .. }) => self + .lower_eii_extern_target(id, *name, target) .map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(decl))]) .unwrap_or_default(), diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 5105cdacd186..ff24eba217df 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -103,8 +103,6 @@ fn eii_( // span of the declaring item without attributes let item_span = func.sig.span; - // span of the eii attribute and the item below it, i.e. the full declaration - let decl_span = eii_attr_span.to(item_span); let foreign_item_name = func.ident; let mut return_items = Vec::new(); @@ -134,7 +132,6 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, - decl_span, ))); return_items.into_iter().map(wrap_item).collect() @@ -213,7 +210,6 @@ fn generate_default_impl( known_eii_macro_resolution: Some(ast::EiiExternTarget { extern_item_path: ast::Path::from_ident(foreign_item_name), impl_unsafe, - span: item_span, }), }); @@ -359,7 +355,6 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, - decl_span: Span, ) -> ast::Item { let mut macro_attrs = ThinVec::new(); @@ -401,7 +396,6 @@ fn generate_attribute_macro_to_implement( eii_extern_target: Some(ast::EiiExternTarget { extern_item_path: ast::Path::from_ident(foreign_item_name), impl_unsafe, - span: decl_span, }), }, ), @@ -458,7 +452,7 @@ pub(crate) fn eii_extern_target( false }; - d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span }); + d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe }); // Return the original item and the new methods. vec![item] diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8b8abfeb6a4f..7dda824e2b18 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -301,7 +301,7 @@ fn process_builtin_attrs( }; extern_item } - EiiImplResolution::Known(decl, _) => decl.eii_extern_target, + EiiImplResolution::Known(decl) => decl.eii_extern_target, EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5b2d73faef19..23201eff455f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -27,7 +27,7 @@ pub enum EiiImplResolution { Macro(DefId), /// Sometimes though, we already know statically and can skip some name resolution. /// Stored together with the eii's name for diagnostics. - Known(EiiDecl, Symbol), + Known(EiiDecl), /// For when resolution failed, but we want to continue compilation Error(ErrorGuaranteed), } @@ -46,7 +46,7 @@ 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, + pub name: Ident, } #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index cefd8c8f1443..7ec4110f80b9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1213,7 +1213,7 @@ fn check_eiis(tcx: TyCtxt<'_>, def_id: LocalDefId) { continue; } } - EiiImplResolution::Known(decl, name) => (decl.eii_extern_target, *name), + EiiImplResolution::Known(decl) => (decl.eii_extern_target, decl.name.name), EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_metadata/src/eii.rs b/compiler/rustc_metadata/src/eii.rs index 425de9e62e50..b06ac8481397 100644 --- a/compiler/rustc_metadata/src/eii.rs +++ b/compiler/rustc_metadata/src/eii.rs @@ -40,7 +40,7 @@ pub(crate) fn collect<'tcx>(tcx: TyCtxt<'tcx>, LocalCrate: LocalCrate) -> EiiMap }; decl } - EiiImplResolution::Known(decl, _) => decl, + EiiImplResolution::Known(decl) => decl, EiiImplResolution::Error(_eg) => continue, }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5b3bdc07ec94..2d3c5c7e48a0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -761,7 +761,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for i in impls { let name = match i.resolution { EiiImplResolution::Macro(def_id) => self.tcx.item_name(def_id), - EiiImplResolution::Known(_, name) => name, + EiiImplResolution::Known(decl) => decl.name.name, EiiImplResolution::Error(_eg) => continue, }; self.dcx().emit_err(errors::EiiWithTrackCaller { diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 7d6edb694d4b..7c2c98920623 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -80,6 +80,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } } + println!("{eiis:#?}"); + // now we have all eiis! For each of them, choose one we want to actually generate. for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); @@ -97,7 +99,7 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): // is instantly an error. if explicit_impls.len() > 1 { tcx.dcx().emit_err(DuplicateEiiImpls { - name: tcx.item_name(foreign_item), + name: decl.name.name, 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), @@ -140,8 +142,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): current_crate_name: tcx.crate_name(LOCAL_CRATE), decl_crate_name: tcx.crate_name(decl_crate), // FIXME: shouldn't call `item_name` - name: tcx.item_name(foreign_item), - span: decl.span, + name: decl.name.name, + span: decl.name.span, help: (), }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f64bd4a1aa19..32cf57af2e7f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2929,7 +2929,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } - if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _, span: _ }) = + if let Some(EiiExternTarget { extern_item_path, impl_unsafe: _ }) = ¯o_def.eii_extern_target { self.smart_resolve_path( diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 0d44604567e4..903285d4d1e3 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -17,18 +17,18 @@ LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/codegen3.rs:9:1 + --> $DIR/auxiliary/codegen3.rs:9:7 | LL | #[eii(eii2)] - | ^^^^^^^^^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | ^^^^ 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 + --> $DIR/auxiliary/codegen3.rs:13:11 | LL | #[eii(eii3)] - | ^^^^^^^^^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii3]` was declared here in crate `codegen3` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies From 52b3ac476c78224a1d35d3857d24413fdfb89138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 18:43:16 +0100 Subject: [PATCH 298/340] trick with super imports that fixes nameres in anonymous modules --- compiler/rustc_builtin_macros/src/eii.rs | 71 ++++++++++++++++++++++-- compiler/rustc_passes/src/eii.rs | 2 - 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index ff24eba217df..2d67608609e3 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -109,6 +109,7 @@ fn eii_( if func.body.is_some() { return_items.push(Box::new(generate_default_impl( + ecx, &func, impl_unsafe, macro_name, @@ -185,6 +186,7 @@ fn filter_attrs_for_multiple_eii_attr( } fn generate_default_impl( + ecx: &mut ExtCtxt<'_>, func: &ast::Fn, impl_unsafe: bool, macro_name: Ident, @@ -208,7 +210,18 @@ fn generate_default_impl( span: eii_attr_span, is_default: true, known_eii_macro_resolution: Some(ast::EiiExternTarget { - extern_item_path: ast::Path::from_ident(foreign_item_name), + extern_item_path: ast::Path { + span: foreign_item_name.span, + segments: thin_vec![ + ast::PathSegment { + ident: Ident::from_str_and_span("super", foreign_item_name.span,), + id: DUMMY_NODE_ID, + args: None + }, + ast::PathSegment { ident: foreign_item_name, id: DUMMY_NODE_ID, args: None }, + ], + tokens: None, + }, impl_unsafe, }), }); @@ -239,18 +252,66 @@ fn generate_default_impl( stmts: thin_vec![ast::Stmt { id: DUMMY_NODE_ID, kind: ast::StmtKind::Item(Box::new(ast::Item { - attrs, + attrs: ThinVec::new(), id: DUMMY_NODE_ID, span: item_span, vis: ast::Visibility { - span: eii_attr_span, + span: item_span, kind: ast::VisibilityKind::Inherited, tokens: None }, - kind: ItemKind::Fn(Box::new(default_func)), + kind: ItemKind::Mod( + ast::Safety::Default, + Ident::from_str_and_span("dflt", item_span), + ast::ModKind::Loaded( + thin_vec![ + Box::new(ast::Item { + attrs: thin_vec![ecx.attr_nested_word( + sym::allow, + sym::unused_imports, + item_span + ),], + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span: eii_attr_span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Use(ast::UseTree { + prefix: ast::Path::from_ident( + Ident::from_str_and_span( + "super", item_span, + ) + ), + kind: ast::UseTreeKind::Glob, + span: item_span, + }), + tokens: None, + }), + Box::new(ast::Item { + attrs, + id: DUMMY_NODE_ID, + span: item_span, + vis: ast::Visibility { + span: eii_attr_span, + kind: ast::VisibilityKind::Inherited, + tokens: None + }, + kind: ItemKind::Fn(Box::new(default_func)), + tokens: None, + }), + ], + ast::Inline::Yes, + ast::ModSpans { + inner_span: item_span, + inject_use_span: item_span, + } + ) + ), tokens: None, })), - span: eii_attr_span + span: eii_attr_span, }], id: DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 7c2c98920623..f3e84665f21d 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -80,8 +80,6 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } } - println!("{eiis:#?}"); - // now we have all eiis! For each of them, choose one we want to actually generate. for (foreign_item, FoundEii { decl, decl_crate, impls }) in eiis { let mut default_impls = Vec::new(); From 7791bc22133cce1693b364f76e99416b50f4d348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 8 Jan 2026 18:44:56 +0100 Subject: [PATCH 299/340] mark ICE regression test as fixed --- tests/ui/eii/duplicate/eii_conflict_with_macro.rs | 1 + tests/ui/eii/privacy2.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs index deee2346552f..d8118f8417a0 100644 --- a/tests/ui/eii/duplicate/eii_conflict_with_macro.rs +++ b/tests/ui/eii/duplicate/eii_conflict_with_macro.rs @@ -1,4 +1,5 @@ //@ compile-flags: --crate-type rlib +//@ build-pass #![feature(extern_item_impls)] macro_rules! foo_impl { () => {} } diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index a4ae188bd0ec..a0bc26ef629b 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,5 +1,5 @@ //@ aux-build:codegen3.rs -// Tests whether name resulution respects privacy properly. +// Tests whether name resolution respects privacy properly. #![feature(extern_item_impls)] extern crate codegen3 as codegen; From 025ac8f512f8c90e4ba02d69e98851e7a4bdb999 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 9 Jan 2026 08:37:01 +0000 Subject: [PATCH 300/340] The aarch64-unknown-none target requires NEON, so the docs were wrong. --- src/doc/rustc/src/platform-support/aarch64-unknown-none.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md index 3d776677d23e..5d1201bbf426 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -29,14 +29,15 @@ You may prefer the `-softfloat` target when writing a kernel or interfacing with pre-compiled binaries that use the soft-float ABI. When using the hardfloat targets, the minimum floating-point features assumed -are those of the `fp-armv8`, which excludes NEON SIMD support. If your +are [`FEAT_AdvSIMD`][feat-advsimd], which means NEON SIMD support. If your processor supports a different set of floating-point features than the default -expectations of `fp-armv8`, then these should also be enabled or disabled as -needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or +expectations of `FEAT_AdvSIMD`, then these should also be enabled or disabled +as needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or LLVM) that you have a specific model of Arm processor, using the [`-Ctarget-cpu`][target-cpu] option. Doing so may change the default set of target-features enabled. +[feat-advsimd]: https://developer.arm.com/documentation/109697/2025_12/Feature-descriptions/The-Armv8-0-architecture-extension?lang=en [target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu [target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature From a3690a2d25d564df5b86742a5be3bb0799a27926 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 8 Jan 2026 19:08:01 +0100 Subject: [PATCH 301/340] Make Clippy compile with `ConstArgKind::Tup()` --- src/tools/clippy/clippy_lints/src/large_include_file.rs | 1 - src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 1 + src/tools/clippy/clippy_utils/src/hir_utils.rs | 8 ++++++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index d77e0beeaf4c..54599499515e 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -1,4 +1,3 @@ -use rustc_ast::AttrItemKind; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 58b153f06545..acea701b2e83 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -323,6 +323,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), + ConstArgKind::Tup(..) => chain!(self, "let ConstArgKind::Tup(..) = {const_arg}.kind"), ConstArgKind::Literal(..) => chain!(self, "let ConstArgKind::Literal(..) = {const_arg}.kind") } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 334cc6bb5d55..e4f76cf4ed57 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1141,6 +1141,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) + | ConstArgKind::Tup(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 73b1cbb21548..82a12fc51c9a 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -666,6 +666,8 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -695,6 +697,7 @@ impl HirEqInterExpr<'_, '_, '_> { // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) + | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Tup(..) @@ -1561,6 +1564,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) { match &const_arg.kind { + ConstArgKind::Tup(tup) => { + for arg in *tup { + self.hash_const_arg(*arg); + } + }, ConstArgKind::Path(path) => self.hash_qpath(path), ConstArgKind::Anon(anon) => self.hash_body(anon.body), ConstArgKind::Struct(path, inits) => { From d28379895b67641408adad95dc69d1e45f1a8a1b Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 10:39:33 +0100 Subject: [PATCH 302/340] Update Cargo.lock --- Cargo.lock | 52 +++++----------------------------------------------- 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1bf48f704ab..9c791babc399 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,19 +182,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive 0.14.0", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - [[package]] name = "askama" version = "0.15.1" @@ -208,30 +195,13 @@ dependencies = [ "serde_json", ] -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser 0.14.0", - "basic-toml", - "memchr", - "proc-macro2", - "quote", - "rustc-hash 2.1.1", - "serde", - "serde_derive", - "syn 2.0.110", -] - [[package]] name = "askama_derive" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994" dependencies = [ - "askama_parser 0.15.1", + "askama_parser", "basic-toml", "memchr", "proc-macro2", @@ -248,19 +218,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46" dependencies = [ - "askama_derive 0.15.1", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "serde", - "serde_derive", - "winnow 0.7.13", + "askama_derive", ] [[package]] @@ -675,7 +633,7 @@ name = "clippy" version = "0.1.94" dependencies = [ "anstream", - "askama 0.14.0", + "askama", "cargo_metadata 0.18.1", "clippy_config", "clippy_lints", @@ -1566,7 +1524,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "askama 0.15.1", + "askama", "cargo_metadata 0.21.0", "serde", "serde_json", @@ -4913,7 +4871,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", - "askama 0.15.1", + "askama", "base64", "expect-test", "indexmap", From b9ae4f7bf7dc4f4a7c8a8cc934522093d6868bf7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 9 Jan 2026 08:55:02 +0100 Subject: [PATCH 303/340] rustdoc_json: Remove one call to `std::mem::take` in `after_krate`. This patch removes one call to `std::mem::take` to save two `memcpy`s: `JsonRenderer::index` can be quite large as noted https://github.com/rust-lang/rust/pull/142335. `self.index` can be passed directly to `types::Crate`. This removal makes `self` immutable. The private `serialize_and_write` method is moved as a function: the `self` argument is replaced by `sess: &Session`. This `&Session` was fetched earlier in `after_krate` in all cases. This change allows to call `serialize_and_write` after `output_crate` is created, without having a conflict around the move of `self`: the borrow checker is now happy. --- src/librustdoc/json/mod.rs | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 37d456ae796b..a201f661d9f7 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -104,22 +104,6 @@ impl<'tcx> JsonRenderer<'tcx> { }) .unwrap_or_default() } - - fn serialize_and_write( - &self, - output_crate: types::Crate, - mut writer: BufWriter, - path: &str, - ) -> Result<(), Error> { - self.sess().time("rustdoc_json_serialize_and_write", || { - try_err!( - serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()), - path - ); - try_err!(writer.flush(), path); - Ok(()) - }) - } } impl<'tcx> JsonRenderer<'tcx> { @@ -252,26 +236,23 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { unreachable!("RUN_ON_MODULE = false, should never call mod_item_in") } - fn after_krate(mut self) -> Result<(), Error> { + fn after_krate(self) -> Result<(), Error> { debug!("Done with crate"); let e = ExternalCrate { crate_num: LOCAL_CRATE }; - - // We've finished using the index, and don't want to clone it, because it is big. - let index = std::mem::take(&mut self.index); + let sess = self.sess(); // Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for // multiple targets: https://github.com/rust-lang/rust/pull/137632 // // We want to describe a single target, so pass tcx.sess rather than tcx. - let target = conversions::target(self.tcx.sess); + let target = conversions::target(sess); debug!("Constructing Output"); let output_crate = types::Crate { root: self.id_from_item_default(e.def_id().into()), crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, - index, paths: self .cache .paths @@ -313,6 +294,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), + // Be careful to not clone the `index`, it is big. + index: self.index, target, format_version: types::FORMAT_VERSION, }; @@ -323,17 +306,34 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap()); p.set_extension("json"); - self.serialize_and_write( + serialize_and_write( + sess, output_crate, try_err!(File::create_buffered(&p), p), &p.display().to_string(), ) } else { - self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "") + serialize_and_write(sess, output_crate, BufWriter::new(stdout().lock()), "") } } } +fn serialize_and_write( + sess: &Session, + output_crate: types::Crate, + mut writer: BufWriter, + path: &str, +) -> Result<(), Error> { + sess.time("rustdoc_json_serialize_and_write", || { + try_err!( + serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()), + path + ); + try_err!(writer.flush(), path); + Ok(()) + }) +} + // Some nodes are used a lot. Make sure they don't unintentionally get bigger. // // These assertions are here, not in `src/rustdoc-json-types/lib.rs` where the types are defined, From 330358a197e1a6df060a19ccb3b69f29006ba395 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Fri, 9 Jan 2026 11:59:23 +0100 Subject: [PATCH 304/340] Further Clippy fixes for Tup/Literal ConstArgKind --- src/tools/clippy/clippy_utils/src/consts.rs | 1 + .../clippy/clippy_utils/src/hir_utils.rs | 23 ++++--------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index e4f76cf4ed57..538f1fd2628c 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1142,6 +1142,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), ConstArgKind::Struct(..) | ConstArgKind::Tup(..) + | ConstArgKind::Literal(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 82a12fc51c9a..0bb641568879 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -666,8 +666,9 @@ impl HirEqInterExpr<'_, '_, '_> { } match (&left.kind, &right.kind) { - (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => - l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)), + (ConstArgKind::Tup(l_t), ConstArgKind::Tup(r_t)) => { + l_t.len() == r_t.len() && l_t.iter().zip(*r_t).all(|(l_c, r_c)| self.eq_const_arg(*l_c, *r_c)) + }, (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, @@ -684,23 +685,14 @@ impl HirEqInterExpr<'_, '_, '_> { .iter() .zip(*args_b) .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - } - (ConstArgKind::Tup(args_a), ConstArgKind::Tup(args_b)) => { - args_a - .iter() - .zip(*args_b) - .all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b)) - }, - (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => { - kind_l == kind_r }, + (ConstArgKind::Literal(kind_l), ConstArgKind::Literal(kind_r)) => kind_l == kind_r, // Use explicit match for now since ConstArg is undergoing flux. ( ConstArgKind::Path(..) | ConstArgKind::Tup(..) | ConstArgKind::Anon(..) | ConstArgKind::TupleCall(..) - | ConstArgKind::Tup(..) | ConstArgKind::Infer(..) | ConstArgKind::Struct(..) | ConstArgKind::Literal(..) @@ -1583,13 +1575,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(arg); } }, - ConstArgKind::Tup(args) => { - for arg in *args { - self.hash_const_arg(arg); - } - }, ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, - ConstArgKind::Literal(lit) => lit.hash(&mut self.s) + ConstArgKind::Literal(lit) => lit.hash(&mut self.s), } } From fb296d7a04ba42e723aa082d4ef9f96105dd1da0 Mon Sep 17 00:00:00 2001 From: Asger Hautop Drewsen Date: Fri, 9 Jan 2026 12:52:25 +0100 Subject: [PATCH 305/340] Use f64 NaN in documentation instead of sqrt(-1.0) --- library/core/src/cmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index feb9c4319604..d61e1071db8b 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1186,7 +1186,7 @@ pub macro Ord($item:item) { /// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` -/// let a = f64::sqrt(-1.0); +/// let a = f64::NAN; /// assert_eq!(a <= a, false); /// ``` /// From 87d716701e83e39a0c9416ca1c54e14b66202260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:35:15 +0100 Subject: [PATCH 306/340] Reenable GCC CI download --- src/ci/run.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 425ad38a6655..b486f0525f40 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -187,9 +187,8 @@ else RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp" fi - # Download GCC from CI on test builders (temporarily disabled because the CI gcc component - # was renamed). - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=false" + # Download GCC from CI on test builders + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true" # download-rustc seems to be broken on CI after the stage0 redesign # Disable it until these issues are debugged and resolved From 58a9fdded8b4f38dfb88da3793bf5750bb136ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:36:24 +0100 Subject: [PATCH 307/340] Bump `download-ci-gcc-stamp` --- src/bootstrap/download-ci-gcc-stamp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/download-ci-gcc-stamp b/src/bootstrap/download-ci-gcc-stamp index bbe26afc9526..ec8d0fa3135d 100644 --- a/src/bootstrap/download-ci-gcc-stamp +++ b/src/bootstrap/download-ci-gcc-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-gcc` configuration download a new version of GCC from CI, even if the GCC submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/138051 +Last change is for: https://github.com/rust-lang/rust/pull/150873 From 5af08c0c28c97f03e2d89356cfd6d569dd18d24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:40:54 +0100 Subject: [PATCH 308/340] Ignore `rustc-src-gpl` in fast try builds --- src/tools/opt-dist/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index b17cfb567e5b..b52dab001ef5 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -450,6 +450,7 @@ fn main() -> anyhow::Result<()> { "rust-docs-json", "rust-analyzer", "rustc-src", + "rustc-src-gpl", "extended", "clippy", "miri", From 01e8f14867ec14591aa73269c8744cbbe9f69645 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Jan 2026 15:03:33 +0100 Subject: [PATCH 309/340] Mention that `rustc_codegen_gcc` is a subtree in `rustc-dev-guide` --- src/doc/rustc-dev-guide/src/external-repos.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/external-repos.md b/src/doc/rustc-dev-guide/src/external-repos.md index d2b4e791df0e..c43c1f680acf 100644 --- a/src/doc/rustc-dev-guide/src/external-repos.md +++ b/src/doc/rustc-dev-guide/src/external-repos.md @@ -22,6 +22,7 @@ The following external projects are managed using some form of a `subtree`: * [rustfmt](https://github.com/rust-lang/rustfmt) * [rust-analyzer](https://github.com/rust-lang/rust-analyzer) * [rustc_codegen_cranelift](https://github.com/rust-lang/rustc_codegen_cranelift) +* [rustc_codegen_gcc](https://github.com/rust-lang/rustc_codegen_gcc) * [rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide) * [compiler-builtins](https://github.com/rust-lang/compiler-builtins) * [stdarch](https://github.com/rust-lang/stdarch) @@ -40,6 +41,7 @@ implement a new tool feature or test, that should happen in one collective rustc * `portable-simd` ([sync script](https://github.com/rust-lang/portable-simd/blob/master/subtree-sync.sh)) * `rustfmt` * `rustc_codegen_cranelift` ([sync script](https://github.com/rust-lang/rustc_codegen_cranelift/blob/113af154d459e41b3dc2c5d7d878e3d3a8f33c69/scripts/rustup.sh#L7)) + * `rustc_codegen_gcc` ([sync guide](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/doc/subtree.md)) * Using the [josh](#synchronizing-a-josh-subtree) tool * `miri` * `rust-analyzer` From 47f28fc71e03e968fc3bcdab8d3a2155698fa36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 14:54:59 +0100 Subject: [PATCH 310/340] Refactor artifact keep mode in bootstrap --- src/bootstrap/src/core/build_steps/check.rs | 51 ++++++++++-- src/bootstrap/src/core/build_steps/clippy.rs | 15 ++-- src/bootstrap/src/core/build_steps/compile.rs | 77 +++++++++++-------- src/bootstrap/src/core/build_steps/test.rs | 5 +- 4 files changed, 97 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 7da2551c76fe..f983c59f9bf8 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -4,7 +4,8 @@ use std::fs; use std::path::{Path, PathBuf}; use crate::core::build_steps::compile::{ - add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, + ArtifactKeepMode, add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, + std_crates_for_run_make, }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ @@ -111,8 +112,7 @@ impl Step for Std { builder.config.free_args.clone(), &check_stamp, vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); drop(_guard); @@ -148,7 +148,14 @@ impl Step for Std { build_compiler, target, ); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); check_stamp } @@ -368,7 +375,14 @@ impl Step for Rustc { let stamp = build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); stamp } @@ -568,7 +582,14 @@ impl Step for CraneliftCodegenBackend { ) .with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } fn metadata(&self) -> Option { @@ -639,7 +660,14 @@ impl Step for GccCodegenBackend { ) .with_prefix("check"); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } fn metadata(&self) -> Option { @@ -777,7 +805,14 @@ fn run_tool_check_step( .with_prefix(&format!("{display_name}-check")); let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + run_cargo( + builder, + cargo, + builder.config.free_args.clone(), + &stamp, + vec![], + ArtifactKeepMode::OnlyRmeta, + ); } tool_check_step!(Rustdoc { diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 085c2d952e30..9e5bfd2e60e9 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -15,7 +15,7 @@ use build_helper::exit; -use super::compile::{run_cargo, rustc_cargo, std_cargo}; +use super::compile::{ArtifactKeepMode, run_cargo, rustc_cargo, std_cargo}; use super::tool::{SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check}; @@ -214,8 +214,7 @@ impl Step for Std { lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), &build_stamp::libstd_stamp(builder, build_compiler, target), vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); } @@ -309,8 +308,7 @@ impl Step for Rustc { lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), &build_stamp::librustc_stamp(builder, build_compiler, target), vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta, ); } @@ -380,7 +378,7 @@ impl Step for CodegenGcc { .with_prefix("rustc_codegen_gcc-check"); let args = lint_args(builder, &self.config, &[]); - run_cargo(builder, cargo, args.clone(), &stamp, vec![], true, false); + run_cargo(builder, cargo, args.clone(), &stamp, vec![], ArtifactKeepMode::OnlyRmeta); // Same but we disable the features enabled by default. let mut cargo = prepare_tool_cargo( @@ -396,7 +394,7 @@ impl Step for CodegenGcc { 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); + run_cargo(builder, cargo, args, &stamp, vec![], ArtifactKeepMode::OnlyRmeta); } fn metadata(&self) -> Option { @@ -478,8 +476,7 @@ macro_rules! lint_any { lint_args(builder, &self.config, &[]), &stamp, vec![], - true, - false, + ArtifactKeepMode::OnlyRmeta ); } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 02be3f2cc735..2808c29cc6c0 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -296,8 +296,11 @@ impl Step for Std { vec![], &stamp, target_deps, - self.is_for_mir_opt_tests, // is_check - false, + if self.is_for_mir_opt_tests { + ArtifactKeepMode::OnlyRmeta + } else { + ArtifactKeepMode::OnlyRlib + }, ); builder.ensure(StdLink::from_std( @@ -1167,14 +1170,28 @@ impl Step for Rustc { target, ); let stamp = build_stamp::librustc_stamp(builder, build_compiler, target); + run_cargo( builder, cargo, vec![], &stamp, vec![], - false, - true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files. + ArtifactKeepMode::Custom(Box::new(|filename| { + if filename.contains("jemalloc_sys") + || filename.contains("rustc_public_bridge") + || filename.contains("rustc_public") + { + // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so, + // so we need to distribute them as rlib to be able to use them. + filename.ends_with(".rlib") + } else { + // Distribute the rest of the rustc crates as rmeta files only to reduce + // the tarball sizes by about 50%. The object files are linked into + // librustc_driver.so, so it is still possible to link against them. + filename.ends_with(".rmeta") + } + })), ); let target_root_dir = stamp.path().parent().unwrap(); @@ -1714,7 +1731,7 @@ impl Step for GccCodegenBackend { let _guard = builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host); - let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); GccCodegenBackendOutput { stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), @@ -1790,7 +1807,7 @@ impl Step for CraneliftCodegenBackend { build_compiler, target, ); - let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let files = run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); write_codegen_backend_stamp(stamp, files, builder.config.dry_run()) } @@ -2620,14 +2637,26 @@ pub fn add_to_sysroot( } } +/// Specifies which rlib/rmeta artifacts outputted by Cargo should be put into the resulting +/// build stamp, and thus be included in dist archives and copied into sysroots by default. +/// Note that some kinds of artifacts are copied automatically (e.g. native libraries). +pub enum ArtifactKeepMode { + /// Only keep .rlib files, ignore .rmeta files + OnlyRlib, + /// Only keep .rmeta files, ignore .rlib files + OnlyRmeta, + /// Custom logic for keeping an artifact + /// It receives the filename of an artifact, and returns true if it should be kept. + Custom(Box bool>), +} + pub fn run_cargo( builder: &Builder<'_>, cargo: Cargo, tail_args: Vec, stamp: &BuildStamp, additional_target_deps: Vec<(PathBuf, DependencyType)>, - is_check: bool, - rlib_only_metadata: bool, + artifact_keep_mode: ArtifactKeepMode, ) -> Vec { // `target_root_dir` looks like $dir/$target/release let target_root_dir = stamp.path().parent().unwrap(); @@ -2661,36 +2690,20 @@ pub fn run_cargo( }; for filename in filenames_vec { // Skip files like executables - let mut keep = false; - if filename.ends_with(".lib") + let keep = if filename.ends_with(".lib") || filename.ends_with(".a") || is_debug_info(&filename) || is_dylib(Path::new(&*filename)) { // Always keep native libraries, rust dylibs and debuginfo - keep = true; - } - if is_check && filename.ends_with(".rmeta") { - // During check builds we need to keep crate metadata - keep = true; - } else if rlib_only_metadata { - if filename.contains("jemalloc_sys") - || filename.contains("rustc_public_bridge") - || filename.contains("rustc_public") - { - // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so, - // so we need to distribute them as rlib to be able to use them. - keep |= filename.ends_with(".rlib"); - } else { - // Distribute the rest of the rustc crates as rmeta files only to reduce - // the tarball sizes by about 50%. The object files are linked into - // librustc_driver.so, so it is still possible to link against them. - keep |= filename.ends_with(".rmeta"); - } + true } else { - // In all other cases keep all rlibs - keep |= filename.ends_with(".rlib"); - } + match &artifact_keep_mode { + ArtifactKeepMode::OnlyRlib => filename.ends_with(".rlib"), + ArtifactKeepMode::OnlyRmeta => filename.ends_with(".rmeta"), + ArtifactKeepMode::Custom(func) => func(&filename), + } + }; if !keep { continue; diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7d7cfccf54e6..f3a1c6b0e3dd 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -14,7 +14,7 @@ use std::{env, fs, iter}; use build_helper::exit; -use crate::core::build_steps::compile::{Std, run_cargo}; +use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo}; use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler}; use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; @@ -2587,7 +2587,8 @@ impl BookTest { let stamp = BuildStamp::new(&builder.cargo_out(test_compiler, mode, target)) .with_prefix(PathBuf::from(dep).file_name().and_then(|v| v.to_str()).unwrap()); - let output_paths = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); + let output_paths = + run_cargo(builder, cargo, vec![], &stamp, vec![], ArtifactKeepMode::OnlyRlib); let directories = output_paths .into_iter() .filter_map(|p| p.parent().map(ToOwned::to_owned)) From e0324b527e2ca5976adb9d813df9e271f3402867 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:44:51 +0000 Subject: [PATCH 311/340] Emit an error for linking staticlibs on BPF Rather than panicking. --- compiler/rustc_codegen_ssa/messages.ftl | 2 ++ compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_codegen_ssa/src/errors.rs | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 1d87dc5da8d2..4875f309cca5 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -10,6 +10,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty +codegen_ssa_bpf_staticlib_not_supported = linking static libraries is not supported for BPF + codegen_ssa_cgu_not_recorded = CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index b47652092ed5..637d54dd06c6 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -2075,7 +2075,7 @@ impl<'a> Linker for BpfLinker<'a> { } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { - panic!("staticlibs not supported") + self.sess.dcx().emit_fatal(errors::BpfStaticlibNotSupported) } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 95306c140895..f57c37ca7929 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -713,6 +713,10 @@ pub struct UnknownArchiveKind<'a> { pub kind: &'a str, } +#[derive(Diagnostic)] +#[diag(codegen_ssa_bpf_staticlib_not_supported)] +pub(crate) struct BpfStaticlibNotSupported; + #[derive(Diagnostic)] #[diag(codegen_ssa_multiple_main_functions)] #[help] From 90c84d0aaea127743b248552c8ab793f5c0f9429 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:45:25 +0000 Subject: [PATCH 312/340] Reduce visibility of some errors --- compiler/rustc_codegen_ssa/src/back/archive.rs | 7 ++++--- compiler/rustc_codegen_ssa/src/errors.rs | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 93f6cb3b87e6..3f12e857391b 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -22,10 +22,11 @@ use tracing::trace; use super::metadata::{create_compressed_metadata_file, search_for_section}; use crate::common; -// Re-exporting for rustc_codegen_llvm::back::archive -pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind}; +// Public for ArchiveBuilderBuilder::extract_bundled_libs +pub use crate::errors::ExtractBundledLibsError; use crate::errors::{ - DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile, + ArchiveBuildFailure, DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, + ErrorWritingDEFFile, UnknownArchiveKind, }; /// An item to be included in an import library. diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f57c37ca7929..39727685aec1 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -661,7 +661,7 @@ pub(crate) struct RlibArchiveBuildFailure { } #[derive(Diagnostic)] -// Public for rustc_codegen_llvm::back::archive +// Public for ArchiveBuilderBuilder::extract_bundled_libs pub enum ExtractBundledLibsError<'a> { #[diag(codegen_ssa_extract_bundled_libs_open_file)] OpenFile { rlib: &'a Path, error: Box }, @@ -700,16 +700,14 @@ pub(crate) struct UnsupportedLinkSelfContained; #[derive(Diagnostic)] #[diag(codegen_ssa_archive_build_failure)] -// Public for rustc_codegen_llvm::back::archive -pub struct ArchiveBuildFailure { +pub(crate) struct ArchiveBuildFailure { pub path: PathBuf, pub error: std::io::Error, } #[derive(Diagnostic)] #[diag(codegen_ssa_unknown_archive_kind)] -// Public for rustc_codegen_llvm::back::archive -pub struct UnknownArchiveKind<'a> { +pub(crate) struct UnknownArchiveKind<'a> { pub kind: &'a str, } From 2cde8d967a7b5b6dbec30cd18d8f7417e4e22d33 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Fri, 9 Jan 2026 09:44:39 -0500 Subject: [PATCH 313/340] Fix std::fs::copy on WASI by setting proper OpenOptions flags When PR #147572 switched WASI to use Unix-style filesystem APIs, the open_to_and_set_permissions function for WASI was implemented to call OpenOptions::new().open() without setting any access mode flags. This causes std::fs::copy to fail with the error: "must specify at least one of read, write, or append access" The fix is to explicitly set .write(true), .create(true), and .truncate(true) on the OpenOptions, matching the behavior of the non-WASI Unix implementation but without the permission handling that WASI doesn't support. Minimal reproduction: fn main() { std::fs::write("/src.txt", b"test").unwrap(); match std::fs::copy("/src.txt", "/dst.txt") { Ok(_) => println!("PASS: fs::copy works!"), Err(e) => println!("FAIL: {}", e), } } # Compile and run: rustc +nightly --target wasm32-wasip2 test.rs -o test.wasm wasmtime -S cli --dir . test.wasm # Before fix: FAIL: must specify at least one of read, write, or append access # After fix: PASS: fs::copy works! Note: The existing test library/std/src/fs/tests.rs::copy_file_ok would have caught this regression if the std test suite ran on WASI targets. Currently std tests don't compile for wasm32-wasip2 due to Unix-specific test code in library/std/src/sys/fd/unix/tests.rs. Fixes the regression introduced in nightly-2025-12-10. --- library/std/src/sys/fs/unix.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 327b0eb7468a..02f733c6e4c1 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2296,7 +2296,11 @@ fn open_to_and_set_permissions( _reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; - let writer = OpenOptions::new().open(to)?; + let writer = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(to)?; let writer_metadata = writer.metadata()?; Ok((writer, writer_metadata)) } From 642663596d87863521b708b9eabb5f7e63446600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 17:00:49 +0100 Subject: [PATCH 314/340] Fix unpacking of gcc-dev component --- src/bootstrap/src/core/download.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 43efdcd7db17..074404b4cdf3 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -396,7 +396,7 @@ impl Config { "; self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error); } - self.unpack(&tarball, root_dir, "gcc"); + self.unpack(&tarball, root_dir, "gcc-dev"); } } From 2a3932295e9ac167f8cd09dc08e86c46e94dbb50 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 16:15:39 +0000 Subject: [PATCH 315/340] Supress unused_parens lint for guard patterns --- compiler/rustc_lint/src/unused.rs | 2 ++ .../parens-around-guard-patterns-not-unused.rs | 13 +++++++++++++ tests/ui/reachable/guard_read_for_never.rs | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0ba54e3829f5..506a16355e22 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1190,6 +1190,8 @@ impl UnusedParens { // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume // that if there are unnecessary parens they serve a purpose of readability. PatKind::Range(..) => return, + // Parentheses may be necessary to disambiguate precedence in guard patterns. + PatKind::Guard(..) => return, // Avoid `p0 | .. | pn` if we should. PatKind::Or(..) if avoid_or => return, // Avoid `mut x` and `mut x @ p` if we should: diff --git a/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs b/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs new file mode 100644 index 000000000000..d5b8365ee612 --- /dev/null +++ b/tests/ui/lint/unused/unused_parens/parens-around-guard-patterns-not-unused.rs @@ -0,0 +1,13 @@ +//! Guard patterns require parentheses to disambiguate precedence +//! +//! Regression test for https://github.com/rust-lang/rust/issues/149594 + +//@ check-pass + +#![feature(guard_patterns)] +#![expect(incomplete_features)] +#![warn(unused_parens)] + +fn main() { + let (_ if false) = (); +} diff --git a/tests/ui/reachable/guard_read_for_never.rs b/tests/ui/reachable/guard_read_for_never.rs index 7061da635301..763dfd354b58 100644 --- a/tests/ui/reachable/guard_read_for_never.rs +++ b/tests/ui/reachable/guard_read_for_never.rs @@ -2,7 +2,7 @@ // //@ check-pass #![feature(guard_patterns, never_type)] -#![expect(incomplete_features, unused_parens)] +#![expect(incomplete_features)] #![deny(unreachable_code)] fn main() { From e275c2371649d145e4cfafc16b1b02ef37593e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 9 Jan 2026 17:46:49 +0100 Subject: [PATCH 316/340] Update bors email in CI postprocessing step --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb6bc325a3bb..8963039dd50b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -289,7 +289,7 @@ jobs: fi # Get closest bors merge commit - PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + PARENT_COMMIT=`git rev-list --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1` ./build/citool/debug/citool postprocess-metrics \ --job-name ${CI_JOB_NAME} \ From 43c1db7d5676ce023f873871cbf6b2c61f1e362d Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Fri, 9 Jan 2026 11:51:59 -0500 Subject: [PATCH 317/340] Run clippy --- library/std/src/sys/fs/unix.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 02f733c6e4c1..bb2ee6ae10ed 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2296,11 +2296,7 @@ fn open_to_and_set_permissions( _reader_metadata: &crate::fs::Metadata, ) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::OpenOptions; - let writer = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(to)?; + let writer = OpenOptions::new().write(true).create(true).truncate(true).open(to)?; let writer_metadata = writer.metadata()?; Ok((writer, writer_metadata)) } From fd59b32f8bf0a14451b390b4a7904c63252a56ad Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 10:40:25 +0530 Subject: [PATCH 318/340] std: sys: fs: uefi: Implement File::read Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..e12c7fb397d8 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -320,8 +320,8 @@ impl File { self.0.set_file_info(file_info) } - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - unsupported() + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { @@ -666,6 +666,19 @@ mod uefi_fs { Ok(p) } + pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut buf_size = buf.len(); + + let r = unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, buf.as_mut_ptr().cast()) }; + + if buf_size == 0 && r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + Ok(buf_size) + } + } + pub(crate) fn read_dir_entry(&self) -> io::Result>> { let file_ptr = self.protocol.as_ptr(); let mut buf_size = 0; From f6f901fa6d2f27a6a309505c9d56a7cb81dd2453 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 12:24:02 +0530 Subject: [PATCH 319/340] std: sys: fs: uefi: Implement File::{flush, *sync} - Make flush a noop since it is only for buffered writers. - Also forward fsync to datasync. UEFI does not have anything separate for metadata sync. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..3fec1ee9ae13 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -285,11 +285,11 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - unsupported() + self.datasync() } pub fn datasync(&self) -> io::Result<()> { - unsupported() + self.0.flush() } pub fn lock(&self) -> io::Result<()> { @@ -348,8 +348,9 @@ impl File { false } + // Write::flush is only meant for buffered writers. So should be noop for unbuffered files. pub fn flush(&self) -> io::Result<()> { - unsupported() + Ok(()) } pub fn seek(&self, _pos: SeekFrom) -> io::Result { @@ -744,6 +745,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + pub(crate) fn flush(&self) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).flush)(file_ptr) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn path(&self) -> &Path { &self.path } From 0401e792f470e1cb776c522da1fb4da47541b508 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 9 Jan 2026 13:49:17 -0500 Subject: [PATCH 320/340] Fix a trivial typo --- compiler/rustc_span/src/def_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 484e626d4638..a0ccf8d7e798 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -81,7 +81,7 @@ impl fmt::Display for CrateNum { /// because it depends on the set of crates in the entire crate graph of a /// compilation session. Again, using the same crate with a different version /// number would fix the issue with a high probability -- but that might be -/// easier said then done if the crates in questions are dependencies of +/// easier said than done if the crates in questions are dependencies of /// third-party crates. /// /// That being said, given a high quality hash function, the collision From 9d2ce878106ab85b2b098358ccd094a0cf7415c3 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 9 Jan 2026 20:42:01 +0100 Subject: [PATCH 321/340] Don't check `[mentions]` paths in submodules from tidy --- src/tools/tidy/src/triagebot.rs | 38 +++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index 59cd9d80b07a..a74d980cfcb7 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -2,11 +2,22 @@ use std::collections::HashSet; use std::path::Path; +use std::sync::LazyLock; use toml::Value; use crate::diagnostics::TidyCtx; +static SUBMODULES: LazyLock> = LazyLock::new(|| { + // WORKSPACES doesn't list all submodules but it's contains the main at least + crate::deps::WORKSPACES + .iter() + .map(|ws| ws.submodules.iter()) + .flatten() + .map(|p| Path::new(p)) + .collect() +}); + pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut check = tidy_ctx.start_check("triagebot"); let triagebot_path = path.join("triagebot.toml"); @@ -39,8 +50,13 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { if !full_path.exists() { // The full-path doesn't exists, maybe it's a glob, let's add it to the glob set builder // to be checked against all the file and directories in the repository. - builder.add(globset::Glob::new(&format!("{clean_path}*")).unwrap()); + let trimmed_path = clean_path.trim_end_matches('/'); + builder.add(globset::Glob::new(&format!("{trimmed_path}{{,/*}}")).unwrap()); glob_entries.push(clean_path.to_string()); + } else if is_in_submodule(Path::new(clean_path)) { + check.error(format!( + "triagebot.toml [mentions.*] '{clean_path}' cannot match inside a submodule" + )); } } @@ -49,8 +65,18 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut found = HashSet::new(); let mut matches = Vec::new(); + let cloned_path = path.to_path_buf(); + // Walk the entire repository and match any entry against the remaining paths - for entry in ignore::WalkBuilder::new(path).build().flatten() { + for entry in ignore::WalkBuilder::new(&path) + .filter_entry(move |entry| { + // Ignore entries inside submodules as triagebot cannot detect them + let entry_path = entry.path().strip_prefix(&cloned_path).unwrap(); + is_not_in_submodule(entry_path) + }) + .build() + .flatten() + { // Strip the prefix as mentions entries are always relative to the repo let entry_path = entry.path().strip_prefix(path).unwrap(); @@ -126,3 +152,11 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { } } } + +fn is_not_in_submodule(path: &Path) -> bool { + SUBMODULES.contains(&path) || !SUBMODULES.iter().any(|p| path.starts_with(*p)) +} + +fn is_in_submodule(path: &Path) -> bool { + !SUBMODULES.contains(&path) && SUBMODULES.iter().any(|p| path.starts_with(*p)) +} From 8e61f0de27b038e6bdb245e192aa2ae48c677523 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 9 Jan 2026 22:47:59 +0200 Subject: [PATCH 322/340] cg_llvm: add a pause to make comment less confusing --- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3ce28612ddfc..54ba671b09bc 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -153,7 +153,7 @@ impl CodegenCx<'_, '_> { return false; } - // With pie relocation model calls of functions defined in the translation + // With pie relocation model, calls of functions defined in the translation // unit can use copy relocations. if self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration { return true; From 229673ac85ef40dca4f2bbcb984cfd4d50a9b02d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Fri, 9 Jan 2026 22:49:32 +0200 Subject: [PATCH 323/340] make sentence more simple --- compiler/rustc_codegen_llvm/src/mono_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 54ba671b09bc..1878f4043ee8 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -111,7 +111,7 @@ impl CodegenCx<'_, '_> { } } - /// Whether a definition or declaration can be assumed to be local to a group of + /// 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. pub(crate) fn assume_dso_local(&self, llval: &llvm::Value, is_declaration: bool) -> bool { From f982bc6a2dd661dd5713a39e96d469c6309f3b2e Mon Sep 17 00:00:00 2001 From: Keith-Cancel Date: Thu, 8 Jan 2026 01:24:13 -0800 Subject: [PATCH 324/340] Fix ICE: can't type-check body of DefId, since type_consts don't have a body. Handling for inherent associated consts is missing elsewhere, remove so it can be handled later in that handling. Diagnostic not always be emitted on associated constant Add a test case and Fix for a different ICE I encountered. I noticed when trying various permuations of the test case code to see if I could find anymore ICEs. I did, but not one that I expected. So in the instances of the a named const not having any args, insantiate it directly. Since it is likely an inherent assocaiated const. Added tests. Centralize the is_type_const() logic. I also noticed basically the exact same check in other part the code. Const blocks can't be a type_const, therefore this check is uneeded. Fix comment spelling error. get_all_attrs is not valid to call for all DefIds it seems. Make sure that if the type is omitted for a type_const that we don't ICE. Co-Authored-By: Boxy --- .../src/check_consts/qualifs.rs | 12 +++------ .../rustc_hir_analysis/src/collect/type_of.rs | 17 +++++++++++- compiler/rustc_middle/src/ty/context.rs | 6 +++++ .../src/builder/expr/as_constant.rs | 10 ++++++- .../mgca/type_const-array-return.rs | 26 +++++++++++++++++++ .../type_const-inherent-const-omitted-type.rs | 12 +++++++++ ...e_const-inherent-const-omitted-type.stderr | 13 ++++++++++ .../type_const-only-in-impl-omitted-type.rs | 22 ++++++++++++++++ ...ype_const-only-in-impl-omitted-type.stderr | 16 ++++++++++++ .../mgca/type_const-recursive.rs | 8 ++++++ .../mgca/type_const-recursive.stderr | 11 ++++++++ .../ui/const-generics/mgca/type_const-use.rs | 13 ++++++++++ 12 files changed, 155 insertions(+), 11 deletions(-) create mode 100644 tests/ui/const-generics/mgca/type_const-array-return.rs create mode 100644 tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs create mode 100644 tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs create mode 100644 tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-recursive.rs create mode 100644 tests/ui/const-generics/mgca/type_const-recursive.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-use.rs diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 113e0d66c48a..02615e3bbc18 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -6,9 +6,7 @@ // having basically only two use-cases that act in different ways. use rustc_errors::ErrorGuaranteed; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::def::DefKind; -use rustc_hir::{LangItem, find_attr}; +use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::*; use rustc_middle::ty::{self, AdtDef, Ty}; @@ -366,14 +364,10 @@ where // check performed after the promotion. Verify that with an assertion. assert!(promoted.is_none() || Q::ALLOW_PROMOTED); - // Avoid looking at attrs of anon consts as that will ICE - let is_type_const_item = - matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst) - && find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_)); - // Don't peak inside trait associated constants, also `#[type_const] const` items // don't have bodies so there's nothing to look at - if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item { + if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def) + { let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def); if !Q::in_qualifs(&qualifs) { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index aa0e5c7fd710..910176a0689c 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>( kind: &'static str, ) -> Ty<'tcx> { let tcx = cx.tcx(); - let ty = tcx.typeck(def_id).node_type(hir_id); + // If the type is omitted on a #[type_const] we can't run + // type check on since that requires the const have a body + // which type_consts don't. + let ty = if tcx.is_type_const(def_id.to_def_id()) { + if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) { + tcx.type_of(trait_item_def_id).instantiate_identity() + } else { + Ty::new_error_with_message( + tcx, + ty_span, + "constant with #[type_const] requires an explicit type", + ) + } + } else { + tcx.typeck(def_id).node_type(hir_id) + }; // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a2f4714d1b2c..a3eec72214c0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1891,6 +1891,12 @@ impl<'tcx> TyCtxt<'tcx> { self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace) } + /// Check if the given `def_id` is a const with the `#[type_const]` attribute. + pub fn is_type_const(self, def_id: DefId) -> bool { + matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst) + && find_attr!(self.get_all_attrs(def_id), AttributeKind::TypeConst(_)) + } + /// Returns the movability of the coroutine of `def_id`, or panics /// if given a `def_id` that is not a coroutine. pub fn coroutine_movability(self, def_id: DefId) -> hir::Movability { diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 186fde4883df..1772d66f5285 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,7 +1,7 @@ //! See docs in build/expr/mod.rs use rustc_abi::Size; -use rustc_ast as ast; +use rustc_ast::{self as ast}; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -47,6 +47,7 @@ pub(crate) fn as_constant_inner<'tcx>( tcx: TyCtxt<'tcx>, ) -> ConstOperand<'tcx> { let Expr { ty, temp_scope_id: _, span, ref kind } = *expr; + match *kind { ExprKind::Literal { lit, neg } => { let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg }); @@ -69,6 +70,13 @@ pub(crate) fn as_constant_inner<'tcx>( } ExprKind::NamedConst { def_id, args, ref user_ty } => { let user_ty = user_ty.as_ref().and_then(push_cuta); + if tcx.is_type_const(def_id) { + let uneval = ty::UnevaluatedConst::new(def_id, args); + let ct = ty::Const::new_unevaluated(tcx, uneval); + + let const_ = Const::Ty(ty, ct); + return ConstOperand { span, user_ty, const_ }; + } let uneval = mir::UnevaluatedConst::new(def_id, args); let const_ = Const::Unevaluated(uneval, ty); diff --git a/tests/ui/const-generics/mgca/type_const-array-return.rs b/tests/ui/const-generics/mgca/type_const-array-return.rs new file mode 100644 index 000000000000..5375e4fded6d --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-array-return.rs @@ -0,0 +1,26 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +pub struct A; + +pub trait Array { + #[type_const] + const LEN: usize; + fn arr() -> [u8; Self::LEN]; +} + +impl Array for A { + #[type_const] + const LEN: usize = 4; + + #[allow(unused_braces)] + fn arr() -> [u8; const { Self::LEN }] { + return [0u8; const { Self::LEN }]; + } +} + +fn main() { + let _ = A::arr(); +} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs new file mode 100644 index 000000000000..b2c734098009 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs @@ -0,0 +1,12 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +struct A; + +impl A { + #[type_const] + const B = 4; + //~^ ERROR: missing type for `const` item +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr new file mode 100644 index 000000000000..b44e47cd7e61 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr @@ -0,0 +1,13 @@ +error: missing type for `const` item + --> $DIR/type_const-inherent-const-omitted-type.rs:8:12 + | +LL | const B = 4; + | ^ + | +help: provide a type for the item + | +LL | const B: = 4; + | ++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs new file mode 100644 index 000000000000..ab613859aa5c --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs @@ -0,0 +1,22 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +trait BadTr { + const NUM: usize; +} + +struct GoodS; + +impl BadTr for GoodS { + #[type_const] + const NUM: = 84; + //~^ ERROR: missing type for `const` item + +} + +fn accept_bad_tr>(_x: &T) {} +//~^ ERROR use of trait associated const without `#[type_const]` + +fn main() { + accept_bad_tr::<84, _>(&GoodS); +} diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr new file mode 100644 index 000000000000..16f312454ed2 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr @@ -0,0 +1,16 @@ +error: missing type for `const` item + --> $DIR/type_const-only-in-impl-omitted-type.rs:12:15 + | +LL | const NUM: = 84; + | ^ help: provide a type for the associated constant: `usize` + +error: use of trait associated const without `#[type_const]` + --> $DIR/type_const-only-in-impl-omitted-type.rs:17:43 + | +LL | fn accept_bad_tr>(_x: &T) {} + | ^^^^^^^^^^^ + | + = note: the declaration in the trait must be marked with `#[type_const]` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-recursive.rs b/tests/ui/const-generics/mgca/type_const-recursive.rs new file mode 100644 index 000000000000..15e49f747ed6 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.rs @@ -0,0 +1,8 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const A: u8 = A; +//~^ ERROR: overflow normalizing the unevaluated constant `A` [E0275] + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-recursive.stderr b/tests/ui/const-generics/mgca/type_const-recursive.stderr new file mode 100644 index 000000000000..947319ec7eda --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-recursive.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow normalizing the unevaluated constant `A` + --> $DIR/type_const-recursive.rs:5:1 + | +LL | const A: u8 = A; + | ^^^^^^^^^^^ + | + = note: in case this is a recursive type alias, consider using a struct, enum, or union instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/const-generics/mgca/type_const-use.rs b/tests/ui/const-generics/mgca/type_const-use.rs new file mode 100644 index 000000000000..04362cd28538 --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-use.rs @@ -0,0 +1,13 @@ +//@ check-pass +// This test should compile without an ICE. +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +#[type_const] +const CONST: usize = 1; + +fn uses_const() { + CONST; +} + +fn main() {} From 07fa70e104647b4b9b4ad9ba93bfaaba4ed5bcdf Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 9 Jan 2026 19:15:49 -0600 Subject: [PATCH 325/340] llvm: Update `reliable_f16` configuration for LLVM22 Since yesterday, the LLVM `main` branch should have working `f16` on all platforms that Rust supports; this will be LLVM version 22, so update how `cfg(target_has_reliable_f16)` is set to reflect this. Within the rust-lang organization, this currently has no effect. The goal is to start catching problems as early as possible in external CI that runs top-of-tree rust against top-of-tree LLVM, and once testing for the rust-lang bump to LLVM 22 starts. Hopefully this will mean that we can fix any problems that show up before the bump actually happens, meaning `f16` will be about ready for stabilization at that point (with some considerations for the GCC patch at [1] propagating). References: * https://github.com/llvm/llvm-project/commit/919021b0df8c91417784bfd84a6ad4869a0d2206 * https://github.com/llvm/llvm-project/commit/054ee2f8706b582859fcf96d1771aa68c37d9e6a * https://github.com/llvm/llvm-project/commit/db26ce5c5572a1a54ce307c762689ab63e5c5485 * https://github.com/llvm/llvm-project/commit/549d7c4f35a99598a269004ee13b237d2565b5ec * https://github.com/llvm/llvm-project/commit/4903c6260cbd781881906007f9c82aceb71fd7c7 [1]: https://github.com/gcc-mirror/gcc/commit/8b6a18ecaf44553230b90bf28adfb9fe9c9d5ab9 --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9b08f4e9869c..63f820dc2918 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -379,19 +379,19 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { { false } - // Unsupported - (Arch::Arm64EC, _) => false, + // Unsupported (fixed in llvm22) + (Arch::Arm64EC, _) if major < 22 => false, // Selection failure (fixed in llvm21) (Arch::S390x, _) if major < 21 => false, // MinGW ABI bugs (Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false, // Infinite recursion - (Arch::CSky, _) => false, + (Arch::CSky, _) if major < 22 => false, // (fixed in llvm22) (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) - (Arch::PowerPC | Arch::PowerPC64, _) => false, - (Arch::Sparc | Arch::Sparc64, _) => false, - (Arch::Wasm32 | Arch::Wasm64, _) => false, + (Arch::PowerPC | Arch::PowerPC64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Sparc | Arch::Sparc64, _) if major < 22 => false, // (fixed in llvm22) + (Arch::Wasm32 | Arch::Wasm64, _) if major < 22 => false, // (fixed in llvm22) // `f16` support only requires that symbols converting to and from `f32` are available. We // provide these in `compiler-builtins`, so `f16` should be available on all platforms that // do not have other ABI issues or LLVM crashes. From ccc86f222830386e90b898deb13cbf2314a5fec8 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 9 Jan 2026 09:32:20 +0530 Subject: [PATCH 326/340] std: sys: fs: uefi: Implement File::write Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index b1e5f33b1b22..95c1b437c057 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -336,8 +336,8 @@ impl File { crate::io::default_read_buf(|buf| self.read(buf), cursor) } - pub fn write(&self, _buf: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { @@ -692,6 +692,25 @@ mod uefi_fs { } } + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + let file_ptr = self.protocol.as_ptr(); + let mut buf_size = buf.len(); + + let r = unsafe { + ((*file_ptr).write)( + file_ptr, + &mut buf_size, + buf.as_ptr().cast::().cast_mut(), + ) + }; + + if buf_size == 0 && r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + Ok(buf_size) + } + } + pub(crate) fn file_info(&self) -> io::Result> { let file_ptr = self.protocol.as_ptr(); let mut info_id = file::INFO_ID; From 7c7cf45dcf6f84937faddf18f55b625f76012a3c Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 12:48:19 +0000 Subject: [PATCH 327/340] Don't special-case `while` block type mismatch 67ea84d erroneously added this special-case when introducing `DesugaringKind::WhileLoop`. It had the unintended effect of emitting erroneous diagnostics in certain `while` blocks. --- compiler/rustc_hir_typeck/src/coercion.rs | 9 ++++----- .../block-result/block-must-not-have-result-while.stderr | 8 ++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5e1e567d103e..52ea6cdeaa0e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; +use rustc_span::{BytePos, DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; use rustc_trait_selection::solve::{Certainty, Goal, NoSolution}; @@ -1828,10 +1828,9 @@ impl<'tcx> CoerceMany<'tcx> { // If the block is from an external macro or try (`?`) desugaring, then // do not suggest adding a semicolon, because there's nowhere to put it. // See issues #81943 and #87051. - && matches!( - cond_expr.span.desugaring_kind(), - None | Some(DesugaringKind::WhileLoop) - ) + // Similarly, if the block is from a loop desugaring, then also do not + // suggest adding a semicolon. See issue #150850. + && cond_expr.span.desugaring_kind().is_none() && !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map()) && !matches!( cond_expr.kind, diff --git a/tests/ui/block-result/block-must-not-have-result-while.stderr b/tests/ui/block-result/block-must-not-have-result-while.stderr index 0b9941ea96ef..d8e854c9b9ba 100644 --- a/tests/ui/block-result/block-must-not-have-result-while.stderr +++ b/tests/ui/block-result/block-must-not-have-result-while.stderr @@ -9,12 +9,8 @@ LL | while true { error[E0308]: mismatched types --> $DIR/block-must-not-have-result-while.rs:5:9 | -LL | / while true { -LL | | true - | | ^^^^ expected `()`, found `bool` -LL | | -LL | | } - | |_____- expected this to be `()` +LL | true + | ^^^^ expected `()`, found `bool` error: aborting due to 1 previous error; 1 warning emitted From 5674be29fa5819cf5d1578f5a53f7a9603a38d90 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 9 Jan 2026 12:04:23 +0000 Subject: [PATCH 328/340] Don't suggest breaking with value from `for` or `while` loops --- .../src/fn_ctxt/suggestions.rs | 22 ++++++---- ...nt-suggest-break-from-unbreakable-loops.rs | 39 +++++++++++++++++ ...uggest-break-from-unbreakable-loops.stderr | 42 +++++++++++++++++++ 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs create mode 100644 tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d51b052e0d1b..3e4c194147f9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,8 +10,8 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, - GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind, - WherePredicateKind, expr_needs_parens, is_range_literal, + GenericBound, HirId, LoopSource, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, + TyKind, WherePredicateKind, expr_needs_parens, is_range_literal, }; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::suggest_impl_trait; @@ -1170,15 +1170,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let found = self.resolve_vars_if_possible(found); - let in_loop = self.is_loop(id) - || self - .tcx + let innermost_loop = if self.is_loop(id) { + Some(self.tcx.hir_node(id)) + } else { + self.tcx .hir_parent_iter(id) .take_while(|(_, node)| { // look at parents until we find the first body owner node.body_id().is_none() }) - .any(|(parent_id, _)| self.is_loop(parent_id)); + .find_map(|(parent_id, node)| self.is_loop(parent_id).then_some(node)) + }; + let can_break_with_value = innermost_loop.is_some_and(|node| { + matches!( + node, + Node::Expr(Expr { kind: ExprKind::Loop(_, _, LoopSource::Loop, ..), .. }) + ) + }); let in_local_statement = self.is_local_statement(id) || self @@ -1186,7 +1194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .hir_parent_iter(id) .any(|(parent_id, _)| self.is_local_statement(parent_id)); - if in_loop && in_local_statement { + if can_break_with_value && in_local_statement { err.multipart_suggestion( "you might have meant to break the loop with this value", vec![ diff --git a/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs new file mode 100644 index 000000000000..69b57486138d --- /dev/null +++ b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.rs @@ -0,0 +1,39 @@ +//! Don't suggest breaking with value from `for` or `while` loops +//! +//! Regression test for https://github.com/rust-lang/rust/issues/150850 + +fn returns_i32() -> i32 { 0 } + +fn suggest_breaking_from_loop() { + let _ = loop { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + //~| SUGGESTION break + }; +} + +fn dont_suggest_breaking_from_for() { + let _ = for _ in 0.. { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + }; +} + +fn dont_suggest_breaking_from_while() { + let cond = true; + let _ = while cond { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + }; +} + +fn dont_suggest_breaking_from_for_nested_in_loop() { + let _ = loop { + for _ in 0.. { + returns_i32() //~ ERROR mismatched types + //~^ SUGGESTION ; + } + }; +} + +fn main() {} diff --git a/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr new file mode 100644 index 000000000000..880cc53f9a7c --- /dev/null +++ b/tests/ui/for-loop-while/dont-suggest-break-from-unbreakable-loops.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:9:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^ expected `()`, found `i32` + | +help: consider using a semicolon here + | +LL | returns_i32(); + | + +help: you might have meant to break the loop with this value + | +LL | break returns_i32(); + | +++++ + + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:17:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:25:9 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-from-unbreakable-loops.rs:33:13 + | +LL | returns_i32() + | ^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 14c6e602f423e01082367954fb0ea19f2b177ba0 Mon Sep 17 00:00:00 2001 From: oncecelll Date: Sat, 10 Jan 2026 13:25:31 +0800 Subject: [PATCH 329/340] Add missing documentation for globs feature Signed-off-by: oncecelll --- compiler/rustc_feature/src/accepted.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 13c1f2219bed..43032bf938c0 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -235,7 +235,7 @@ declare_features! ( (accepted, generic_param_attrs, "1.27.0", Some(48848)), /// Allows the `#[global_allocator]` attribute. (accepted, global_allocator, "1.28.0", Some(27389)), - // FIXME: explain `globs`. + /// Allows globs imports (`use module::*;`) to import all public items from a module. (accepted, globs, "1.0.0", None), /// Allows using `..=X` as a pattern. (accepted, half_open_range_patterns, "1.66.0", Some(67264)), From a0df7b2ad5c94f97a30d04008059e9dcfd1492a2 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 10 Jan 2026 09:34:44 +0100 Subject: [PATCH 330/340] compiler: Forward attributes to eii-expanded macros Otherwise you get errors like these if you have an Externally Implementable Item defined in std: error: attribute macro has missing stability attribute --> library/std/src/io/mod.rs:2269:1 | 2269 | #[eii(on_broken_pipe)] | ^^^^^^^^^^^^^^^^^^^^-- | | | in this attribute macro expansion | ::: library/core/src/macros/mod.rs:1899:5 | 1899 | pub macro eii($item:item) { | ------------- in this expansion of `#[eii]` Or (fatal) warnings like these: warning: missing documentation for an attribute macro --> library/std/src/io/mod.rs:2269:1 --- compiler/rustc_builtin_macros/src/eii.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 2d67608609e3..0ebd3dc826d4 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -133,6 +133,7 @@ fn eii_( macro_name, foreign_item_name, impl_unsafe, + &attrs_from_decl, ))); return_items.into_iter().map(wrap_item).collect() @@ -416,9 +417,14 @@ fn generate_attribute_macro_to_implement( macro_name: Ident, foreign_item_name: Ident, impl_unsafe: bool, + attrs_from_decl: &[Attribute], ) -> ast::Item { let mut macro_attrs = ThinVec::new(); + // To avoid e.g. `error: attribute macro has missing stability attribute` + // errors for eii's in std. + macro_attrs.extend_from_slice(attrs_from_decl); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); From 9b811544f211639c4e828e5bbe3497167ff40723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sat, 10 Jan 2026 11:10:31 +0100 Subject: [PATCH 331/340] once again reorganize the EII tests a bit --- .../auxiliary/{codegen1.rs => other_crate_privacy1.rs} | 0 .../auxiliary/{codegen3.rs => other_crate_privacy2.rs} | 0 tests/ui/eii/{ => duplicate}/multiple_decls.rs | 0 tests/ui/eii/{ => duplicate}/multiple_decls.stderr | 0 tests/ui/eii/{ => duplicate}/multiple_impls.rs | 0 tests/ui/eii/{ => duplicate}/multiple_impls.run.stdout | 0 .../auxiliary/codegen_cross_crate_other_crate.rs} | 0 tests/ui/eii/{ => linking}/codegen_cross_crate.rs | 4 ++-- .../eii/{ => linking}/codegen_cross_crate.run.stdout | 0 tests/ui/eii/{ => linking}/codegen_single_crate.rs | 0 .../eii/{ => linking}/codegen_single_crate.run.stdout | 0 tests/ui/eii/{ => linking}/same-symbol.rs | 0 tests/ui/eii/{ => linking}/same-symbol.run.stdout | 0 tests/ui/eii/privacy1.rs | 6 +++--- tests/ui/eii/privacy2.rs | 4 ++-- tests/ui/eii/privacy2.stderr | 10 +++++----- .../auxiliary/cross_crate_eii_declaration.rs | 0 .../cross_crate_type_ok.rs} | 0 .../ui/eii/{ => type_checking}/cross_crate_wrong_ty.rs | 0 .../{ => type_checking}/cross_crate_wrong_ty.stderr | 0 20 files changed, 12 insertions(+), 12 deletions(-) rename tests/ui/eii/auxiliary/{codegen1.rs => other_crate_privacy1.rs} (100%) rename tests/ui/eii/auxiliary/{codegen3.rs => other_crate_privacy2.rs} (100%) rename tests/ui/eii/{ => duplicate}/multiple_decls.rs (100%) rename tests/ui/eii/{ => duplicate}/multiple_decls.stderr (100%) rename tests/ui/eii/{ => duplicate}/multiple_impls.rs (100%) rename tests/ui/eii/{ => duplicate}/multiple_impls.run.stdout (100%) rename tests/ui/eii/{auxiliary/codegen2.rs => linking/auxiliary/codegen_cross_crate_other_crate.rs} (100%) rename tests/ui/eii/{ => linking}/codegen_cross_crate.rs (82%) rename tests/ui/eii/{ => linking}/codegen_cross_crate.run.stdout (100%) rename tests/ui/eii/{ => linking}/codegen_single_crate.rs (100%) rename tests/ui/eii/{ => linking}/codegen_single_crate.run.stdout (100%) rename tests/ui/eii/{ => linking}/same-symbol.rs (100%) rename tests/ui/eii/{ => linking}/same-symbol.run.stdout (100%) rename tests/ui/eii/{ => type_checking}/auxiliary/cross_crate_eii_declaration.rs (100%) rename tests/ui/eii/{cross_crate.rs => type_checking/cross_crate_type_ok.rs} (100%) rename tests/ui/eii/{ => type_checking}/cross_crate_wrong_ty.rs (100%) rename tests/ui/eii/{ => type_checking}/cross_crate_wrong_ty.stderr (100%) diff --git a/tests/ui/eii/auxiliary/codegen1.rs b/tests/ui/eii/auxiliary/other_crate_privacy1.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen1.rs rename to tests/ui/eii/auxiliary/other_crate_privacy1.rs diff --git a/tests/ui/eii/auxiliary/codegen3.rs b/tests/ui/eii/auxiliary/other_crate_privacy2.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen3.rs rename to tests/ui/eii/auxiliary/other_crate_privacy2.rs diff --git a/tests/ui/eii/multiple_decls.rs b/tests/ui/eii/duplicate/multiple_decls.rs similarity index 100% rename from tests/ui/eii/multiple_decls.rs rename to tests/ui/eii/duplicate/multiple_decls.rs diff --git a/tests/ui/eii/multiple_decls.stderr b/tests/ui/eii/duplicate/multiple_decls.stderr similarity index 100% rename from tests/ui/eii/multiple_decls.stderr rename to tests/ui/eii/duplicate/multiple_decls.stderr diff --git a/tests/ui/eii/multiple_impls.rs b/tests/ui/eii/duplicate/multiple_impls.rs similarity index 100% rename from tests/ui/eii/multiple_impls.rs rename to tests/ui/eii/duplicate/multiple_impls.rs diff --git a/tests/ui/eii/multiple_impls.run.stdout b/tests/ui/eii/duplicate/multiple_impls.run.stdout similarity index 100% rename from tests/ui/eii/multiple_impls.run.stdout rename to tests/ui/eii/duplicate/multiple_impls.run.stdout diff --git a/tests/ui/eii/auxiliary/codegen2.rs b/tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs similarity index 100% rename from tests/ui/eii/auxiliary/codegen2.rs rename to tests/ui/eii/linking/auxiliary/codegen_cross_crate_other_crate.rs diff --git a/tests/ui/eii/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs similarity index 82% rename from tests/ui/eii/codegen_cross_crate.rs rename to tests/ui/eii/linking/codegen_cross_crate.rs index a1fa617491bd..4016712e7504 100644 --- a/tests/ui/eii/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -1,6 +1,6 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen2.rs +//@ aux-build: codegen_cross_crate_other_crate.rs //@ compile-flags: -O //@ ignore-backends: gcc // FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 @@ -8,7 +8,7 @@ // Tests whether calling EIIs works with the declaration in another crate. #![feature(extern_item_impls)] -extern crate codegen2 as codegen; +extern crate codegen_cross_crate_other_crate as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/codegen_cross_crate.run.stdout b/tests/ui/eii/linking/codegen_cross_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_cross_crate.run.stdout rename to tests/ui/eii/linking/codegen_cross_crate.run.stdout diff --git a/tests/ui/eii/codegen_single_crate.rs b/tests/ui/eii/linking/codegen_single_crate.rs similarity index 100% rename from tests/ui/eii/codegen_single_crate.rs rename to tests/ui/eii/linking/codegen_single_crate.rs diff --git a/tests/ui/eii/codegen_single_crate.run.stdout b/tests/ui/eii/linking/codegen_single_crate.run.stdout similarity index 100% rename from tests/ui/eii/codegen_single_crate.run.stdout rename to tests/ui/eii/linking/codegen_single_crate.run.stdout diff --git a/tests/ui/eii/same-symbol.rs b/tests/ui/eii/linking/same-symbol.rs similarity index 100% rename from tests/ui/eii/same-symbol.rs rename to tests/ui/eii/linking/same-symbol.rs diff --git a/tests/ui/eii/same-symbol.run.stdout b/tests/ui/eii/linking/same-symbol.run.stdout similarity index 100% rename from tests/ui/eii/same-symbol.run.stdout rename to tests/ui/eii/linking/same-symbol.run.stdout diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index b5bbf68bfdaf..72aec83d2cee 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -1,13 +1,13 @@ //@ run-pass //@ check-run-results -//@ aux-build: codegen1.rs +//@ aux-build: other_crate_privacy1.rs //@ ignore-backends: gcc -// FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 +// FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether re-exports work. #![feature(extern_item_impls)] -extern crate codegen1 as codegen; +extern crate other_crate_privacy1 as codegen; #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index a0bc26ef629b..e3f1f8c863da 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -1,8 +1,8 @@ -//@ aux-build:codegen3.rs +//@ aux-build:other_crate_privacy2.rs // Tests whether name resolution respects privacy properly. #![feature(extern_item_impls)] -extern crate codegen3 as codegen; +extern crate other_crate_privacy2 as codegen; // has a span but in the other crate //~? ERROR `#[eii2]` required, but not found diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index 903285d4d1e3..9f4fd6a071c9 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -11,24 +11,24 @@ LL | codegen::decl1(42); | ^^^^^ private function | note: the function `decl1` is defined here - --> $DIR/auxiliary/codegen3.rs:7:1 + --> $DIR/auxiliary/other_crate_privacy2.rs:7:1 | LL | fn decl1(x: u64); | ^^^^^^^^^^^^^^^^^ error: `#[eii2]` required, but not found - --> $DIR/auxiliary/codegen3.rs:9:7 + --> $DIR/auxiliary/other_crate_privacy2.rs:9:7 | LL | #[eii(eii2)] - | ^^^^ expected because `#[eii2]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii2]` was declared here in crate `other_crate_privacy2` | = 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:11 + --> $DIR/auxiliary/other_crate_privacy2.rs:13:11 | LL | #[eii(eii3)] - | ^^^^ expected because `#[eii3]` was declared here in crate `codegen3` + | ^^^^ expected because `#[eii3]` was declared here in crate `other_crate_privacy2` | = help: expected at least one implementation in crate `privacy2` or any of its dependencies diff --git a/tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs b/tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs similarity index 100% rename from tests/ui/eii/auxiliary/cross_crate_eii_declaration.rs rename to tests/ui/eii/type_checking/auxiliary/cross_crate_eii_declaration.rs diff --git a/tests/ui/eii/cross_crate.rs b/tests/ui/eii/type_checking/cross_crate_type_ok.rs similarity index 100% rename from tests/ui/eii/cross_crate.rs rename to tests/ui/eii/type_checking/cross_crate_type_ok.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.rs b/tests/ui/eii/type_checking/cross_crate_wrong_ty.rs similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.rs rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.rs diff --git a/tests/ui/eii/cross_crate_wrong_ty.stderr b/tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr similarity index 100% rename from tests/ui/eii/cross_crate_wrong_ty.stderr rename to tests/ui/eii/type_checking/cross_crate_wrong_ty.stderr From 00ad6714064e0003d04731933be62636a19c9400 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 13:00:07 +0100 Subject: [PATCH 332/340] Subscribe myself to attr parsing --- triagebot.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 59c5e5f24330..3007ec765e00 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1358,11 +1358,11 @@ message = "The rustc-dev-guide subtree was changed. If this PR *only* touches th cc = ["@BoxyUwU", "@jieyouxu", "@kobzol", "@tshepang"] [mentions."compiler/rustc_passes/src/check_attr.rs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_attr_parsing"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."compiler/rustc_hir/src/attrs"] -cc = ["@jdonszelmann"] +cc = ["@jdonszelmann", "@JonathanBrouwer"] [mentions."src/tools/enzyme"] cc = ["@ZuseZ4"] From da0dda15036e486778afee422ab8603cc6d1334e Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 10 Jan 2026 14:21:46 +0100 Subject: [PATCH 333/340] Remove special case for `AllowedTargets::CrateLevel` --- .../src/attributes/crate_level.rs | 18 ++++++------ compiler/rustc_attr_parsing/src/context.rs | 14 ++-------- .../rustc_attr_parsing/src/target_checking.rs | 28 ++++++------------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 01c503357fc7..5604fbd25edc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -9,7 +9,7 @@ impl SingleAttributeParser for CrateNameParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(n) = args else { @@ -33,7 +33,7 @@ impl SingleAttributeParser for RecursionLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; 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; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -56,7 +56,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -79,7 +79,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -102,7 +102,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let ArgParser::NameValue(nv) = args else { @@ -123,7 +123,7 @@ pub(crate) struct NoCoreParser; impl NoArgsAttributeParser for NoCoreParser { const PATH: &[Symbol] = &[sym::no_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore; } @@ -132,7 +132,7 @@ pub(crate) struct NoStdParser; impl NoArgsAttributeParser for NoStdParser { const PATH: &[Symbol] = &[sym::no_std]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; } @@ -141,7 +141,7 @@ pub(crate) struct RustcCoherenceIsCoreParser; impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore; } @@ -151,7 +151,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { const PATH: &[Symbol] = &[sym::windows_subsystem]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); 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 { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d..527e3f567cf3 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; +use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; +use rustc_hir::{AttrPath, HirId}; use rustc_session::Session; use rustc_session::lint::{Lint, LintId}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; @@ -303,8 +303,6 @@ pub trait Stage: Sized + 'static + Sealed { ) -> ErrorGuaranteed; fn should_emit(&self) -> ShouldEmit; - - fn id_is_crate_root(id: Self::Id) -> bool; } // allow because it's a sealed trait @@ -326,10 +324,6 @@ impl Stage for Early { fn should_emit(&self) -> ShouldEmit { self.emit_errors } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_NODE_ID - } } // allow because it's a sealed trait @@ -351,10 +345,6 @@ impl Stage for Late { fn should_emit(&self) -> ShouldEmit { ShouldEmit::ErrorsAndLints } - - fn id_is_crate_root(id: Self::Id) -> bool { - id == CRATE_HIR_ID - } } /// used when parsing attributes for miscellaneous things *before* ast lowering diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 88fa3e436292..52c2d10f4797 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -15,11 +15,6 @@ use crate::session_diagnostics::InvalidTarget; pub(crate) enum AllowedTargets { AllowList(&'static [Policy]), AllowListWarnRest(&'static [Policy]), - /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`. - /// For crate-level attributes we emit a specific set of lints to warn - /// people about accidentally not using them on the crate. - /// Only use this for attributes that are *exclusively* valid at the crate level. - CrateLevel, } pub(crate) enum AllowedResult { @@ -53,7 +48,6 @@ impl AllowedTargets { AllowedResult::Warn } } - AllowedTargets::CrateLevel => AllowedResult::Allowed, } } @@ -61,7 +55,6 @@ impl AllowedTargets { match self { AllowedTargets::AllowList(list) => list, AllowedTargets::AllowListWarnRest(list) => list, - AllowedTargets::CrateLevel => ALL_TARGETS, } .iter() .filter_map(|target| match target { @@ -95,7 +88,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { - Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx); + if allowed_targets.allowed_targets() == &[Target::Crate] { + Self::check_crate_level(target, cx); + return; + } match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} @@ -149,18 +145,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } - pub(crate) fn check_type( - crate_level: bool, - target: Target, - cx: &mut AcceptContext<'_, 'sess, S>, - ) { - let is_crate_root = S::id_is_crate_root(cx.target_id); - - if is_crate_root { - return; - } - - if !crate_level { + pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) { + // For crate-level attributes we emit a specific set of lints to warn + // people about accidentally not using them on the crate. + if target == Target::Crate { return; } From 8332887f36091d9c6c8b2faefdb33dcaa1743e32 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Sat, 10 Jan 2026 11:04:54 -0500 Subject: [PATCH 334/340] 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 8c133afcd5e0..6d1bd93c47f0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 8c133afcd5e0d69932fe11f5907683723f8d361d +Subproject commit 6d1bd93c47f059ec1344cb31e68a2fb284cbc6b1 From 6878e73d26af87e01c1c289c77f1448fa3c3e76f Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 10 Jan 2026 11:59:33 +0530 Subject: [PATCH 335/340] std: sys: fs: uefi: Implement File::seek - Tested using OVMF on QEMU. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index fcf21d9e9731..23de7adfabc6 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -352,8 +352,24 @@ impl File { unsupported() } - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - unsupported() + pub fn seek(&self, pos: SeekFrom) -> io::Result { + const NEG_OFF_ERR: io::Error = + io::const_error!(io::ErrorKind::InvalidInput, "cannot seek to negative offset."); + + let off = match pos { + SeekFrom::Start(p) => p, + SeekFrom::End(p) => { + // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + if p == 0 { + 0xFFFFFFFFFFFFFFFF + } else { + self.file_attr()?.size().checked_add_signed(p).ok_or(NEG_OFF_ERR)? + } + } + SeekFrom::Current(p) => self.tell()?.checked_add_signed(p).ok_or(NEG_OFF_ERR)?, + }; + + self.0.set_position(off).map(|_| off) } pub fn size(&self) -> Option> { @@ -755,6 +771,12 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(pos) } } + pub(crate) fn set_position(&self, pos: u64) -> io::Result<()> { + let file_ptr = self.protocol.as_ptr(); + let r = unsafe { ((*file_ptr).set_position)(file_ptr, pos) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.protocol.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; From 76fcac23713815f214aba8d4751986d771f7f131 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sat, 10 Jan 2026 23:40:22 +0100 Subject: [PATCH 336/340] Port `#[rustc_has_incoherent_inherent_impls]` to attribute parser --- .../src/attributes/rustc_internal.rs | 15 +++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 13 +++++++------ compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/coherence/inherent_impls.rs | 7 +++++-- compiler/rustc_middle/src/ty/trait_def.rs | 6 +++--- compiler/rustc_passes/messages.ftl | 4 ---- compiler/rustc_passes/src/check_attr.rs | 15 +-------------- compiler/rustc_passes/src/errors.rs | 9 --------- 9 files changed, 35 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 922a5bd297ac..834b1d988cb4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -305,3 +305,18 @@ impl SingleAttributeParser for RustcScalableVectorParser { Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span }) } } + +pub(crate) struct RustcHasIncoherentInherentImplsParser; + +impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser { + const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::ForeignTy), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d..513e6ad72b56 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -62,12 +62,12 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ - RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, - RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, - RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, - RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, - RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser, + RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, + RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, + RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, + RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, + RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -264,6 +264,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 23201eff455f..c791f54902d1 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -880,6 +880,9 @@ pub enum AttributeKind { /// Represents `#[rustc_coherence_is_core]` RustcCoherenceIsCore(Span), + /// Represents `#[rustc_has_incoherent_inherent_impls]` + RustcHasIncoherentInherentImpls, + /// Represents `#[rustc_layout_scalar_valid_range_end]`. RustcLayoutScalarValidRangeEnd(Box, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 3efa876ed6a9..4e1e9a074e66 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -95,6 +95,7 @@ impl AttributeKind { Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcCoherenceIsCore(..) => No, + RustcHasIncoherentInherentImpls => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcLegacyConstGenerics { .. } => Yes, diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 984a812246eb..fe47f3258846 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -15,7 +15,7 @@ use rustc_hir::find_attr; use rustc_middle::bug; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams, simplify_type}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; -use rustc_span::{ErrorGuaranteed, sym}; +use rustc_span::ErrorGuaranteed; use crate::errors; @@ -79,7 +79,10 @@ impl<'tcx> InherentCollect<'tcx> { } if self.tcx.features().rustc_attrs() { - if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { + if !find_attr!( + self.tcx.get_all_attrs(ty_def_id), + AttributeKind::RustcHasIncoherentInherentImpls + ) { let impl_span = self.tcx.def_span(impl_def_id); return Err(self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span })); } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 691cb43b724a..2f6b38a619d2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -2,11 +2,11 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{self as hir, find_attr}; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::symbol::sym; use tracing::debug; use crate::query::LocalCrate; @@ -241,7 +241,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait /// Query provider for `incoherent_impls`. pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { if let Some(def_id) = simp.def() - && !tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) + && !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcHasIncoherentInherentImpls) { return &[]; } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 94996c0adb47..ba44aa3a35ab 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -244,10 +244,6 @@ passes_function_not_have_default_implementation = function doesn't have a defaul passes_functions_names_duplicated = functions names are duplicated .note = all `#[rustc_must_implement_one_of]` arguments must be unique -passes_has_incoherent_inherent_impl = - `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits - .label = only adts, extern types and traits are supported - passes_ignored_derived_impls = `{$name}` has {$trait_list_len -> [one] a derived impl diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2d3c5c7e48a0..360feacac0e9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -306,6 +306,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::CfgAttrTrace | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } + | AttributeKind::RustcHasIncoherentInherentImpls ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -325,9 +326,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::rustc_has_incoherent_inherent_impls, ..] => { - self.check_has_incoherent_inherent_impls(attr, span, target) - } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1164,17 +1162,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {} - _ => { - self.tcx - .dcx() - .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span }); - } - } - } - fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) { if find_attr!(attrs, AttributeKind::FfiConst(_)) { // `#[ffi_const]` functions cannot be `#[ffi_pure]` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index af5cb29b83d0..14555765e423 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -187,15 +187,6 @@ pub(crate) struct DocAttrNotCrateLevel<'a> { pub attr_name: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_has_incoherent_inherent_impl)] -pub(crate) struct HasIncoherentInherentImpl { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_both_ffi_const_and_pure, code = E0757)] pub(crate) struct BothFfiConstAndPure { From 50813939e4d21a90cef22f42d4fb2d32600f2910 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 11 Jan 2026 12:04:46 +1100 Subject: [PATCH 337/340] Don't run the longer partial-sort tests under Miri --- library/alloctests/tests/sort/partial.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/alloctests/tests/sort/partial.rs b/library/alloctests/tests/sort/partial.rs index c7248990c70c..679841b91e8d 100644 --- a/library/alloctests/tests/sort/partial.rs +++ b/library/alloctests/tests/sort/partial.rs @@ -79,6 +79,10 @@ fn basic_impl() { fn random_patterns() { check_is_partial_sorted_ranges(&patterns::random(10)); check_is_partial_sorted_ranges(&patterns::random(50)); - check_is_partial_sorted_ranges(&patterns::random(100)); - check_is_partial_sorted_ranges(&patterns::random(1000)); + + // Longer tests would take hours to run under Miri. + if !cfg!(miri) { + check_is_partial_sorted_ranges(&patterns::random(100)); + check_is_partial_sorted_ranges(&patterns::random(1000)); + } } From 199aa6813eb08b32abca02745f1fb331813bb044 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 12 Jan 2026 05:04:54 +0000 Subject: [PATCH 338/340] Prepare for merging from rust-lang/rust This updates the rust-version file to 44a5b55557c26353f388400d7da95527256fe260. --- 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 c44422d758c5..b53a66c66751 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f57b9e6f565a1847e83a63f3e90faa3870536c1f +44a5b55557c26353f388400d7da95527256fe260 From 8a8b31a4d1e971044b7904acd711191d7f6b200c Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 12 Jan 2026 06:53:19 +0100 Subject: [PATCH 339/340] compiler: Make Externally Implementable Item (eii) macros "semiopaque" Otherwise eiis defined by std will produce large amounts of `missing stability attribute` errors. --- compiler/rustc_builtin_macros/src/eii.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index 0ebd3dc826d4..b1cd35c0433d 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -425,6 +425,9 @@ fn generate_attribute_macro_to_implement( // errors for eii's in std. macro_attrs.extend_from_slice(attrs_from_decl); + // Avoid "missing stability attribute" errors for eiis in std. See #146993. + macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span)); + // #[builtin_macro(eii_shared_macro)] macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span)); From 41939ae3b31848a9d854c25ce2c1973de5e64e6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Jan 2026 11:48:16 +0100 Subject: [PATCH 340/340] test closing std streams separately, and in two configurations --- .../miri/tests/pass-dep/libc/close-std-streams.rs | 13 +++++++++++++ src/tools/miri/tests/pass-dep/libc/libc-fs.rs | 11 +---------- 2 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 src/tools/miri/tests/pass-dep/libc/close-std-streams.rs diff --git a/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs b/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs new file mode 100644 index 000000000000..cc30d9557fc6 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/close-std-streams.rs @@ -0,0 +1,13 @@ +//@ignore-target: windows # no libc +//@ revisions: default null +//@[null] compile-flags: -Zmiri-mute-stdout-stderr + +fn main() { + // This is std library UB, but that's not relevant since we're + // only interacting with libc here. + unsafe { + libc::close(0); + libc::close(1); + libc::close(2); + } +} 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 8c860b5db7ba..00d5f7d97e28 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -1,4 +1,4 @@ -//@ignore-target: windows # File handling is not implemented yet +//@ignore-target: windows # no libc //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] @@ -48,7 +48,6 @@ fn main() { test_nofollow_not_symlink(); #[cfg(target_os = "macos")] test_ioctl(); - test_close_stdout(); } fn test_file_open_unix_allow_two_args() { @@ -580,11 +579,3 @@ fn test_ioctl() { assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); } } - -fn test_close_stdout() { - // This is std library UB, but that's not relevant since we're - // only interacting with libc here. - unsafe { - libc::close(1); - } -}