@@ -241,14 +241,26 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
241241}
242242
243243fn check_reversed_empty_range ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
244- fn inside_indexing_expr < ' a > ( cx : & ' a LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) -> Option < & ' a Expr < ' a > > {
245- match get_parent_expr ( cx, expr) {
246- parent_expr @ Some ( Expr {
244+ fn inside_indexing_expr ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) -> bool {
245+ matches ! (
246+ get_parent_expr( cx, expr) ,
247+ Some ( Expr {
247248 kind: ExprKind :: Index ( ..) ,
248249 ..
249- } ) => parent_expr,
250- _ => None ,
250+ } )
251+ )
252+ }
253+
254+ fn is_for_loop_arg ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) -> bool {
255+ let mut cur_expr = expr;
256+ while let Some ( parent_expr) = get_parent_expr ( cx, cur_expr) {
257+ match higher:: for_loop ( parent_expr) {
258+ Some ( ( _, args, _) ) if args. hir_id == expr. hir_id => return true ,
259+ _ => cur_expr = parent_expr,
260+ }
251261 }
262+
263+ false
252264 }
253265
254266 fn is_empty_range ( limits : RangeLimits , ordering : Ordering ) -> bool {
@@ -267,34 +279,18 @@ fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
267279 if let Some ( ordering) = Constant :: partial_cmp( cx. tcx, ty, & start_idx, & end_idx) ;
268280 if is_empty_range( limits, ordering) ;
269281 then {
270- if let Some ( parent_expr) = inside_indexing_expr( cx, expr) {
271- let ( reason, outcome) = if ordering == Ordering :: Equal {
272- ( "empty" , "always yield an empty slice" )
273- } else {
274- ( "reversed" , "panic at run-time" )
275- } ;
276-
277- span_lint_and_then(
278- cx,
279- REVERSED_EMPTY_RANGES ,
280- expr. span,
281- & format!( "this range is {} and using it to index a slice will {}" , reason, outcome) ,
282- |diag| {
283- if_chain! {
284- if ordering == Ordering :: Equal ;
285- if let ty:: Slice ( slice_ty) = cx. tables. expr_ty( parent_expr) . kind;
286- then {
287- diag. span_suggestion(
288- parent_expr. span,
289- "if you want an empty slice, use" ,
290- format!( "[] as &[{}]" , slice_ty) ,
291- Applicability :: MaybeIncorrect
292- ) ;
293- }
294- }
295- }
296- ) ;
297- } else {
282+ if inside_indexing_expr( cx, expr) {
283+ // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ...
284+ if ordering != Ordering :: Equal {
285+ span_lint(
286+ cx,
287+ REVERSED_EMPTY_RANGES ,
288+ expr. span,
289+ "this range is reversed and using it to index a slice will panic at run-time" ,
290+ ) ;
291+ }
292+ // ... except in for loop arguments for backwards compatibility with `reverse_range_loop`
293+ } else if ordering != Ordering :: Equal || is_for_loop_arg( cx, expr) {
298294 span_lint_and_then(
299295 cx,
300296 REVERSED_EMPTY_RANGES ,
0 commit comments