Skip to content

Commit 7f4b539

Browse files
committed
Merge remote-tracking branch 'upstream/master' into rustup
2 parents 7a3097f + 03dd624 commit 7f4b539

File tree

173 files changed

+6305
-944
lines changed

Some content is hidden

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

173 files changed

+6305
-944
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6916,6 +6916,7 @@ Released 2018-09-13
69166916
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
69176917
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
69186918
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
6919+
[`same_length_and_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_length_and_capacity
69196920
[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
69206921
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
69216922
[`seek_from_current`]: https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current

clippy_lints/src/assertions_on_constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
33
use clippy_utils::diagnostics::span_lint_and_help;
44
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node};
55
use clippy_utils::msrvs::Msrv;
6+
use clippy_utils::visitors::is_const_evaluatable;
67
use clippy_utils::{is_inside_always_const_context, msrvs};
78
use rustc_ast::LitKind;
89
use rustc_hir::{Expr, ExprKind};
@@ -50,6 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
5051
_ => return,
5152
}
5253
&& let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn)
54+
&& is_const_evaluatable(cx, condition)
5355
&& let Some((Constant::Bool(assert_val), const_src)) =
5456
ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt())
5557
&& let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id)

clippy_lints/src/booleans.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
433433
},
434434
ExprKind::MethodCall(path, receiver, args, _) => {
435435
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
436-
if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) {
436+
if !matches!(type_of_receiver.opt_diag_name(cx), Some(sym::Option | sym::Result)) {
437437
return None;
438438
}
439439
METHODS_WITH_NEGATION

clippy_lints/src/casts/cast_precision_loss.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,21 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
2323

2424
let cast_to_f64 = to_nbits == 64;
2525
let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
26-
let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
27-
let arch_dependent_str = "on targets with 64-bit wide pointers ";
28-
let from_nbits_str = if arch_dependent {
29-
"64".to_owned()
30-
} else if is_isize_or_usize(cast_from) {
31-
// FIXME: handle 16 bits `usize` type
32-
"32 or 64".to_owned()
26+
27+
let has_width = if is_isize_or_usize(cast_from) {
28+
"can be up to 64 bits wide depending on the target architecture".to_owned()
3329
} else {
34-
from_nbits.to_string()
30+
format!("is {from_nbits} bits wide")
3531
};
3632

3733
span_lint(
3834
cx,
3935
CAST_PRECISION_LOSS,
4036
expr.span,
4137
format!(
42-
"casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
43-
but `{1}`'s mantissa is only {4} bits wide)",
44-
cast_from,
45-
if cast_to_f64 { "f64" } else { "f32" },
46-
if arch_dependent { arch_dependent_str } else { "" },
47-
from_nbits_str,
48-
mantissa_nbits
38+
"casting `{cast_from}` to `{cast_to}` may cause a loss of precision \
39+
(`{cast_from}` {has_width}, \
40+
but `{cast_to}`'s mantissa is only {mantissa_nbits} bits wide)",
4941
),
5042
);
5143
}

clippy_lints/src/casts/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ declare_clippy_lint! {
836836
/// ```
837837
#[clippy::version = "1.93.0"]
838838
pub NEEDLESS_TYPE_CAST,
839-
pedantic,
839+
nursery,
840840
"binding defined with one type but always cast to another"
841841
}
842842

clippy_lints/src/casts/needless_type_cast.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::sugg::Sugg;
23
use clippy_utils::visitors::{Descend, for_each_expr, for_each_expr_without_closures};
34
use core::ops::ControlFlow;
5+
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
46
use rustc_data_structures::fx::FxHashMap;
57
use rustc_errors::Applicability;
68
use rustc_hir::def::{DefKind, Res};
@@ -14,6 +16,7 @@ use super::NEEDLESS_TYPE_CAST;
1416
struct BindingInfo<'a> {
1517
source_ty: Ty<'a>,
1618
ty_span: Span,
19+
init: Option<&'a Expr<'a>>,
1720
}
1821

1922
struct UsageInfo<'a> {
@@ -73,6 +76,7 @@ fn collect_binding_from_let<'a>(
7376
BindingInfo {
7477
source_ty: ty,
7578
ty_span: ty_hir.span,
79+
init: Some(let_expr.init),
7680
},
7781
);
7882
}
@@ -103,6 +107,7 @@ fn collect_binding_from_local<'a>(
103107
BindingInfo {
104108
source_ty: ty,
105109
ty_span: ty_hir.span,
110+
init: let_stmt.init,
106111
},
107112
);
108113
}
@@ -182,12 +187,7 @@ fn is_generic_res(cx: &LateContext<'_>, res: Res) -> bool {
182187
.iter()
183188
.any(|p| p.kind.is_ty_or_const())
184189
};
185-
match res {
186-
Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => has_type_params(def_id),
187-
// Ctor → Variant → ADT: constructor's parent is variant, variant's parent is the ADT
188-
Res::Def(DefKind::Ctor(..), def_id) => has_type_params(cx.tcx.parent(cx.tcx.parent(def_id))),
189-
_ => false,
190-
}
190+
cx.tcx.res_generics_def_id(res).is_some_and(has_type_params)
191191
}
192192

193193
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>) ->
234234
}
235235
}
236236

237+
fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool {
238+
match expr.kind {
239+
ExprKind::Lit(lit) => matches!(
240+
lit.node,
241+
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
242+
),
243+
ExprKind::Unary(rustc_hir::UnOp::Neg, inner) => can_coerce_to_target_type(inner),
244+
ExprKind::Binary(_, lhs, rhs) => can_coerce_to_target_type(lhs) && can_coerce_to_target_type(rhs),
245+
_ => false,
246+
}
247+
}
248+
237249
fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) {
238250
let mut usages = Vec::new();
239251

@@ -274,16 +286,48 @@ fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId
274286
return;
275287
};
276288

277-
span_lint_and_sugg(
289+
// Don't lint if there's exactly one use and the initializer cannot be coerced to the
290+
// target type (i.e., would require an explicit cast). In such cases, the fix would add
291+
// a cast to the initializer rather than eliminating one - the cast isn't truly "needless."
292+
// See: https://github.com/rust-lang/rust-clippy/issues/16240
293+
if usages.len() == 1
294+
&& binding_info
295+
.init
296+
.is_some_and(|init| !can_coerce_to_target_type(init) && !init.span.from_expansion())
297+
{
298+
return;
299+
}
300+
301+
span_lint_and_then(
278302
cx,
279303
NEEDLESS_TYPE_CAST,
280304
binding_info.ty_span,
281305
format!(
282306
"this binding is defined as `{}` but is always cast to `{}`",
283307
binding_info.source_ty, first_target
284308
),
285-
"consider defining it as",
286-
first_target.to_string(),
287-
Applicability::MaybeIncorrect,
309+
|diag| {
310+
if let Some(init) = binding_info
311+
.init
312+
.filter(|i| !can_coerce_to_target_type(i) && !i.span.from_expansion())
313+
{
314+
let sugg = Sugg::hir(cx, init, "..").as_ty(first_target);
315+
diag.multipart_suggestion(
316+
format!("consider defining it as `{first_target}` and casting the initializer"),
317+
vec![
318+
(binding_info.ty_span, first_target.to_string()),
319+
(init.span, sugg.to_string()),
320+
],
321+
Applicability::MachineApplicable,
322+
);
323+
} else {
324+
diag.span_suggestion(
325+
binding_info.ty_span,
326+
"consider defining it as",
327+
first_target.to_string(),
328+
Applicability::MachineApplicable,
329+
);
330+
}
331+
},
288332
);
289333
}

clippy_lints/src/casts/ref_as_ptr.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet_with_applicability;
33
use clippy_utils::sugg::Sugg;
4-
use clippy_utils::{ExprUseNode, expr_use_ctxt, std_or_core};
4+
use clippy_utils::{ExprUseNode, expr_use_ctxt, is_expr_temporary_value, std_or_core};
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Expr, Mutability, Ty, TyKind};
6+
use rustc_hir::{Expr, ExprKind, Mutability, Ty, TyKind};
77
use rustc_lint::LateContext;
88
use rustc_middle::ty;
99

@@ -23,10 +23,18 @@ pub(super) fn check<'tcx>(
2323
if matches!(cast_from.kind(), ty::Ref(..))
2424
&& let ty::RawPtr(_, to_mutbl) = cast_to.kind()
2525
&& let use_cx = expr_use_ctxt(cx, expr)
26-
// TODO: only block the lint if `cast_expr` is a temporary
27-
&& !matches!(use_cx.use_node(cx), ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
2826
&& let Some(std_or_core) = std_or_core(cx)
2927
{
28+
if let ExprKind::AddrOf(_, _, addr_inner) = cast_expr.kind
29+
&& is_expr_temporary_value(cx, addr_inner)
30+
&& matches!(
31+
use_cx.use_node(cx),
32+
ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_)
33+
)
34+
{
35+
return;
36+
}
37+
3038
let fn_name = match to_mutbl {
3139
Mutability::Not => "from_ref",
3240
Mutability::Mut => "from_mut",

clippy_lints/src/collapsible_if.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ declare_clippy_lint! {
7676
/// ```
7777
#[clippy::version = "1.51.0"]
7878
pub COLLAPSIBLE_ELSE_IF,
79-
style,
79+
pedantic,
8080
"nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)"
8181
}
8282

@@ -267,6 +267,9 @@ impl LateLintPass<'_> for CollapsibleIf {
267267
&& !expr.span.from_expansion()
268268
{
269269
if let Some(else_) = else_
270+
// Short circuit if both `if` branches contain only a single `if {..} else {}`, as
271+
// collapsing such blocks can lead to less readable code (#4971)
272+
&& !(single_inner_if_else(then) && single_inner_if_else(else_))
270273
&& let ExprKind::Block(else_, None) = else_.kind
271274
{
272275
self.check_collapsible_else_if(cx, then.span, else_);
@@ -280,6 +283,19 @@ impl LateLintPass<'_> for CollapsibleIf {
280283
}
281284
}
282285

286+
/// Returns true if `expr` is a block that contains only one `if {..} else {}` statement
287+
fn single_inner_if_else(expr: &Expr<'_>) -> bool {
288+
if let ExprKind::Block(block, None) = expr.kind
289+
&& let Some(inner_expr) = expr_block(block)
290+
&& let ExprKind::If(_, _, else_) = inner_expr.kind
291+
&& else_.is_some()
292+
{
293+
true
294+
} else {
295+
false
296+
}
297+
}
298+
283299
/// If `block` is a block with either one expression or a statement containing an expression,
284300
/// return the expression. We don't peel blocks recursively, as extra blocks might be intentional.
285301
fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
667667
crate::returns::LET_AND_RETURN_INFO,
668668
crate::returns::NEEDLESS_RETURN_INFO,
669669
crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO,
670+
crate::same_length_and_capacity::SAME_LENGTH_AND_CAPACITY_INFO,
670671
crate::same_name_method::SAME_NAME_METHOD_INFO,
671672
crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
672673
crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,

clippy_lints/src/disallowed_methods.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]);
8888

8989
impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
9090
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
91+
if expr.span.desugaring_kind().is_some() {
92+
return;
93+
}
9194
let (id, span) = match &expr.kind {
9295
ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span),
9396
ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {

0 commit comments

Comments
 (0)