@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
2
2
use clippy_utils:: source:: { snippet_with_applicability, snippet_with_context} ;
3
3
use clippy_utils:: sugg:: has_enclosing_paren;
4
4
use clippy_utils:: ty:: { contains_ty, expr_sig, is_copy, peel_mid_ty_refs, variant_of_res} ;
5
- use clippy_utils:: { fn_def_id, get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage} ;
5
+ use clippy_utils:: { fn_def_id, get_parent_expr, is_lint_allowed, meets_msrv , msrvs , path_to_local, walk_to_expr_usage} ;
6
6
use rustc_ast:: util:: parser:: { PREC_POSTFIX , PREC_PREFIX } ;
7
7
use rustc_data_structures:: fx:: FxIndexMap ;
8
8
use rustc_errors:: Applicability ;
@@ -17,9 +17,10 @@ use rustc_infer::infer::TyCtxtInferExt;
17
17
use rustc_lint:: { LateContext , LateLintPass } ;
18
18
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AutoBorrow , AutoBorrowMutability } ;
19
19
use rustc_middle:: ty:: {
20
- self , subst:: Subst , EarlyBinder , FnSig , ParamTy , PredicateKind , ProjectionPredicate , Ty , TyCtxt , TypeVisitable ,
21
- TypeckResults ,
20
+ self , subst:: Subst , EarlyBinder , FnSig , GenericArgKind , ParamTy , PredicateKind , ProjectionPredicate , Ty , TyCtxt ,
21
+ TypeVisitable , TypeckResults ,
22
22
} ;
23
+ use rustc_semver:: RustcVersion ;
23
24
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
24
25
use rustc_span:: { symbol:: sym, Span , Symbol } ;
25
26
use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -157,13 +158,27 @@ pub struct Dereferencing {
157
158
/// been finished. Note we can't lint at the end of every body as they can be nested within each
158
159
/// other.
159
160
current_body : Option < BodyId > ,
161
+
160
162
/// The list of locals currently being checked by the lint.
161
163
/// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
162
164
/// This is needed for or patterns where one of the branches can be linted, but another can not
163
165
/// be.
164
166
///
165
167
/// e.g. `m!(x) | Foo::Bar(ref x)`
166
168
ref_locals : FxIndexMap < HirId , Option < RefPat > > ,
169
+
170
+ // `IntoIterator` for arrays requires Rust 1.53.
171
+ msrv : Option < RustcVersion > ,
172
+ }
173
+
174
+ impl Dereferencing {
175
+ #[ must_use]
176
+ pub fn new ( msrv : Option < RustcVersion > ) -> Self {
177
+ Self {
178
+ msrv,
179
+ ..Dereferencing :: default ( )
180
+ }
181
+ }
167
182
}
168
183
169
184
struct StateData {
@@ -257,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
257
272
match ( self . state . take ( ) , kind) {
258
273
( None , kind) => {
259
274
let expr_ty = typeck. expr_ty ( expr) ;
260
- let ( position, adjustments) = walk_parents ( cx, expr) ;
275
+ let ( position, adjustments) = walk_parents ( cx, expr, self . msrv ) ;
261
276
262
277
match kind {
263
278
RefOp :: Deref => {
@@ -564,6 +579,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
564
579
self . current_body = None ;
565
580
}
566
581
}
582
+
583
+ extract_msrv_attr ! ( LateContext ) ;
567
584
}
568
585
569
586
fn try_parse_ref_op < ' tcx > (
@@ -660,7 +677,11 @@ impl Position {
660
677
/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
661
678
/// locations as those follow different rules.
662
679
#[ expect( clippy:: too_many_lines) ]
663
- fn walk_parents < ' tcx > ( cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > ) -> ( Position , & ' tcx [ Adjustment < ' tcx > ] ) {
680
+ fn walk_parents < ' tcx > (
681
+ cx : & LateContext < ' tcx > ,
682
+ e : & ' tcx Expr < ' _ > ,
683
+ msrv : Option < RustcVersion > ,
684
+ ) -> ( Position , & ' tcx [ Adjustment < ' tcx > ] ) {
664
685
let mut adjustments = [ ] . as_slice ( ) ;
665
686
let mut precedence = 0i8 ;
666
687
let ctxt = e. span . ctxt ( ) ;
@@ -770,7 +791,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
770
791
Some ( ty) => binding_ty_auto_deref_stability ( ty, precedence) ,
771
792
None => {
772
793
if let ty:: Param ( param_ty) = ty. skip_binder ( ) . kind ( ) {
773
- needless_borrow_impl_arg_position ( cx, parent, i, * param_ty, e, precedence)
794
+ needless_borrow_impl_arg_position ( cx, parent, i, * param_ty, e, precedence, msrv )
774
795
} else {
775
796
param_auto_deref_stability ( ty. skip_binder ( ) , precedence)
776
797
}
@@ -818,7 +839,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
818
839
} else {
819
840
let ty = cx. tcx . fn_sig ( id) . skip_binder ( ) . inputs ( ) [ i] ;
820
841
if let ty:: Param ( param_ty) = ty. kind ( ) {
821
- needless_borrow_impl_arg_position ( cx, parent, i, * param_ty, e, precedence)
842
+ needless_borrow_impl_arg_position ( cx, parent, i, * param_ty, e, precedence, msrv )
822
843
} else {
823
844
param_auto_deref_stability ( ty, precedence)
824
845
}
@@ -957,7 +978,9 @@ fn needless_borrow_impl_arg_position<'tcx>(
957
978
param_ty : ParamTy ,
958
979
mut expr : & Expr < ' tcx > ,
959
980
precedence : i8 ,
981
+ msrv : Option < RustcVersion > ,
960
982
) -> Position {
983
+ let destruct_trait_def_id = cx. tcx . lang_items ( ) . destruct_trait ( ) ;
961
984
let sized_trait_def_id = cx. tcx . lang_items ( ) . sized_trait ( ) ;
962
985
963
986
let Some ( callee_def_id) = fn_def_id ( cx, parent) else { return Position :: Other ( precedence) } ;
@@ -984,7 +1007,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
984
1007
985
1008
let mut trait_with_ref_mut_self_method = false ;
986
1009
987
- // If no traits were found, or only the `Sized` or `Any` traits were found, return.
1010
+ // If no traits were found, or only the `Destruct`, ` Sized`, or `Any` traits were found, return.
988
1011
if predicates
989
1012
. iter ( )
990
1013
. filter_map ( |predicate| {
@@ -1000,7 +1023,9 @@ fn needless_borrow_impl_arg_position<'tcx>(
1000
1023
trait_with_ref_mut_self_method |= has_ref_mut_self_method ( cx, * trait_def_id) ;
1001
1024
} )
1002
1025
. all ( |trait_def_id| {
1003
- Some ( trait_def_id) == sized_trait_def_id || cx. tcx . is_diagnostic_item ( sym:: Any , trait_def_id)
1026
+ Some ( trait_def_id) == destruct_trait_def_id
1027
+ || Some ( trait_def_id) == sized_trait_def_id
1028
+ || cx. tcx . is_diagnostic_item ( sym:: Any , trait_def_id)
1004
1029
} )
1005
1030
{
1006
1031
return Position :: Other ( precedence) ;
@@ -1035,6 +1060,16 @@ fn needless_borrow_impl_arg_position<'tcx>(
1035
1060
}
1036
1061
1037
1062
predicates. iter ( ) . all ( |predicate| {
1063
+ if let PredicateKind :: Trait ( trait_predicate) = predicate. kind ( ) . skip_binder ( )
1064
+ && cx. tcx . is_diagnostic_item ( sym:: IntoIterator , trait_predicate. trait_ref . def_id )
1065
+ && let ty:: Param ( param_ty) = trait_predicate. self_ty ( ) . kind ( )
1066
+ && let GenericArgKind :: Type ( ty) = substs_with_referent_ty[ param_ty. index as usize ] . unpack ( )
1067
+ && ty. is_array ( )
1068
+ && !meets_msrv ( msrv, msrvs:: ARRAY_INTO_ITERATOR )
1069
+ {
1070
+ return false ;
1071
+ }
1072
+
1038
1073
let predicate = EarlyBinder ( predicate) . subst ( cx. tcx , & substs_with_referent_ty) ;
1039
1074
let obligation = Obligation :: new ( ObligationCause :: dummy ( ) , cx. param_env , predicate) ;
1040
1075
cx. tcx
0 commit comments