Skip to content

Commit 9d91529

Browse files
committed
Implemented '-W type-limits' (rust-lang#3833)
1 parent 61bb357 commit 9d91529

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed

src/rustc/middle/lint.rs

+109
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ enum lint {
5454
deprecated_pattern,
5555
non_camel_case_types,
5656
structural_records,
57+
type_limits,
5758

5859
managed_heap_memory,
5960
owned_heap_memory,
@@ -186,6 +187,11 @@ fn get_lint_dict() -> lint_dict {
186187
desc: ~"allow legacy modes",
187188
default: forbid}),
188189

190+
(~"type_limits",
191+
@{lint: type_limits,
192+
desc: ~"comparisons made useless by limits of the types involved",
193+
default: warn})
194+
189195
/* FIXME(#3266)--make liveness warnings lintable
190196
(~"unused_variable",
191197
@{lint: unused_variable,
@@ -397,6 +403,7 @@ fn check_item(i: @ast::item, cx: ty::ctxt) {
397403
check_item_heap(cx, i);
398404
check_item_structural_records(cx, i);
399405
check_item_deprecated_modes(cx, i);
406+
check_item_type_limits(cx, i);
400407
}
401408

402409
// Take a visitor, and modify it so that it will not proceed past subitems.
@@ -430,6 +437,108 @@ fn check_item_while_true(cx: ty::ctxt, it: @ast::item) {
430437
visit::visit_item(it, (), visit);
431438
}
432439

440+
fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) {
441+
pure fn is_valid<T: cmp::Ord>(binop: ast::binop, v: T, min: T, max: T) -> bool {
442+
match binop {
443+
ast::lt => v <= max,
444+
ast::le => v < max,
445+
ast::gt => v >= min,
446+
ast::ge => v > min,
447+
ast::eq | ast::ne => v >= min && v <= max,
448+
_ => fail
449+
}
450+
}
451+
452+
pure fn rev_binop(binop: ast::binop) -> ast::binop {
453+
match binop {
454+
ast::lt => ast::ge,
455+
ast::le => ast::gt,
456+
ast::gt => ast::le,
457+
ast::ge => ast::lt,
458+
_ => binop
459+
}
460+
}
461+
462+
fn check_limits(cx: ty::ctxt, binop: ast::binop, l: &ast::expr,
463+
r: &ast::expr) -> bool {
464+
let (lit, expr, swap) = match (l.node, r.node) {
465+
(ast::expr_lit(_), _) => (l, r, true),
466+
(_, ast::expr_lit(_)) => (r, l, false),
467+
_ => return true
468+
};
469+
// Normalize the binop so that the literal is always on the RHS in
470+
// the comparison
471+
let norm_binop = if (swap) {
472+
rev_binop(binop)
473+
} else {
474+
binop
475+
};
476+
match ty::get(ty::expr_ty(cx, @*expr)).sty {
477+
ty::ty_int(int_ty) => {
478+
let (min, max): (i64, i64) = match int_ty {
479+
ast::ty_i => (int::min_value as i64, int::max_value as i64),
480+
ast::ty_char => (u32::min_value as i64, u32::max_value as i64),
481+
ast::ty_i8 => (i8::min_value as i64, i8::max_value as i64),
482+
ast::ty_i16 => (i16::min_value as i64, i16::max_value as i64),
483+
ast::ty_i32 => (i32::min_value as i64, i32::max_value as i64),
484+
ast::ty_i64 => (i64::min_value, i64::max_value)
485+
};
486+
let lit_val: i64 = match lit.node {
487+
ast::expr_lit(@li) => match li.node {
488+
ast::lit_int(v, _) => v,
489+
ast::lit_uint(v, _) => v as i64,
490+
ast::lit_int_unsuffixed(v) => v,
491+
_ => return true
492+
},
493+
_ => fail
494+
};
495+
is_valid(norm_binop, lit_val, min, max)
496+
}
497+
ty::ty_uint(uint_ty) => {
498+
let (min, max): (u64, u64) = match uint_ty {
499+
ast::ty_u => (uint::min_value as u64, uint::max_value as u64),
500+
ast::ty_u8 => (u8::min_value as u64, u8::max_value as u64),
501+
ast::ty_u16 => (u16::min_value as u64, u16::max_value as u64),
502+
ast::ty_u32 => (u32::min_value as u64, u32::max_value as u64),
503+
ast::ty_u64 => (u64::min_value, u64::max_value)
504+
};
505+
let lit_val: u64 = match lit.node {
506+
ast::expr_lit(@li) => match li.node {
507+
ast::lit_int(v, _) => v as u64,
508+
ast::lit_uint(v, _) => v,
509+
ast::lit_int_unsuffixed(v) => v as u64,
510+
_ => return true
511+
},
512+
_ => fail
513+
};
514+
is_valid(norm_binop, lit_val, min, max)
515+
}
516+
_ => true
517+
}
518+
}
519+
520+
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
521+
visit_expr: fn@(e: @ast::expr) {
522+
match e.node {
523+
ast::expr_binary(binop, @l, @r) => {
524+
match binop {
525+
ast::eq | ast::lt | ast::le | ast::ne | ast::ge | ast::gt => {
526+
if !check_limits(cx, binop, &l, &r) {
527+
cx.sess.span_lint(type_limits, e.id, it.id, e.span,
528+
~"comparison is useless due to type limits");
529+
}
530+
}
531+
_ => ()
532+
}
533+
}
534+
_ => ()
535+
}
536+
},
537+
.. *visit::default_simple_visitor()
538+
}));
539+
visit::visit_item(it, (), visit);
540+
}
541+
433542
fn check_item_structural_records(cx: ty::ctxt, it: @ast::item) {
434543
let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
435544
visit_expr: fn@(e: @ast::expr) {

0 commit comments

Comments
 (0)