Skip to content

Commit f64e401

Browse files
committed
Merge remote-tracking branch 'upstream/master' into rustup
2 parents 52fa003 + 0b784f8 commit f64e401

File tree

232 files changed

+4515
-2784
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

232 files changed

+4515
-2784
lines changed

CHANGELOG.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,89 @@ document.
88

99
[e9b7045...master](https://github.com/rust-lang/rust-clippy/compare/e9b7045...master)
1010

11+
## Rust 1.91
12+
13+
Current stable, released 2025-10-30
14+
15+
[View all 146 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-07-25T21%3A05%3A11Z..2025-09-04T22%3A34%3A27Z+base%3Amaster)
16+
17+
### New Lints
18+
19+
* Added [`possible_missing_else`] to `suspicious`
20+
[#15317](https://github.com/rust-lang/rust-clippy/pull/15317)
21+
22+
### Moves and Deprecations
23+
24+
* Moved [`cognitive_complexity`] from `nursery` to `restriction`
25+
[#15415](https://github.com/rust-lang/rust-clippy/pull/15415)
26+
* Moved [`declare_interior_mutable_const`] from `style` to `suspicious`
27+
[#15454](https://github.com/rust-lang/rust-clippy/pull/15454)
28+
* Moved [`crosspointer_transmute`] from `complexity` to `suspicious`
29+
[#15403](https://github.com/rust-lang/rust-clippy/pull/15403)
30+
31+
### Enhancements
32+
33+
* [`excessive_precision`] added `const_literal_digits_threshold` option to suppress overly precise constants.
34+
[#15193](https://github.com/rust-lang/rust-clippy/pull/15193)
35+
* [`unwrap_in_result`] rewritten for better accuracy; now lints on `.unwrap()` and `.expect()`
36+
directly and no longer mixes `Result` and `Option`.
37+
[#15445](https://github.com/rust-lang/rust-clippy/pull/15445)
38+
* [`panic`] now works in `const` contexts.
39+
[#15565](https://github.com/rust-lang/rust-clippy/pull/15565)
40+
* [`implicit_clone`] now also lints `to_string` calls (merging [`string_to_string`] behavior).
41+
[#14177](https://github.com/rust-lang/rust-clippy/pull/14177)
42+
* [`collapsible_match`] improved suggestions to handle necessary ref/dereferencing.
43+
[#14221](https://github.com/rust-lang/rust-clippy/pull/14221)
44+
* [`map_identity`] now suggests making variables mutable when required; recognizes tuple struct restructuring.
45+
[#15261](https://github.com/rust-lang/rust-clippy/pull/15261)
46+
* [`option_map_unit_fn`] preserves `unsafe` blocks in suggestions.
47+
[#15570](https://github.com/rust-lang/rust-clippy/pull/15570)
48+
* [`unnecessary_mut_passed`] provides structured, clearer fix suggestions.
49+
[#15438](https://github.com/rust-lang/rust-clippy/pull/15438)
50+
* [`float_equality_without_abs`] now checks `f16` and `f128` types.
51+
[#15054](https://github.com/rust-lang/rust-clippy/pull/15054)
52+
* [`doc_markdown`] expanded whitelist (`InfiniBand`, `RoCE`, `PowerPC`) and improved handling of
53+
identifiers like NixOS.
54+
[#15558](https://github.com/rust-lang/rust-clippy/pull/15558)
55+
* [`clone_on_ref_ptr`] now suggests fully qualified paths to avoid resolution errors.
56+
[#15561](https://github.com/rust-lang/rust-clippy/pull/15561)
57+
* [`manual_assert`] simplifies boolean expressions in suggested fixes.
58+
[#15368](https://github.com/rust-lang/rust-clippy/pull/15368)
59+
* [`four_forward_slashes`] warns about bare CR in comments and avoids invalid autofixes.
60+
[#15175](https://github.com/rust-lang/rust-clippy/pull/15175)
61+
62+
### False Positive Fixes
63+
64+
* [`alloc_instead_of_core`] fixed FP when `alloc` is an alias
65+
[#15581](https://github.com/rust-lang/rust-clippy/pull/15581)
66+
* [`needless_range_loop`] fixed FP and FN when meeting multidimensional array
67+
[#15486](https://github.com/rust-lang/rust-clippy/pull/15486)
68+
* [`semicolon_inside_block`] fixed FP when attribute over expr is not enabled
69+
[#15476](https://github.com/rust-lang/rust-clippy/pull/15476)
70+
* [`unnested_or_patterns`] fixed FP on structs with only shorthand field patterns
71+
[#15343](https://github.com/rust-lang/rust-clippy/pull/15343)
72+
* [`match_ref_pats`] fixed FP on match scrutinee of never type
73+
[#15474](https://github.com/rust-lang/rust-clippy/pull/15474)
74+
* [`infinite_loop`] fixed FP in async blocks that are not awaited
75+
[#15157](https://github.com/rust-lang/rust-clippy/pull/15157)
76+
* [`iter_on_single_items`] fixed FP on function pointers and let statements
77+
[#15013](https://github.com/rust-lang/rust-clippy/pull/15013)
78+
79+
### ICE Fixes
80+
81+
* [`len_zero`] fix ICE when fn len has a return type without generic type params
82+
[#15660](https://github.com/rust-lang/rust-clippy/pull/15660)
83+
84+
### Documentation Improvements
85+
86+
* [`cognitive_complexity`] corrected documentation to state lint is in `restriction`, not `nursery`
87+
[#15563](https://github.com/rust-lang/rust-clippy/pull/15563)
88+
89+
### Performance Improvements
90+
91+
* [`doc_broken_link`] optimized by 99.77% (12M → 27k instructions)
92+
[#15385](https://github.com/rust-lang/rust-clippy/pull/15385)
93+
1194
## Rust 1.90
1295

1396
Current stable, released 2025-09-18
@@ -6253,6 +6336,7 @@ Released 2018-09-13
62536336
[`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
62546337
[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
62556338
[`empty_enum_variants_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum_variants_with_brackets
6339+
[`empty_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enums
62566340
[`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments
62576341
[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
62586342
[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
@@ -6583,6 +6667,7 @@ Released 2018-09-13
65836667
[`needless_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_else
65846668
[`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each
65856669
[`needless_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_if
6670+
[`needless_ifs`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_ifs
65866671
[`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init
65876672
[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
65886673
[`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# The Rust Code of Conduct
22

3-
The Code of Conduct for this repository [can be found online](https://www.rust-lang.org/conduct.html).
3+
The Code of Conduct for this repository [can be found online](https://rust-lang.org/policies/code-of-conduct/).

book/book.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
[book]
22
authors = ["The Rust Clippy Developers"]
33
language = "en"
4-
multilingual = false
5-
src = "src"
64
title = "Clippy Documentation"
75

86
[rust]

book/src/development/method_checking.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ use clippy_utils::sym;
2121
impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
2222
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
2323
// Check our expr is calling a method with pattern matching
24-
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
24+
if let hir::ExprKind::MethodCall(path, _, _, _) = &expr.kind
2525
// Check if the name of this method is `our_fancy_method`
2626
&& path.ident.name == sym::our_fancy_method
27-
// We can check the type of the self argument whenever necessary.
28-
// (It's necessary if we want to check that method is specifically belonging to a specific trait,
29-
// for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
27+
// Check if the method belongs to the `sym::OurFancyTrait` trait.
28+
// (for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
3029
// See the next section for more information.
31-
&& cx.ty_based_def(self_arg).opt_parent(cx).is_diag_item(cx, sym::OurFancyTrait)
30+
&& cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::OurFancyTrait)
3231
{
3332
println!("`expr` is a method call for `our_fancy_method`");
3433
}
@@ -45,6 +44,12 @@ New symbols such as `our_fancy_method` need to be added to the `clippy_utils::sy
4544
This module extends the list of symbols already provided by the compiler crates
4645
in `rustc_span::sym`.
4746

47+
If a trait defines only one method (such as the `std::ops::Deref` trait, which only has the `deref()` method),
48+
one might be tempted to omit the method name check. This would work, but is not always advisable because:
49+
- If a new method (possibly with a default implementation) were to be added to the trait, there would be a risk of
50+
matching the wrong method.
51+
- Comparing symbols is very cheap and might prevent a more expensive lookup.
52+
4853
## Checking if a `impl` block implements a method
4954

5055
While sometimes we want to check whether a method is being called or not, other

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
859859
* [`io_other_error`](https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error)
860860
* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
861861
* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)
862+
* [`len_zero`](https://rust-lang.github.io/rust-clippy/master/index.html#len_zero)
862863
* [`lines_filter_map_ok`](https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok)
863864
* [`manual_abs_diff`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff)
864865
* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)

clippy_config/src/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ define_Conf! {
748748
io_other_error,
749749
iter_kv_map,
750750
legacy_numeric_constants,
751+
len_zero,
751752
lines_filter_map_ok,
752753
manual_abs_diff,
753754
manual_bits,

clippy_dev/src/deprecate_lint.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints};
1+
use crate::parse::{DeprecatedLint, Lint, ParseCx};
2+
use crate::update_lints::generate_lint_files;
23
use crate::utils::{UpdateMode, Version};
34
use std::ffi::OsStr;
45
use std::path::{Path, PathBuf};
@@ -13,21 +14,20 @@ use std::{fs, io};
1314
/// # Panics
1415
///
1516
/// If a file path could not read from or written to
16-
pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
17-
if let Some((prefix, _)) = name.split_once("::") {
18-
panic!("`{name}` should not contain the `{prefix}` prefix");
19-
}
20-
21-
let mut lints = find_lint_decls();
22-
let (mut deprecated_lints, renamed_lints) = read_deprecated_lints();
17+
pub fn deprecate<'cx>(cx: ParseCx<'cx>, clippy_version: Version, name: &'cx str, reason: &'cx str) {
18+
let mut lints = cx.find_lint_decls();
19+
let (mut deprecated_lints, renamed_lints) = cx.read_deprecated_lints();
2320

2421
let Some(lint) = lints.iter().find(|l| l.name == name) else {
2522
eprintln!("error: failed to find lint `{name}`");
2623
return;
2724
};
2825

29-
let prefixed_name = String::from_iter(["clippy::", name]);
30-
match deprecated_lints.binary_search_by(|x| x.name.cmp(&prefixed_name)) {
26+
let prefixed_name = cx.str_buf.with(|buf| {
27+
buf.extend(["clippy::", name]);
28+
cx.arena.alloc_str(buf)
29+
});
30+
match deprecated_lints.binary_search_by(|x| x.name.cmp(prefixed_name)) {
3131
Ok(_) => {
3232
println!("`{name}` is already deprecated");
3333
return;
@@ -36,8 +36,8 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
3636
idx,
3737
DeprecatedLint {
3838
name: prefixed_name,
39-
reason: reason.into(),
40-
version: clippy_version.rust_display().to_string(),
39+
reason,
40+
version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()),
4141
},
4242
),
4343
}
@@ -61,8 +61,8 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
6161
}
6262
}
6363

64-
fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io::Result<bool> {
65-
fn remove_lint(name: &str, lints: &mut Vec<Lint>) {
64+
fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint<'_>>) -> io::Result<bool> {
65+
fn remove_lint(name: &str, lints: &mut Vec<Lint<'_>>) {
6666
lints.iter().position(|l| l.name == name).map(|pos| lints.remove(pos));
6767
}
6868

@@ -135,14 +135,14 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
135135
);
136136

137137
assert!(
138-
content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
138+
content[lint.declaration_range].contains(&name.to_uppercase()),
139139
"error: `{}` does not contain lint `{}`'s declaration",
140140
path.display(),
141141
lint.name
142142
);
143143

144144
// Remove lint declaration (declare_clippy_lint!)
145-
content.replace_range(lint.declaration_range.clone(), "");
145+
content.replace_range(lint.declaration_range, "");
146146

147147
// Remove the module declaration (mod xyz;)
148148
let mod_decl = format!("\nmod {name};");

clippy_dev/src/fmt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ fn run_rustfmt(update_mode: UpdateMode) {
268268
.expect("invalid rustfmt path");
269269
rustfmt_path.truncate(rustfmt_path.trim_end().len());
270270

271-
let args: Vec<_> = walk_dir_no_dot_or_target()
271+
let args: Vec<_> = walk_dir_no_dot_or_target(".")
272272
.filter_map(|e| {
273273
let e = expect_action(e, ErrAction::Read, ".");
274274
e.path()

clippy_dev/src/lib.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#![feature(
2-
rustc_private,
32
exit_status_error,
43
if_let_guard,
4+
new_range,
5+
new_range_api,
56
os_str_slice,
67
os_string_truncate,
8+
pattern,
9+
rustc_private,
710
slice_split_once
811
)]
912
#![warn(
@@ -15,6 +18,7 @@
1518
)]
1619
#![allow(clippy::missing_panics_doc)]
1720

21+
extern crate rustc_arena;
1822
#[expect(unused_extern_crates, reason = "required to link to rustc crates")]
1923
extern crate rustc_driver;
2024
extern crate rustc_lexer;
@@ -32,5 +36,8 @@ pub mod setup;
3236
pub mod sync;
3337
pub mod update_lints;
3438

39+
mod parse;
3540
mod utils;
36-
pub use utils::{ClippyInfo, UpdateMode};
41+
42+
pub use self::parse::{ParseCx, new_parse_cx};
43+
pub use self::utils::{ClippyInfo, UpdateMode};

clippy_dev/src/main.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
use clap::{Args, Parser, Subcommand};
66
use clippy_dev::{
7-
ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync,
8-
update_lints,
7+
ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, new_parse_cx, release, rename_lint, serve,
8+
setup, sync, update_lints,
99
};
10-
use std::convert::Infallible;
1110
use std::env;
1211

1312
fn main() {
@@ -28,15 +27,15 @@ fn main() {
2827
allow_no_vcs,
2928
} => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
3029
DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)),
31-
DevCommand::UpdateLints { check } => update_lints::update(UpdateMode::from_check(check)),
30+
DevCommand::UpdateLints { check } => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::from_check(check))),
3231
DevCommand::NewLint {
3332
pass,
3433
name,
3534
category,
3635
r#type,
3736
msrv,
3837
} => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) {
39-
Ok(()) => update_lints::update(UpdateMode::Change),
38+
Ok(()) => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::Change)),
4039
Err(e) => eprintln!("Unable to create lint: {e}"),
4140
},
4241
DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
@@ -79,13 +78,18 @@ fn main() {
7978
old_name,
8079
new_name,
8180
uplift,
82-
} => rename_lint::rename(
83-
clippy.version,
84-
&old_name,
85-
new_name.as_ref().unwrap_or(&old_name),
86-
uplift,
87-
),
88-
DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason),
81+
} => new_parse_cx(|cx| {
82+
rename_lint::rename(
83+
cx,
84+
clippy.version,
85+
&old_name,
86+
new_name.as_ref().unwrap_or(&old_name),
87+
uplift,
88+
);
89+
}),
90+
DevCommand::Deprecate { name, reason } => {
91+
new_parse_cx(|cx| deprecate_lint::deprecate(cx, clippy.version, &name, &reason));
92+
},
8993
DevCommand::Sync(SyncCommand { subcommand }) => match subcommand {
9094
SyncSubcommand::UpdateNightly => sync::update_nightly(),
9195
},
@@ -95,6 +99,20 @@ fn main() {
9599
}
96100
}
97101

102+
fn lint_name(name: &str) -> Result<String, String> {
103+
let name = name.replace('-', "_");
104+
if let Some((pre, _)) = name.split_once("::") {
105+
Err(format!("lint name should not contain the `{pre}` prefix"))
106+
} else if name
107+
.bytes()
108+
.any(|x| !matches!(x, b'_' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z'))
109+
{
110+
Err("lint name contains invalid characters".to_owned())
111+
} else {
112+
Ok(name)
113+
}
114+
}
115+
98116
#[derive(Parser)]
99117
#[command(name = "dev", about)]
100118
struct Dev {
@@ -150,7 +168,7 @@ enum DevCommand {
150168
#[arg(
151169
short,
152170
long,
153-
value_parser = |name: &str| Ok::<_, Infallible>(name.replace('-', "_")),
171+
value_parser = lint_name,
154172
)]
155173
/// Name of the new lint in snake case, ex: `fn_too_long`
156174
name: String,
@@ -223,8 +241,12 @@ enum DevCommand {
223241
/// Rename a lint
224242
RenameLint {
225243
/// The name of the lint to rename
244+
#[arg(value_parser = lint_name)]
226245
old_name: String,
227-
#[arg(required_unless_present = "uplift")]
246+
#[arg(
247+
required_unless_present = "uplift",
248+
value_parser = lint_name,
249+
)]
228250
/// The new name of the lint
229251
new_name: Option<String>,
230252
#[arg(long)]
@@ -234,6 +256,7 @@ enum DevCommand {
234256
/// Deprecate the given lint
235257
Deprecate {
236258
/// The name of the lint to deprecate
259+
#[arg(value_parser = lint_name)]
237260
name: String,
238261
#[arg(long, short)]
239262
/// The reason for deprecation

0 commit comments

Comments
 (0)