Skip to content

Commit 13962af

Browse files
committed
Include signed integer types in the lint
1 parent 0556e48 commit 13962af

File tree

3 files changed

+96
-55
lines changed

3 files changed

+96
-55
lines changed

src/librustc_lint/types.rs

+88-54
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,61 @@ impl TypeLimits {
5858
}
5959
}
6060

61+
/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint.
62+
/// Returns `true` iff the lint was overridden.
63+
fn lint_overflowing_range_endpoint<'a, 'tcx>(
64+
cx: &LateContext<'a, 'tcx>,
65+
lit: &ast::Lit,
66+
lit_val: u128,
67+
max: u128,
68+
expr: &'tcx hir::Expr,
69+
parent_expr: &'tcx hir::Expr,
70+
ty: impl std::fmt::Debug,
71+
) -> bool {
72+
// We only want to handle exclusive (`..`) ranges,
73+
// which are represented as `ExprKind::Struct`.
74+
if let ExprKind::Struct(_, eps, _) = &parent_expr.node {
75+
debug_assert_eq!(eps.len(), 2);
76+
// We can suggest using an inclusive range
77+
// (`..=`) instead only if it is the `end` that is
78+
// overflowing and only by 1.
79+
if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
80+
let mut err = cx.struct_span_lint(
81+
OVERFLOWING_LITERALS,
82+
parent_expr.span,
83+
&format!("range endpoint is out of range for `{:?}`", ty),
84+
);
85+
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
86+
use ast::{LitKind, LitIntType};
87+
// We need to preserve the literal's suffix,
88+
// as it may determine typing information.
89+
let suffix = match lit.node {
90+
LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s),
91+
LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s),
92+
LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
93+
_ => bug!(),
94+
};
95+
let suggestion = format!(
96+
"{}..={}{}",
97+
start,
98+
lit_val - 1,
99+
suffix,
100+
);
101+
err.span_suggestion(
102+
parent_expr.span,
103+
&"use an inclusive range instead",
104+
suggestion,
105+
Applicability::MachineApplicable,
106+
);
107+
err.emit();
108+
return true;
109+
}
110+
}
111+
}
112+
113+
false
114+
}
115+
61116
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
62117
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
63118
match e.node {
@@ -103,6 +158,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
103158
);
104159
return;
105160
}
161+
162+
let par_id = cx.tcx.hir().get_parent_node_by_hir_id(e.hir_id);
163+
if let Node::Expr(par_e) = cx.tcx.hir().get_by_hir_id(par_id) {
164+
if let hir::ExprKind::Struct(..) = par_e.node {
165+
if is_range_literal(cx.sess(), par_e)
166+
&& lint_overflowing_range_endpoint(
167+
cx,
168+
lit,
169+
v,
170+
max,
171+
e,
172+
par_e,
173+
t,
174+
)
175+
{
176+
// The overflowing literal lint was overridden.
177+
return;
178+
}
179+
}
180+
}
181+
106182
cx.span_lint(
107183
OVERFLOWING_LITERALS,
108184
e.span,
@@ -150,61 +226,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
150226
}
151227
hir::ExprKind::Struct(..)
152228
if is_range_literal(cx.sess(), parent_expr) => {
153-
// We only want to handle exclusive (`..`) ranges,
154-
// which are represented as `ExprKind::Struct`.
155-
if let ExprKind::Struct(_, eps, _) = &parent_expr.node {
156-
debug_assert_eq!(eps.len(), 2);
157-
// We can suggest using an inclusive range
158-
// (`..=`) instead only if it is the `end` that is
159-
// overflowing and only by 1.
160-
if eps[1].expr.hir_id == e.hir_id
161-
&& lit_val - 1 == max
162-
{
163-
let mut err = cx.struct_span_lint(
164-
OVERFLOWING_LITERALS,
165-
parent_expr.span,
166-
&format!(
167-
"range endpoint is out of range \
168-
for `{:?}`",
169-
t,
170-
),
171-
);
172-
if let Ok(start) = cx.sess().source_map()
173-
.span_to_snippet(eps[0].span)
174-
{
175-
use ast::{LitKind::*, LitIntType};
176-
// We need to preserve the literal's suffix,
177-
// as it may determine typing information.
178-
let suffix = match lit.node {
179-
Int(_, LitIntType::Signed(s)) => {
180-
format!("{}", s)
181-
}
182-
Int(_, LitIntType::Unsigned(s)) => {
183-
format!("{}", s)
184-
}
185-
Int(_, LitIntType::Unsuffixed) => {
186-
"".to_owned()
187-
}
188-
_ => bug!(),
189-
};
190-
let suggestion = format!(
191-
"{}..={}{}",
192-
start,
193-
lit_val - 1,
194-
suffix,
195-
);
196-
err.span_suggestion(
197-
parent_expr.span,
198-
&"use an inclusive range instead",
199-
suggestion,
200-
Applicability::MachineApplicable,
201-
);
202-
err.emit();
203-
return;
204-
}
205-
}
229+
if lint_overflowing_range_endpoint(
230+
cx,
231+
lit,
232+
lit_val,
233+
max,
234+
e,
235+
parent_expr,
236+
t,
237+
) {
238+
// The overflowing literal lint was overridden.
239+
return;
206240
}
207-
}
241+
}
208242
_ => {}
209243
}
210244
}

src/test/ui/lint/lint-range-endpoint-overflow.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn main() {
77
let range_d = 256..5; //~ ERROR literal out of range for `u8`
88
let range_e = 0..257; //~ ERROR literal out of range for `u8`
99
let _range_f = 0..256u8; //~ ERROR range endpoint is out of range for `u8`
10+
let _range_g = 0..128i8; //~ ERROR range endpoint is out of range for `i8`
1011

1112
range_a.collect::<Vec<u8>>();
1213
range_b.collect::<Vec<u8>>();

src/test/ui/lint/lint-range-endpoint-overflow.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,11 @@ error: range endpoint is out of range for `u8`
3434
LL | let _range_f = 0..256u8;
3535
| ^^^^^^^^ help: use an inclusive range instead: `0..=255u8`
3636

37-
error: aborting due to 5 previous errors
37+
error: range endpoint is out of range for `i8`
38+
--> $DIR/lint-range-endpoint-overflow.rs:10:20
39+
|
40+
LL | let _range_g = 0..128i8;
41+
| ^^^^^^^^ help: use an inclusive range instead: `0..=127i8`
42+
43+
error: aborting due to 6 previous errors
3844

0 commit comments

Comments
 (0)