Skip to content

Commit 041a269

Browse files
committed
Rollup merge of rust-lang#33339 - oli-obk:fix/const_eval, r=japaric
fix various const eval errors These were found after const_evaluating arbitrary expressions and linting if the const evaluator failed fixes rust-lang#33275 (int -> float casts for negative ints) fixes rust-lang#33291 (int -> char casts (new! wasn't allowed in constants until this PR)) r? @eddyb cc @bluss @japaric
2 parents 2e4474f + ce6ea47 commit 041a269

File tree

3 files changed

+67
-55
lines changed

3 files changed

+67
-55
lines changed

src/librustc_const_eval/eval.rs

+37-48
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,6 @@ pub enum ErrKind {
377377
NotOn(ConstVal),
378378
CallOn(ConstVal),
379379

380-
NegateWithOverflow(i64),
381-
AddiWithOverflow(i64, i64),
382-
SubiWithOverflow(i64, i64),
383-
MuliWithOverflow(i64, i64),
384-
AdduWithOverflow(u64, u64),
385-
SubuWithOverflow(u64, u64),
386-
MuluWithOverflow(u64, u64),
387380
DivideByZero,
388381
DivideWithOverflow,
389382
ModuloByZero,
@@ -415,6 +408,7 @@ pub enum ErrKind {
415408
TypeMismatch(String, ConstInt),
416409
BadType(ConstVal),
417410
ErroneousReferencedConstant(Box<ConstEvalErr>),
411+
CharCast(ConstInt),
418412
}
419413

420414
impl From<ConstMathErr> for ErrKind {
@@ -439,13 +433,6 @@ impl ConstEvalErr {
439433
NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
440434
CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(),
441435

442-
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
443-
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
444-
SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
445-
MuliWithOverflow(..) => "attempted to mul with overflow".into_cow(),
446-
AdduWithOverflow(..) => "attempted to add with overflow".into_cow(),
447-
SubuWithOverflow(..) => "attempted to sub with overflow".into_cow(),
448-
MuluWithOverflow(..) => "attempted to mul with overflow".into_cow(),
449436
DivideByZero => "attempted to divide by zero".into_cow(),
450437
DivideWithOverflow => "attempted to divide with overflow".into_cow(),
451438
ModuloByZero => "attempted remainder with a divisor of zero".into_cow(),
@@ -482,6 +469,9 @@ impl ConstEvalErr {
482469
},
483470
BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
484471
ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
472+
CharCast(ref got) => {
473+
format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
474+
},
485475
}
486476
}
487477
}
@@ -824,7 +814,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
824814
debug!("const call({:?})", call_args);
825815
eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
826816
},
827-
hir::ExprLit(ref lit) => lit_to_const(&lit.node, tcx, ety, lit.span)?,
817+
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
818+
Ok(val) => val,
819+
Err(err) => signal!(e, err),
820+
},
828821
hir::ExprBlock(ref block) => {
829822
match block.expr {
830823
Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?,
@@ -930,7 +923,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
930923
};
931924

932925
match (ety.map(|t| &t.sty), result) {
933-
(Some(ref ty_hint), Integral(i)) => Ok(Integral(infer(i, tcx, ty_hint, e.span)?)),
926+
(Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
927+
Ok(inferred) => Ok(Integral(inferred)),
928+
Err(err) => signal!(e, err),
929+
},
934930
(_, result) => Ok(result),
935931
}
936932
}
@@ -939,15 +935,9 @@ fn infer<'tcx>(
939935
i: ConstInt,
940936
tcx: &TyCtxt<'tcx>,
941937
ty_hint: &ty::TypeVariants<'tcx>,
942-
span: Span
943-
) -> Result<ConstInt, ConstEvalErr> {
938+
) -> Result<ConstInt, ErrKind> {
944939
use syntax::ast::*;
945940

946-
let err = |e| ConstEvalErr {
947-
span: span,
948-
kind: e,
949-
};
950-
951941
match (ty_hint, i) {
952942
(&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
953943
(&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
@@ -993,17 +983,17 @@ fn infer<'tcx>(
993983
Err(_) => Ok(Usize(ConstUsize::Us32(i as u32))),
994984
}
995985
},
996-
(&ty::TyUint(_), InferSigned(_)) => Err(err(IntermediateUnsignedNegative)),
986+
(&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
997987

998-
(&ty::TyInt(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
999-
(&ty::TyUint(ity), i) => Err(err(TypeMismatch(ity.to_string(), i))),
988+
(&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
989+
(&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
1000990

1001991
(&ty::TyEnum(ref adt, _), i) => {
1002992
let hints = tcx.lookup_repr_hints(adt.did);
1003993
let int_ty = tcx.enum_repr_type(hints.iter().next());
1004-
infer(i, tcx, &int_ty.to_ty(tcx).sty, span)
994+
infer(i, tcx, &int_ty.to_ty(tcx).sty)
1005995
},
1006-
(_, i) => Err(err(BadType(ConstVal::Integral(i)))),
996+
(_, i) => Err(BadType(ConstVal::Integral(i))),
1007997
}
1008998
}
1009999

@@ -1089,23 +1079,22 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe
10891079
Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))),
10901080
}
10911081
},
1092-
ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => {
1093-
// FIXME: this could probably be prettier
1094-
// there's no easy way to turn an `Infer` into a f64
1095-
let val = (-val).map_err(Math)?;
1096-
let val = val.to_u64().unwrap() as f64;
1097-
let val = -val;
1098-
Ok(Float(val))
1082+
ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
1083+
Infer(u) => Ok(Float(u as f64)),
1084+
InferSigned(i) => Ok(Float(i as f64)),
1085+
_ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
10991086
},
1100-
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)),
1101-
ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => {
1102-
let val = (-val).map_err(Math)?;
1103-
let val = val.to_u64().unwrap() as f32;
1104-
let val = -val;
1105-
Ok(Float(val as f64))
1087+
ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
1088+
Infer(u) => Ok(Float(u as f32 as f64)),
1089+
InferSigned(i) => Ok(Float(i as f32 as f64)),
1090+
_ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
11061091
},
1107-
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
11081092
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
1093+
ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
1094+
Ok(U8(u)) => Ok(Char(u as char)),
1095+
// can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
1096+
_ => Err(CharCast(val)),
1097+
},
11091098
_ => Err(CannotCast),
11101099
}
11111100
}
@@ -1136,36 +1125,36 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind,
11361125
tcx: &TyCtxt<'tcx>,
11371126
ty_hint: Option<Ty<'tcx>>,
11381127
span: Span,
1139-
) -> Result<ConstVal, ConstEvalErr> {
1128+
) -> Result<ConstVal, ErrKind> {
11401129
use syntax::ast::*;
11411130
use syntax::ast::LitIntType::*;
11421131
match *lit {
11431132
LitKind::Str(ref s, _) => Ok(Str((*s).clone())),
11441133
LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
11451134
LitKind::Byte(n) => Ok(Integral(U8(n))),
11461135
LitKind::Int(n, Signed(ity)) => {
1147-
infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
1136+
infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral)
11481137
},
11491138

11501139
LitKind::Int(n, Unsuffixed) => {
11511140
match ty_hint.map(|t| &t.sty) {
11521141
Some(&ty::TyInt(ity)) => {
1153-
infer(InferSigned(n as i64), tcx, &ty::TyInt(ity), span).map(Integral)
1142+
infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral)
11541143
},
11551144
Some(&ty::TyUint(uty)) => {
1156-
infer(Infer(n), tcx, &ty::TyUint(uty), span).map(Integral)
1145+
infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral)
11571146
},
11581147
None => Ok(Integral(Infer(n))),
11591148
Some(&ty::TyEnum(ref adt, _)) => {
11601149
let hints = tcx.lookup_repr_hints(adt.did);
11611150
let int_ty = tcx.enum_repr_type(hints.iter().next());
1162-
infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty, span).map(Integral)
1151+
infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
11631152
},
11641153
Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
11651154
}
11661155
},
11671156
LitKind::Int(n, Unsigned(ity)) => {
1168-
infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral)
1157+
infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral)
11691158
},
11701159

11711160
LitKind::Float(ref n, _) |

src/test/compile-fail/const-eval-overflow-4b.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
#![allow(unused_imports)]
1717

18-
use std::fmt;
1918
use std::{i8, i16, i32, i64, isize};
2019
use std::{u8, u16, u32, u64, usize};
2120

@@ -26,10 +25,15 @@ const A_I8_T
2625
//~| found `u8` [E0250]
2726
= [0; (i8::MAX as usize) + 1];
2827

29-
fn main() {
30-
foo(&A_I8_T[..]);
31-
}
3228

33-
fn foo<T:fmt::Debug>(x: T) {
34-
println!("{:?}", x);
35-
}
29+
const A_CHAR_USIZE
30+
: [u32; 5u8 as char as usize]
31+
= [0; 5];
32+
33+
34+
const A_BAD_CHAR_USIZE
35+
: [u32; 5i8 as char as usize]
36+
//~^ ERROR only `u8` can be cast as `char`, not `i8`
37+
= [0; 5];
38+
39+
fn main() {}

src/test/run-pass/const-err.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// check for const_err regressions
12+
13+
#![deny(const_err)]
14+
15+
16+
fn main() {
17+
let _ = ((-1 as i8) << 8 - 1) as f32;
18+
let _ = 0u8 as char;
19+
}

0 commit comments

Comments
 (0)