Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0924d62

Browse files
committed
Merge remote-tracking branch 'upstream/master' into sync-from-rust
2 parents f303168 + 403816f commit 0924d62

File tree

60 files changed

+1129
-216
lines changed

Some content is hidden

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

60 files changed

+1129
-216
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,32 @@ cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
194194
```
195195
Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`.
196196

197+
### Specifying the minimum supported Rust version
198+
199+
Projects that intend to support old versions of Rust can disable lints pertaining to newer features by
200+
specifying the minimum supported Rust version (MSRV) in the clippy configuration file.
201+
202+
```toml
203+
msrv = "1.30.0"
204+
```
205+
206+
The MSRV can also be specified as an inner attribute, like below.
207+
208+
```rust
209+
#![feature(custom_inner_attributes)]
210+
#![clippy::msrv = "1.30.0"]
211+
212+
fn main() {
213+
...
214+
}
215+
```
216+
217+
Tilde/Caret version requirements (like `^1.0` or `~1.2`) can be specified as well.
218+
219+
Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly.
220+
221+
Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv)
222+
197223
## Contributing
198224

199225
If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md).

clippy_lints/src/deprecated_lints.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,6 @@ declare_deprecated_lint! {
5151
"`Vec::as_mut_slice` has been stabilized in 1.7"
5252
}
5353

54-
declare_deprecated_lint! {
55-
/// **What it does:** Nothing. This lint has been deprecated.
56-
///
57-
/// **Deprecation reason:** This used to check for `.to_string()` method calls on values
58-
/// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be
59-
/// specialized to be as efficient as `to_owned`.
60-
pub STR_TO_STRING,
61-
"using `str::to_string` is common even today and specialization will likely happen soon"
62-
}
63-
64-
declare_deprecated_lint! {
65-
/// **What it does:** Nothing. This lint has been deprecated.
66-
///
67-
/// **Deprecation reason:** This used to check for `.to_string()` method calls on values
68-
/// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be
69-
/// specialized to be as efficient as `clone`.
70-
pub STRING_TO_STRING,
71-
"using `string::to_string` is common even today and specialization will likely happen soon"
72-
}
73-
7454
declare_deprecated_lint! {
7555
/// **What it does:** Nothing. This lint has been deprecated.
7656
///

clippy_lints/src/future_not_send.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
9292
|db| {
9393
cx.tcx.infer_ctxt().enter(|infcx| {
9494
for FulfillmentError { obligation, .. } in send_errors {
95-
infcx.maybe_note_obligation_cause_for_async_await(
96-
db,
97-
&obligation,
98-
);
99-
if let Trait(trait_pred, _) =
100-
obligation.predicate.skip_binders()
101-
{
95+
infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
96+
if let Trait(trait_pred, _) = obligation.predicate.skip_binders() {
10297
db.note(&format!(
10398
"`{}` doesn't implement `{}`",
10499
trait_pred.self_ty(),

clippy_lints/src/lib.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern crate rustc_target;
4444
extern crate rustc_trait_selection;
4545
extern crate rustc_typeck;
4646

47+
use crate::utils::parse_msrv;
4748
use rustc_data_structures::fx::FxHashSet;
4849
use rustc_lint::LintId;
4950
use rustc_session::Session;
@@ -440,14 +441,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
440441
"clippy::unstable_as_mut_slice",
441442
"`Vec::as_mut_slice` has been stabilized in 1.7",
442443
);
443-
store.register_removed(
444-
"clippy::str_to_string",
445-
"using `str::to_string` is common even today and specialization will likely happen soon",
446-
);
447-
store.register_removed(
448-
"clippy::string_to_string",
449-
"using `string::to_string` is common even today and specialization will likely happen soon",
450-
);
451444
store.register_removed(
452445
"clippy::misaligned_transmute",
453446
"this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
@@ -839,6 +832,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
839832
&strings::STRING_ADD_ASSIGN,
840833
&strings::STRING_FROM_UTF8_AS_BYTES,
841834
&strings::STRING_LIT_AS_BYTES,
835+
&strings::STRING_TO_STRING,
836+
&strings::STR_TO_STRING,
842837
&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
843838
&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
844839
&swap::ALMOST_SWAPPED,
@@ -933,7 +928,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
933928
&zero_div_zero::ZERO_DIVIDED_BY_ZERO,
934929
]);
935930
// end register lints, do not remove this comment, it’s used in `update_lints`
936-
937931
store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
938932
store.register_late_pass(|| box serde_api::SerdeAPI);
939933
store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
@@ -969,7 +963,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
969963
store.register_late_pass(|| box strings::StringAdd);
970964
store.register_late_pass(|| box implicit_return::ImplicitReturn);
971965
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
972-
store.register_late_pass(|| box methods::Methods);
966+
967+
let parsed_msrv = conf.msrv.as_ref().and_then(|s| {
968+
parse_msrv(s, None, None).or_else(|| {
969+
sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
970+
None
971+
})
972+
});
973+
974+
let msrv = parsed_msrv.clone();
975+
store.register_late_pass(move || box methods::Methods::new(msrv.clone()));
976+
let msrv = parsed_msrv.clone();
977+
store.register_late_pass(move || box matches::Matches::new(msrv.clone()));
978+
let msrv = parsed_msrv.clone();
979+
store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone()));
980+
let msrv = parsed_msrv;
981+
store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone()));
982+
973983
store.register_late_pass(|| box map_clone::MapClone);
974984
store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
975985
store.register_late_pass(|| box shadow::Shadow);
@@ -983,7 +993,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
983993
store.register_late_pass(|| box types::Casts);
984994
let type_complexity_threshold = conf.type_complexity_threshold;
985995
store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
986-
store.register_late_pass(|| box matches::Matches::default());
987996
store.register_late_pass(|| box minmax::MinMaxPass);
988997
store.register_late_pass(|| box open_options::OpenOptions);
989998
store.register_late_pass(|| box zero_div_zero::ZeroDiv);
@@ -1144,7 +1153,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11441153
store.register_late_pass(|| box if_let_mutex::IfLetMutex);
11451154
store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
11461155
store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
1147-
store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
11481156
store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
11491157
store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
11501158
store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
@@ -1166,13 +1174,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11661174
store.register_late_pass(|| box manual_ok_or::ManualOkOr);
11671175
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
11681176
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
1169-
store.register_late_pass(|| box manual_strip::ManualStrip);
11701177
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
11711178
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
11721179
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
11731180
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
11741181
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
11751182
store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
1183+
store.register_late_pass(|| box strings::StrToString);
1184+
store.register_late_pass(|| box strings::StringToString);
11761185

11771186

11781187
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1215,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12151224
LintId::of(&shadow::SHADOW_REUSE),
12161225
LintId::of(&shadow::SHADOW_SAME),
12171226
LintId::of(&strings::STRING_ADD),
1227+
LintId::of(&strings::STRING_TO_STRING),
1228+
LintId::of(&strings::STR_TO_STRING),
12181229
LintId::of(&types::RC_BUFFER),
12191230
LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
12201231
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
@@ -1930,14 +1941,6 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
19301941
"unstable_as_mut_slice",
19311942
"`Vec::as_mut_slice` has been stabilized in 1.7",
19321943
);
1933-
store.register_removed(
1934-
"str_to_string",
1935-
"using `str::to_string` is common even today and specialization will likely happen soon",
1936-
);
1937-
store.register_removed(
1938-
"string_to_string",
1939-
"using `string::to_string` is common even today and specialization will likely happen soon",
1940-
);
19411944
store.register_removed(
19421945
"misaligned_transmute",
19431946
"this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",

clippy_lints/src/loops.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2950,7 +2950,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
29502950
for ref stmt in block.stmts {
29512951
if_chain! {
29522952
if let StmtKind::Local(
2953-
Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. },
2953+
Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
29542954
init: Some(ref init_expr), .. }
29552955
) = stmt.kind;
29562956
if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
@@ -2964,6 +2964,16 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
29642964
if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
29652965
if iter_calls.len() == 1;
29662966
then {
2967+
let mut used_count_visitor = UsedCountVisitor {
2968+
cx,
2969+
id: *pat_id,
2970+
count: 0,
2971+
};
2972+
walk_block(&mut used_count_visitor, block);
2973+
if used_count_visitor.count > 1 {
2974+
return;
2975+
}
2976+
29672977
// Suggest replacing iter_call with iter_replacement, and removing stmt
29682978
let iter_call = &iter_calls[0];
29692979
span_lint_and_then(
@@ -3087,6 +3097,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
30873097
}
30883098
}
30893099

3100+
struct UsedCountVisitor<'a, 'tcx> {
3101+
cx: &'a LateContext<'tcx>,
3102+
id: HirId,
3103+
count: usize,
3104+
}
3105+
3106+
impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
3107+
type Map = Map<'tcx>;
3108+
3109+
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
3110+
if same_var(self.cx, expr, self.id) {
3111+
self.count += 1;
3112+
} else {
3113+
walk_expr(self, expr);
3114+
}
3115+
}
3116+
3117+
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
3118+
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
3119+
}
3120+
}
3121+
30903122
/// Detect the occurrences of calls to `iter` or `into_iter` for the
30913123
/// given identifier
30923124
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {

clippy_lints/src/manual_non_exhaustive.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
use crate::utils::{snippet_opt, span_lint_and_then};
1+
use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then};
22
use if_chain::if_chain;
33
use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind};
44
use rustc_attr as attr;
55
use rustc_errors::Applicability;
66
use rustc_lint::{EarlyContext, EarlyLintPass};
7-
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
use rustc_session::{declare_tool_lint, impl_lint_pass};
88
use rustc_span::{sym, Span};
9+
use semver::{Version, VersionReq};
10+
11+
const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version {
12+
major: 1,
13+
minor: 40,
14+
patch: 0,
15+
pre: Vec::new(),
16+
build: Vec::new(),
17+
};
918

1019
declare_clippy_lint! {
1120
/// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
@@ -55,10 +64,26 @@ declare_clippy_lint! {
5564
"manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
5665
}
5766

58-
declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
67+
#[derive(Clone)]
68+
pub struct ManualNonExhaustive {
69+
msrv: Option<VersionReq>,
70+
}
71+
72+
impl ManualNonExhaustive {
73+
#[must_use]
74+
pub fn new(msrv: Option<VersionReq>) -> Self {
75+
Self { msrv }
76+
}
77+
}
78+
79+
impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
5980

6081
impl EarlyLintPass for ManualNonExhaustive {
6182
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
83+
if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) {
84+
return;
85+
}
86+
6287
match &item.kind {
6388
ItemKind::Enum(def, _) => {
6489
check_manual_non_exhaustive_enum(cx, item, &def.variants);
@@ -73,6 +98,8 @@ impl EarlyLintPass for ManualNonExhaustive {
7398
_ => {},
7499
}
75100
}
101+
102+
extract_msrv_attr!(EarlyContext);
76103
}
77104

78105
fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {

clippy_lints/src/manual_strip.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::consts::{constant, Constant};
22
use crate::utils::usage::mutated_variables;
33
use crate::utils::{
4-
eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
4+
eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
55
};
66

77
use if_chain::if_chain;
@@ -10,12 +10,21 @@ use rustc_hir::def::Res;
1010
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
1111
use rustc_hir::BinOpKind;
1212
use rustc_hir::{BorrowKind, Expr, ExprKind};
13-
use rustc_lint::{LateContext, LateLintPass};
13+
use rustc_lint::{LateContext, LateLintPass, LintContext};
1414
use rustc_middle::hir::map::Map;
1515
use rustc_middle::ty;
16-
use rustc_session::{declare_lint_pass, declare_tool_lint};
16+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1717
use rustc_span::source_map::Spanned;
1818
use rustc_span::Span;
19+
use semver::{Version, VersionReq};
20+
21+
const MANUAL_STRIP_MSRV: Version = Version {
22+
major: 1,
23+
minor: 45,
24+
patch: 0,
25+
pre: Vec::new(),
26+
build: Vec::new(),
27+
};
1928

2029
declare_clippy_lint! {
2130
/// **What it does:**
@@ -51,7 +60,18 @@ declare_clippy_lint! {
5160
"suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
5261
}
5362

54-
declare_lint_pass!(ManualStrip => [MANUAL_STRIP]);
63+
pub struct ManualStrip {
64+
msrv: Option<VersionReq>,
65+
}
66+
67+
impl ManualStrip {
68+
#[must_use]
69+
pub fn new(msrv: Option<VersionReq>) -> Self {
70+
Self { msrv }
71+
}
72+
}
73+
74+
impl_lint_pass!(ManualStrip => [MANUAL_STRIP]);
5575

5676
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5777
enum StripKind {
@@ -61,6 +81,10 @@ enum StripKind {
6181

6282
impl<'tcx> LateLintPass<'tcx> for ManualStrip {
6383
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
84+
if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
85+
return;
86+
}
87+
6488
if_chain! {
6589
if let Some((cond, then, _)) = higher::if_block(&expr);
6690
if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
@@ -114,6 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
114138
}
115139
}
116140
}
141+
142+
extract_msrv_attr!(LateContext);
117143
}
118144

119145
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.

0 commit comments

Comments
 (0)