about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_lint/types.rs142
-rw-r--r--src/test/ui/lint/lint-range-endpoint-overflow.rs1
-rw-r--r--src/test/ui/lint/lint-range-endpoint-overflow.stderr8
3 files changed, 96 insertions, 55 deletions
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 3b3e2455fa7..379b20ab760 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -58,6 +58,61 @@ impl TypeLimits {
     }
 }
 
+/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
+/// Returns `true` iff the lint was overridden.
+fn lint_overflowing_range_endpoint<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    lit: &ast::Lit,
+    lit_val: u128,
+    max: u128,
+    expr: &'tcx hir::Expr,
+    parent_expr: &'tcx hir::Expr,
+    ty: impl std::fmt::Debug,
+) -> bool {
+    // We only want to handle exclusive (`..`) ranges,
+    // which are represented as `ExprKind::Struct`.
+    if let ExprKind::Struct(_, eps, _) = &parent_expr.node {
+        debug_assert_eq!(eps.len(), 2);
+        // We can suggest using an inclusive range
+        // (`..=`) instead only if it is the `end` that is
+        // overflowing and only by 1.
+        if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
+            let mut err = cx.struct_span_lint(
+                OVERFLOWING_LITERALS,
+                parent_expr.span,
+                &format!("range endpoint is out of range for `{:?}`", ty),
+            );
+            if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
+                use ast::{LitKind, LitIntType};
+                // We need to preserve the literal's suffix,
+                // as it may determine typing information.
+                let suffix = match lit.node {
+                    LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s),
+                    LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s),
+                    LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
+                    _ => bug!(),
+                };
+                let suggestion = format!(
+                    "{}..={}{}",
+                    start,
+                    lit_val - 1,
+                    suffix,
+                );
+                err.span_suggestion(
+                    parent_expr.span,
+                    &"use an inclusive range instead",
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
+                err.emit();
+                return true;
+            }
+        }
+    }
+
+    false
+}
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
         match e.node {
@@ -103,6 +158,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                         );
                                         return;
                                     }
+
+                                    let par_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
+                                    if let Node::Expr(par_e) = cx.tcx.hir().get_by_hir_id(par_id) {
+                                        if let hir::ExprKind::Struct(..) = par_e.node {
+                                            if is_range_literal(cx.sess(), par_e)
+                                                && lint_overflowing_range_endpoint(
+                                                    cx,
+                                                    lit,
+                                                    v,
+                                                    max,
+                                                    e,
+                                                    par_e,
+                                                    t,
+                                                )
+                                            {
+                                                    // The overflowing literal lint was overridden.
+                                                    return;
+                                            }
+                                        }
+                                    }
+
                                     cx.span_lint(
                                         OVERFLOWING_LITERALS,
                                         e.span,
@@ -150,61 +226,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                     }
                                     hir::ExprKind::Struct(..)
                                         if is_range_literal(cx.sess(), parent_expr) => {
-                                            // We only want to handle exclusive (`..`) ranges,
-                                            // which are represented as `ExprKind::Struct`.
-                                            if let ExprKind::Struct(_, eps, _) = &parent_expr.node {
-                                                debug_assert_eq!(eps.len(), 2);
-                                                // We can suggest using an inclusive range
-                                                // (`..=`) instead only if it is the `end` that is
-                                                // overflowing and only by 1.
-                                                if eps[1].expr.hir_id == e.hir_id
-                                                    && lit_val - 1 == max
-                                                {
-                                                    let mut err = cx.struct_span_lint(
-                                                        OVERFLOWING_LITERALS,
-                                                        parent_expr.span,
-                                                        &format!(
-                                                            "range endpoint is out of range \
-                                                             for `{:?}`",
-                                                            t,
-                                                        ),
-                                                    );
-                                                    if let Ok(start) = cx.sess().source_map()
-                                                        .span_to_snippet(eps[0].span)
-                                                    {
-                                                        use ast::{LitKind::*, LitIntType};
-                                                        // We need to preserve the literal's suffix,
-                                                        // as it may determine typing information.
-                                                        let suffix = match lit.node {
-                                                            Int(_, LitIntType::Signed(s)) => {
-                                                                format!("{}", s)
-                                                            }
-                                                            Int(_, LitIntType::Unsigned(s)) => {
-                                                                format!("{}", s)
-                                                            }
-                                                            Int(_, LitIntType::Unsuffixed) => {
-                                                                "".to_owned()
-                                                            }
-                                                            _ => bug!(),
-                                                        };
-                                                        let suggestion = format!(
-                                                            "{}..={}{}",
-                                                            start,
-                                                            lit_val - 1,
-                                                            suffix,
-                                                        );
-                                                        err.span_suggestion(
-                                                            parent_expr.span,
-                                                            &"use an inclusive range instead",
-                                                            suggestion,
-                                                            Applicability::MachineApplicable,
-                                                        );
-                                                        err.emit();
-                                                        return;
-                                                    }
-                                                }
+                                            if lint_overflowing_range_endpoint(
+                                                cx,
+                                                lit,
+                                                lit_val,
+                                                max,
+                                                e,
+                                                parent_expr,
+                                                t,
+                                            ) {
+                                                // The overflowing literal lint was overridden.
+                                                return;
                                             }
-                                    }
+                                        }
                                     _ => {}
                                 }
                             }
diff --git a/src/test/ui/lint/lint-range-endpoint-overflow.rs b/src/test/ui/lint/lint-range-endpoint-overflow.rs
index 5d7430007ab..7034d56aa5d 100644
--- a/src/test/ui/lint/lint-range-endpoint-overflow.rs
+++ b/src/test/ui/lint/lint-range-endpoint-overflow.rs
@@ -7,6 +7,7 @@ fn main() {
     let range_d = 256..5; //~ ERROR literal out of range for `u8`
     let range_e = 0..257; //~ ERROR literal out of range for `u8`
     let _range_f = 0..256u8;  //~ ERROR range endpoint is out of range for `u8`
+    let _range_g = 0..128i8;  //~ ERROR range endpoint is out of range for `i8`
 
     range_a.collect::<Vec<u8>>();
     range_b.collect::<Vec<u8>>();
diff --git a/src/test/ui/lint/lint-range-endpoint-overflow.stderr b/src/test/ui/lint/lint-range-endpoint-overflow.stderr
index 72f548cf4ad..939451d6bc0 100644
--- a/src/test/ui/lint/lint-range-endpoint-overflow.stderr
+++ b/src/test/ui/lint/lint-range-endpoint-overflow.stderr
@@ -34,5 +34,11 @@ error: range endpoint is out of range for `u8`
 LL |     let _range_f = 0..256u8;
    |                    ^^^^^^^^ help: use an inclusive range instead: `0..=255u8`
 
-error: aborting due to 5 previous errors
+error: range endpoint is out of range for `i8`
+  --> $DIR/lint-range-endpoint-overflow.rs:10:20
+   |
+LL |     let _range_g = 0..128i8;
+   |                    ^^^^^^^^ help: use an inclusive range instead: `0..=127i8`
+
+error: aborting due to 6 previous errors