From 12c4a1951e85925dbccc40efb163f4f179c30046 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 11:02:44 +0200 Subject: [PATCH 1/5] remove unused constant error variants --- src/librustc_const_eval/eval.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c2ac3d838c8d0..4fd4daf09980b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -377,13 +377,6 @@ pub enum ErrKind { NotOn(ConstVal), CallOn(ConstVal), - NegateWithOverflow(i64), - AddiWithOverflow(i64, i64), - SubiWithOverflow(i64, i64), - MuliWithOverflow(i64, i64), - AdduWithOverflow(u64, u64), - SubuWithOverflow(u64, u64), - MuluWithOverflow(u64, u64), DivideByZero, DivideWithOverflow, ModuloByZero, @@ -439,13 +432,6 @@ impl ConstEvalErr { NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(), - NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(), - AddiWithOverflow(..) => "attempted to add with overflow".into_cow(), - SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(), - MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(), - AdduWithOverflow(..) => "attempted to add with overflow".into_cow(), - SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(), - MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(), DivideByZero => "attempted to divide by zero".into_cow(), DivideWithOverflow => "attempted to divide with overflow".into_cow(), ModuloByZero => "attempted remainder with a divisor of zero".into_cow(), From bf51eafbef4d949673a17ae1f2cc478bcc8c0b58 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 11:26:29 +0200 Subject: [PATCH 2/5] check for wrong const_err warnings --- src/librustc_const_eval/eval.rs | 26 ++++++++++++-------------- src/test/run-pass/const-err.rs | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/const-err.rs diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4fd4daf09980b..1bd9b37b644b3 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -408,6 +408,7 @@ pub enum ErrKind { TypeMismatch(String, ConstInt), BadType(ConstVal), ErroneousReferencedConstant(Box), + BadCharValue, } impl From for ErrKind { @@ -468,6 +469,7 @@ impl ConstEvalErr { }, BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), + BadCharValue => "invalid numeric value for char".into_cow(), } } } @@ -1075,23 +1077,19 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))), } }, - ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => { - // FIXME: this could probably be prettier - // there's no easy way to turn an `Infer` into a f64 - let val = (-val).map_err(Math)?; - let val = val.to_u64().unwrap() as f64; - let val = -val; - Ok(Float(val)) + ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { + Infer(u) => Ok(Float(u as f64)), + InferSigned(i) => Ok(Float(i as f64)), + _ => unreachable!(), }, - ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)), - ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => { - let val = (-val).map_err(Math)?; - let val = val.to_u64().unwrap() as f32; - let val = -val; - Ok(Float(val as f64)) + ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { + Infer(u) => Ok(Float(u as f32 as f64)), + InferSigned(i) => Ok(Float(i as f32 as f64)), + _ => unreachable!(), }, - ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)), ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), + ty::TyChar if v as u32 as u64 == v => ::std::char::from_u32(v as u32).map(Char) + .ok_or(BadCharValue), _ => Err(CannotCast), } } diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs new file mode 100644 index 0000000000000..8d7ac4f54c131 --- /dev/null +++ b/src/test/run-pass/const-err.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// check for const_err regressions + +#![deny(const_err)] + + +fn main() { + let _ = ((-1 as i8) << 8 - 1) as f32; + let _ = 0u8 as char; +} From 10737a5a45ed9a1d9ae73b996fae893da1d62512 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:38:33 +0200 Subject: [PATCH 3/5] `* as char` assumes `*` to be of type `u8` --- src/librustc_const_eval/eval.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 1bd9b37b644b3..21eb06dfb97d1 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -408,7 +408,7 @@ pub enum ErrKind { TypeMismatch(String, ConstInt), BadType(ConstVal), ErroneousReferencedConstant(Box), - BadCharValue, + CharCast(ConstInt), } impl From for ErrKind { @@ -469,7 +469,9 @@ impl ConstEvalErr { }, BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), - BadCharValue => "invalid numeric value for char".into_cow(), + CharCast(ref got) => { + format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow() + }, } } } @@ -1080,16 +1082,19 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() { Infer(u) => Ok(Float(u as f64)), InferSigned(i) => Ok(Float(i as f64)), - _ => unreachable!(), + _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), }, ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() { Infer(u) => Ok(Float(u as f32 as f64)), InferSigned(i) => Ok(Float(i as f32 as f64)), - _ => unreachable!(), + _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"), }, ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")), - ty::TyChar if v as u32 as u64 == v => ::std::char::from_u32(v as u32).map(Char) - .ok_or(BadCharValue), + ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) { + Ok(U8(u)) => Ok(Char(u as char)), + // can only occur before typeck, typeck blocks `T as char` for `T` != `u8` + _ => Err(CharCast(val)), + }, _ => Err(CannotCast), } } From f080b13c6beaa409c2bb643dd997a73ce0e75b89 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:38:49 +0200 Subject: [PATCH 4/5] tests --- .../compile-fail/const-eval-overflow-4b.rs | 18 +++++++++++------- src/test/run-pass/const-err.rs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 5aa93cf6383fe..31e1a72967f4d 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -15,7 +15,6 @@ #![allow(unused_imports)] -use std::fmt; use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; @@ -26,10 +25,15 @@ const A_I8_T //~| found `u8` [E0250] = [0; (i8::MAX as usize) + 1]; -fn main() { - foo(&A_I8_T[..]); -} -fn foo(x: T) { - println!("{:?}", x); -} +const A_CHAR_USIZE + : [u32; 5u8 as char as usize] + = [0; 5]; + + +const A_BAD_CHAR_USIZE + : [u32; 5i8 as char as usize] + //~^ ERROR only `u8` can be cast as `char`, not `i8` + = [0; 5]; + +fn main() {} diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index 8d7ac4f54c131..30641c1cb87b1 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // From ce6ea47d43e9c646849aad34876a0054da58a1e9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 2 May 2016 16:40:40 +0200 Subject: [PATCH 5/5] refactor infer function There was no span available in the cast function, but we need to infer the `x` in `x as char` to `u8`. The spans are now removed from all functions using `infer` and instead added in `eval_const_expr_partial` --- src/librustc_const_eval/eval.rs | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 21eb06dfb97d1..fc933d567fbd3 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -814,7 +814,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, debug!("const call({:?})", call_args); eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))? }, - hir::ExprLit(ref lit) => lit_to_const(&lit.node, tcx, ety, lit.span)?, + hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) { + Ok(val) => val, + Err(err) => signal!(e, err), + }, hir::ExprBlock(ref block) => { match block.expr { Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?, @@ -920,7 +923,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>, }; match (ety.map(|t| &t.sty), result) { - (Some(ref ty_hint), Integral(i)) => Ok(Integral(infer(i, tcx, ty_hint, e.span)?)), + (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) { + Ok(inferred) => Ok(Integral(inferred)), + Err(err) => signal!(e, err), + }, (_, result) => Ok(result), } } @@ -929,15 +935,9 @@ fn infer<'tcx>( i: ConstInt, tcx: &TyCtxt<'tcx>, ty_hint: &ty::TypeVariants<'tcx>, - span: Span -) -> Result { +) -> Result { use syntax::ast::*; - let err = |e| ConstEvalErr { - span: span, - kind: e, - }; - match (ty_hint, i) { (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result), (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), @@ -983,17 +983,17 @@ fn infer<'tcx>( Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))), } }, - (&ty::TyUint(_), InferSigned(_)) => Err(err(IntermediateUnsignedNegative)), + (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative), - (&ty::TyInt(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))), - (&ty::TyUint(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))), + (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), + (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyEnum(ref adt, _), i) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(i, tcx, &int_ty.to_ty(tcx).sty, span) + infer(i, tcx, &int_ty.to_ty(tcx).sty) }, - (_, i) => Err(err(BadType(ConstVal::Integral(i)))), + (_, i) => Err(BadType(ConstVal::Integral(i))), } } @@ -1125,7 +1125,7 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind, tcx: &TyCtxt<'tcx>, ty_hint: Option>, span: Span, - ) -> Result { + ) -> Result { use syntax::ast::*; use syntax::ast::LitIntType::*; match *lit { @@ -1133,28 +1133,28 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind, LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), LitKind::Byte(n) => Ok(Integral(U8(n))), LitKind::Int(n, Signed(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral) + infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) }, LitKind::Int(n, Unsuffixed) => { match ty_hint.map(|t| &t.sty) { Some(&ty::TyInt(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral) + infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) }, Some(&ty::TyUint(uty)) => { - infer(Infer(n), tcx, &ty::TyUint(uty), span).map(Integral) + infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) }, None => Ok(Integral(Infer(n))), Some(&ty::TyEnum(ref adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty, span).map(Integral) + infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) }, Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), } }, LitKind::Int(n, Unsigned(ity)) => { - infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral) + infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral) }, LitKind::Float(ref n, _) |