Skip to content

Commit

Permalink
Fixes missing overflow lint for i64 rust-lang#14269
Browse files Browse the repository at this point in the history
The `type_overflow` lint, doesn't catch the overflow for `i64` because
the overflow happens earlier in the parse phase when the `u64` as biggest
possible int gets casted to `i64` , without checking the for overflows.
We can't lint in the parse phase, so a refactoring of the `LitInt` type
was necessary.

The types `LitInt`, `LitUint` and `LitIntUnsuffixed` where merged to one
type `LitInt` which stores it's value as `u64`. An additional parameter was
added which indicate the signedness of the type and the sign of the value.
  • Loading branch information
hirschenberger committed Aug 5, 2014
1 parent 795f6ae commit 0dc2157
Show file tree
Hide file tree
Showing 18 changed files with 142 additions and 99 deletions.
2 changes: 1 addition & 1 deletion src/libfourcc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
(val << 8) | (byte as u32)
};
}
let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
let e = cx.expr_lit(sp, ast::LitInt(val as u64, ast::UnsignedIntLit(ast::TyU32)));
MacExpr::new(e)
}

Expand Down
35 changes: 21 additions & 14 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl LintPass for TypeLimits {
match expr.node {
ast::ExprLit(lit) => {
match lit.node {
ast::LitUint(..) => {
ast::LitInt(_, ast::UnsignedIntLit(_)) => {
cx.span_lint(UNSIGNED_NEGATE, e.span,
"negation of unsigned int literal may \
be unintentional");
Expand Down Expand Up @@ -177,15 +177,25 @@ impl LintPass for TypeLimits {
} else { t };
let (min, max) = int_ty_range(int_type);
let mut lit_val: i64 = match lit.node {
ast::LitInt(v, _) => v,
ast::LitUint(v, _) => v as i64,
ast::LitIntUnsuffixed(v) => v,
ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
if v > i64::MAX as u64{
cx.span_lint(TYPE_OVERFLOW, e.span,
"literal out of range for its type");
return;
}
v as i64
}
ast::LitInt(v, ast::SignedIntLit(_, ast::Minus)) |
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Minus)) => {
-(v as i64)
}
_ => fail!()
};
if self.negated_expr_id == e.id {
lit_val *= -1;
}
if lit_val < min || lit_val > max {
if lit_val < min || lit_val > max {
cx.span_lint(TYPE_OVERFLOW, e.span,
"literal out of range for its type");
}
Expand All @@ -197,9 +207,7 @@ impl LintPass for TypeLimits {
let (min, max) = uint_ty_range(uint_type);
let lit_val: u64 = match lit.node {
ast::LitByte(_v) => return, // _v is u8, within range by definition
ast::LitInt(v, _) => v as u64,
ast::LitUint(v, _) => v,
ast::LitIntUnsuffixed(v) => v as u64,
ast::LitInt(v, _) => v,
_ => fail!()
};
if lit_val < min || lit_val > max {
Expand Down Expand Up @@ -294,9 +302,10 @@ impl LintPass for TypeLimits {
let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
ast::ExprLit(li) => match li.node {
ast::LitInt(v, _) => v,
ast::LitUint(v, _) => v as i64,
ast::LitIntUnsuffixed(v) => v,
ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => v as i64,
ast::LitInt(v, ast::SignedIntLit(_, ast::Minus)) |
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Minus)) => -(v as i64),
_ => return true
},
_ => fail!()
Expand All @@ -307,9 +316,7 @@ impl LintPass for TypeLimits {
let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
ast::ExprLit(li) => match li.node {
ast::LitInt(v, _) => v as u64,
ast::LitUint(v, _) => v,
ast::LitIntUnsuffixed(v) => v as u64,
ast::LitInt(v, _) => v,
_ => return true
},
_ => fail!()
Expand Down
11 changes: 7 additions & 4 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,10 +560,13 @@ pub fn lit_to_const(lit: &Lit) -> const_val {
}
LitByte(n) => const_uint(n as u64),
LitChar(n) => const_uint(n as u64),
LitInt(n, _) => const_int(n),
LitUint(n, _) => const_uint(n),
LitIntUnsuffixed(n) => const_int(n),
LitFloat(ref n, _) | LitFloatUnsuffixed(ref n) => {
LitInt(n, ast::SignedIntLit(_, ast::Plus)) |
LitInt(n, ast::UnsuffixedIntLit(ast::Plus)) => const_int(n as i64),
LitInt(n, ast::SignedIntLit(_, ast::Minus)) |
LitInt(n, ast::UnsuffixedIntLit(ast::Minus)) => const_int(-(n as i64)),
LitInt(n, ast::UnsignedIntLit(_)) => const_uint(n),
LitFloat(ref n, _) |
LitFloatUnsuffixed(ref n) => {
const_float(from_str::<f64>(n.get()).unwrap() as f64)
}
LitNil => const_nil,
Expand Down
10 changes: 7 additions & 3 deletions src/librustc/middle/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
match lit.node {
ast::LitByte(b) => C_integral(Type::uint_from_ty(cx, ast::TyU8), b as u64, false),
ast::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
ast::LitInt(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true),
ast::LitUint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false),
ast::LitIntUnsuffixed(i) => {
ast::LitInt(i, ast::SignedIntLit(t, _)) => {
C_integral(Type::int_from_ty(cx, t), i, true)
}
ast::LitInt(u, ast::UnsignedIntLit(t)) => {
C_integral(Type::uint_from_ty(cx, t), u, false)
}
ast::LitInt(i, ast::UnsuffixedIntLit(_)) => {
let lit_int_ty = ty::node_id_to_type(cx.tcx(), e.id);
match ty::get(lit_int_ty).sty {
ty::ty_int(t) => {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2057,9 +2057,9 @@ fn check_lit(fcx: &FnCtxt,
}
ast::LitByte(_) => ty::mk_u8(),
ast::LitChar(_) => ty::mk_char(),
ast::LitInt(_, t) => ty::mk_mach_int(t),
ast::LitUint(_, t) => ty::mk_mach_uint(t),
ast::LitIntUnsuffixed(_) => {
ast::LitInt(_, ast::SignedIntLit(t, _)) => ty::mk_mach_int(t),
ast::LitInt(_, ast::UnsignedIntLit(t)) => ty::mk_mach_uint(t),
ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
let opt_ty = expected.map_to_option(fcx, |sty| {
match *sty {
ty::ty_int(i) => Some(ty::mk_mach_int(i)),
Expand Down
2 changes: 0 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1947,8 +1947,6 @@ fn lit_to_string(lit: &ast::Lit) -> String {
},
ast::LitChar(c) => format!("'{}'", c),
ast::LitInt(i, _t) => i.to_string(),
ast::LitUint(u, _t) => u.to_string(),
ast::LitIntUnsuffixed(i) => i.to_string(),
ast::LitFloat(ref f, _t) => f.get().to_string(),
ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
ast::LitBool(b) => b.to_string(),
Expand Down
38 changes: 35 additions & 3 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use parse::token::{InternedString, str_to_ident};
use parse::token;

use std::fmt;
use std::num::Zero;
use std::fmt::Show;
use std::option::Option;
use std::rc::Rc;
Expand Down Expand Up @@ -656,15 +657,46 @@ pub enum StrStyle {

pub type Lit = Spanned<Lit_>;

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum Sign {
Minus,
Plus
}

impl<T: PartialOrd+Zero> Sign {
pub fn new(n: T) -> Sign {
if n < Zero::zero() {
Minus
} else {
Plus
}
}
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum LitIntType {
SignedIntLit(IntTy, Sign),
UnsignedIntLit(UintTy),
UnsuffixedIntLit(Sign)
}

impl LitIntType {
pub fn suffix_len(&self) -> uint {
match *self {
UnsuffixedIntLit(_) => 0,
SignedIntLit(s, _) => s.suffix_len(),
UnsignedIntLit(u) => u.suffix_len()
}
}
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum Lit_ {
LitStr(InternedString, StrStyle),
LitBinary(Rc<Vec<u8> >),
LitByte(u8),
LitChar(char),
LitInt(i64, IntTy),
LitUint(u64, UintTy),
LitIntUnsuffixed(i64),
LitInt(u64, LitIntType),
LitFloat(InternedString, FloatTy),
LitFloatUnsuffixed(InternedString),
LitNil,
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/ext/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,13 +626,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.expr(sp, ast::ExprLit(box(GC) respan(sp, lit)))
}
fn expr_uint(&self, span: Span, i: uint) -> Gc<ast::Expr> {
self.expr_lit(span, ast::LitUint(i as u64, ast::TyU))
self.expr_lit(span, ast::LitInt(i as u64, ast::UnsignedIntLit(ast::TyU)))
}
fn expr_int(&self, sp: Span, i: int) -> Gc<ast::Expr> {
self.expr_lit(sp, ast::LitInt(i as i64, ast::TyI))
self.expr_lit(sp, ast::LitInt(i as u64, ast::SignedIntLit(ast::TyI, ast::Sign::new(i))))
}
fn expr_u8(&self, sp: Span, u: u8) -> Gc<ast::Expr> {
self.expr_lit(sp, ast::LitUint(u as u64, ast::TyU8))
self.expr_lit(sp, ast::LitInt(u as u64, ast::UnsignedIntLit(ast::TyU8)))
}
fn expr_bool(&self, sp: Span, value: bool) -> Gc<ast::Expr> {
self.expr_lit(sp, ast::LitBool(value))
Expand Down
11 changes: 6 additions & 5 deletions src/libsyntax/ext/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
}

// u8 literal, push to vector expression
ast::LitUint(v, ast::TyU8) => {
ast::LitInt(v, ast::UnsignedIntLit(ast::TyU8)) => {
if v > 0xFF {
cx.span_err(expr.span, "too large u8 literal in bytes!");
err = true;
Expand All @@ -57,13 +57,14 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
}

// integer literal, push to vector expression
ast::LitIntUnsuffixed(v) => {
ast::LitInt(_, ast::UnsuffixedIntLit(ast::Minus)) => {
cx.span_err(expr.span, "negative integer literal in bytes!");
err = true;
}
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
if v > 0xFF {
cx.span_err(expr.span, "too large integer literal in bytes!");
err = true;
} else if v < 0 {
cx.span_err(expr.span, "negative integer literal in bytes!");
err = true;
} else {
bytes.push(cx.expr_u8(expr.span, v as u8));
}
Expand Down
9 changes: 6 additions & 3 deletions src/libsyntax/ext/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
ast::LitChar(c) => {
accumulator.push_char(c);
}
ast::LitInt(i, _) | ast::LitIntUnsuffixed(i) => {
ast::LitInt(i, ast::UnsignedIntLit(_)) |
ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
accumulator.push_str(format!("{}", i).as_slice());
}
ast::LitUint(u, _) => {
accumulator.push_str(format!("{}", u).as_slice());
ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
accumulator.push_str(format!("-{}", i).as_slice());
}
ast::LitNil => {}
ast::LitBool(b) => {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ impl<'a> MethodDef<'a> {
let arms : Vec<ast::Arm> = variants.iter().enumerate()
.map(|(index, &variant)| {
let pat = variant_to_pat(cx, sp, &*variant);
let lit = ast::LitUint(index as u64, ast::TyU);
let lit = ast::LitInt(index as u64, ast::UnsignedIntLit(ast::TyU));
cx.arm(sp, vec![pat], cx.expr_lit(sp, lit))
}).collect();

Expand Down
9 changes: 5 additions & 4 deletions src/libsyntax/ext/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,17 @@ pub mod rt {
(signed, $t:ty, $tag:ident) => (
impl ToSource for $t {
fn to_source(&self) -> String {
let lit = dummy_spanned(ast::LitInt(*self as i64, ast::$tag));
pprust::lit_to_string(&lit)
let lit = ast::LitInt(*self as u64, ast::SignedIntLit(ast::$tag,
ast::Sign::new(*self)));
pprust::lit_to_string(&dummy_spanned(lit))
}
}
);
(unsigned, $t:ty, $tag:ident) => (
impl ToSource for $t {
fn to_source(&self) -> String {
let lit = dummy_spanned(ast::LitUint(*self as u64, ast::$tag));
pprust::lit_to_string(&lit)
let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit(ast::$tag));
pprust::lit_to_string(&dummy_spanned(lit))
}
}
);
Expand Down
Loading

0 comments on commit 0dc2157

Please sign in to comment.