Skip to content

Commit df283df

Browse files
committed
Don't use the undefined bytes of PrimVal::Bytes
1 parent 7218836 commit df283df

File tree

12 files changed

+255
-277
lines changed

12 files changed

+255
-277
lines changed

src/librustc/mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mod value;
1010

1111
pub use self::error::{EvalError, EvalResult, EvalErrorKind};
1212

13-
pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64};
13+
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
1414

1515
use std::collections::BTreeMap;
1616
use std::fmt;

src/librustc/mir/interpret/value.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,6 @@ use ty::layout::{Align, HasDataLayout};
44
use ty;
55

66
use super::{EvalResult, MemoryPointer, PointerArithmetic};
7-
use syntax::ast::FloatTy;
8-
use rustc_const_math::ConstFloat;
9-
10-
pub fn bytes_to_f32(bits: u128) -> ConstFloat {
11-
ConstFloat {
12-
bits,
13-
ty: FloatTy::F32,
14-
}
15-
}
16-
17-
pub fn bytes_to_f64(bits: u128) -> ConstFloat {
18-
ConstFloat {
19-
bits,
20-
ty: FloatTy::F64,
21-
}
22-
}
237

248
/// A `Value` represents a single self-contained Rust value.
259
///
@@ -182,10 +166,6 @@ impl<'tcx> PrimVal {
182166
PrimVal::Bytes(n as u128)
183167
}
184168

185-
pub fn from_float(f: ConstFloat) -> Self {
186-
PrimVal::Bytes(f.bits)
187-
}
188-
189169
pub fn from_bool(b: bool) -> Self {
190170
PrimVal::Bytes(b as u128)
191171
}
@@ -260,14 +240,6 @@ impl<'tcx> PrimVal {
260240
})
261241
}
262242

263-
pub fn to_f32(self) -> EvalResult<'tcx, ConstFloat> {
264-
self.to_bytes().map(bytes_to_f32)
265-
}
266-
267-
pub fn to_f64(self) -> EvalResult<'tcx, ConstFloat> {
268-
self.to_bytes().map(bytes_to_f64)
269-
}
270-
271243
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
272244
match self.to_bytes()? {
273245
0 => Ok(false),

src/librustc/ty/mod.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,10 +1845,34 @@ impl<'a, 'gcx, 'tcx> AdtDef {
18451845
..
18461846
}) => {
18471847
trace!("discriminants: {} ({:?})", b, repr_type);
1848-
discr = Discr {
1849-
val: b,
1850-
ty: repr_type.to_ty(tcx),
1851-
};
1848+
let ty = repr_type.to_ty(tcx);
1849+
if ty.is_signed() {
1850+
let (ty, param_env) = tcx
1851+
.lift_to_global(&(ty, param_env))
1852+
.unwrap_or_else(|| {
1853+
bug!("MIR: discriminants({:?}, {:?}) got \
1854+
type with inference types/regions",
1855+
ty, param_env);
1856+
});
1857+
let size = tcx.global_tcx()
1858+
.layout_of(param_env.and(ty))
1859+
.expect("int layout")
1860+
.size
1861+
.bits();
1862+
let val = b as i128;
1863+
// sign extend to i128
1864+
let amt = 128 - size;
1865+
let val = (val << amt) >> amt;
1866+
discr = Discr {
1867+
val: val as u128,
1868+
ty,
1869+
};
1870+
} else {
1871+
discr = Discr {
1872+
val: b,
1873+
ty,
1874+
};
1875+
}
18521876
}
18531877
_ => {
18541878
if !expr_did.is_local() {

src/librustc_mir/build/expr/as_rvalue.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use rustc::middle::region;
2222
use rustc::ty::{self, Ty};
2323
use rustc::mir::*;
2424
use rustc::mir::interpret::{Value, PrimVal};
25-
use syntax::ast;
2625
use syntax_pos::Span;
2726

2827
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -382,9 +381,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
382381

383382
// Helper to get a `-1` value of the appropriate type
384383
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
384+
let bits = self.hir.type_bit_size(ty);
385+
let n = (!0u128) >> (128 - bits);
385386
let literal = Literal::Value {
386387
value: self.hir.tcx().mk_const(ty::Const {
387-
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(-1i128 as u128))),
388+
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
388389
ty
389390
})
390391
};
@@ -394,31 +395,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
394395

395396
// Helper to get the minimum value of the appropriate type
396397
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
397-
let literal = match ty.sty {
398-
ty::TyInt(ity) => {
399-
let ity = match ity {
400-
ast::IntTy::Isize => self.hir.tcx().sess.target.isize_ty,
401-
other => other,
402-
};
403-
let val = match ity {
404-
ast::IntTy::I8 => i8::min_value() as i128,
405-
ast::IntTy::I16 => i16::min_value() as i128,
406-
ast::IntTy::I32 => i32::min_value() as i128,
407-
ast::IntTy::I64 => i64::min_value() as i128,
408-
ast::IntTy::I128 => i128::min_value() as i128,
409-
ast::IntTy::Isize => unreachable!(),
410-
};
411-
412-
Literal::Value {
413-
value: self.hir.tcx().mk_const(ty::Const {
414-
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
415-
ty
416-
})
417-
}
418-
}
419-
_ => {
420-
span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
421-
}
398+
assert!(ty.is_signed());
399+
let bits = self.hir.type_bit_size(ty);
400+
let n = 1 << (bits - 1);
401+
let literal = Literal::Value {
402+
value: self.hir.tcx().mk_const(ty::Const {
403+
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
404+
ty
405+
})
422406
};
423407

424408
self.literal_operand(span, ty, literal)

src/librustc_mir/hair/cx/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,34 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
149149
}
150150
}
151151

152+
pub fn type_bit_size(
153+
&self,
154+
ty: Ty<'tcx>,
155+
) -> u64 {
156+
let tcx = self.tcx.global_tcx();
157+
let (ty, param_env) = self
158+
.tcx
159+
.lift_to_global(&(ty, self.param_env))
160+
.unwrap_or_else(|| {
161+
bug!("MIR: Cx::const_eval_literal({:?}, {:?}) got \
162+
type with inference types/regions",
163+
ty, self.param_env);
164+
});
165+
tcx
166+
.layout_of(param_env.and(ty))
167+
.expect("int layout")
168+
.size
169+
.bits()
170+
}
171+
152172
pub fn const_eval_literal(
153173
&mut self,
154174
lit: &'tcx ast::LitKind,
155175
ty: Ty<'tcx>,
156176
sp: Span,
157177
neg: bool,
158178
) -> Literal<'tcx> {
179+
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
159180
let tcx = self.tcx.global_tcx();
160181

161182
let parse_float = |num: &str, fty| -> ConstFloat {
@@ -165,6 +186,15 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
165186
})
166187
};
167188

189+
let clamp = |n| {
190+
let size = self.type_bit_size(ty);
191+
trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
192+
let amt = 128 - size;
193+
let result = (n << amt) >> amt;
194+
trace!("clamp result: {}", result);
195+
result
196+
};
197+
168198
use rustc::mir::interpret::*;
169199
let lit = match *lit {
170200
LitKind::Str(ref s, _) => {
@@ -185,9 +215,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
185215
LitKind::Int(n, _) if neg => {
186216
let n = n as i128;
187217
let n = n.overflowing_neg().0;
188-
Value::ByVal(PrimVal::Bytes(n as u128))
218+
let n = clamp(n as u128);
219+
Value::ByVal(PrimVal::Bytes(n))
189220
},
190-
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(n)),
221+
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
191222
LitKind::Float(n, fty) => {
192223
let n = n.as_str();
193224
let mut f = parse_float(&n, fty);

src/librustc_mir/interpret/cast.rs

Lines changed: 39 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -14,75 +14,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
1414
src_ty: Ty<'tcx>,
1515
dest_ty: Ty<'tcx>,
1616
) -> EvalResult<'tcx, PrimVal> {
17+
use rustc::ty::TypeVariants::*;
1718
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
18-
let src_kind = self.ty_to_primval_kind(src_ty)?;
1919

2020
match val {
2121
PrimVal::Undef => Ok(PrimVal::Undef),
2222
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
23-
val @ PrimVal::Bytes(_) => {
24-
use rustc::mir::interpret::PrimValKind::*;
25-
match src_kind {
26-
F32 => self.cast_from_float(val.to_f32()?, dest_ty),
27-
F64 => self.cast_from_float(val.to_f64()?, dest_ty),
28-
29-
I8 | I16 | I32 | I64 | I128 => {
30-
self.cast_from_signed_int(val.to_i128()?, dest_ty)
31-
}
32-
33-
Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
34-
self.cast_from_int(val.to_u128()?, dest_ty, false)
35-
}
23+
PrimVal::Bytes(b) => {
24+
match src_ty.sty {
25+
TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
26+
_ => self.cast_from_int(b, src_ty, dest_ty),
3627
}
3728
}
3829
}
3930
}
4031

41-
fn cast_from_signed_int(&self, val: i128, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
42-
self.cast_from_int(val as u128, ty, val < 0)
43-
}
44-
45-
fn int_to_int(&self, v: i128, ty: IntTy) -> u128 {
46-
match ty {
47-
IntTy::I8 => v as i8 as u128,
48-
IntTy::I16 => v as i16 as u128,
49-
IntTy::I32 => v as i32 as u128,
50-
IntTy::I64 => v as i64 as u128,
51-
IntTy::I128 => v as u128,
52-
IntTy::Isize => {
53-
let ty = self.tcx.sess.target.isize_ty;
54-
self.int_to_int(v, ty)
55-
}
56-
}
57-
}
58-
fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 {
59-
match ty {
60-
UintTy::U8 => v as u8 as u128,
61-
UintTy::U16 => v as u16 as u128,
62-
UintTy::U32 => v as u32 as u128,
63-
UintTy::U64 => v as u64 as u128,
64-
UintTy::U128 => v,
65-
UintTy::Usize => {
66-
let ty = self.tcx.sess.target.usize_ty;
67-
self.int_to_uint(v, ty)
68-
}
69-
}
70-
}
71-
7232
fn cast_from_int(
7333
&self,
7434
v: u128,
75-
ty: Ty<'tcx>,
76-
negative: bool,
35+
src_ty: Ty<'tcx>,
36+
dest_ty: Ty<'tcx>,
7737
) -> EvalResult<'tcx, PrimVal> {
78-
trace!("cast_from_int: {}, {}, {}", v, ty, negative);
38+
trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
7939
use rustc::ty::TypeVariants::*;
80-
match ty.sty {
81-
// Casts to bool are not permitted by rustc, no need to handle them here.
82-
TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))),
83-
TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))),
40+
match dest_ty.sty {
41+
TyInt(_) | TyUint(_) => {
42+
let v = self.sign_extend(v, src_ty)?;
43+
let v = self.truncate(v, dest_ty)?;
44+
Ok(PrimVal::Bytes(v))
45+
}
8446

85-
TyFloat(fty) if negative => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
47+
TyFloat(fty) if src_ty.is_signed() => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
8648
TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
8749

8850
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
@@ -91,31 +53,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
9153
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
9254
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
9355

94-
_ => err!(Unimplemented(format!("int to {:?} cast", ty))),
56+
// Casts to bool are not permitted by rustc, no need to handle them here.
57+
_ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
9558
}
9659
}
9760

98-
fn cast_from_float(&self, val: ConstFloat, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
61+
fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
9962
use rustc::ty::TypeVariants::*;
100-
match ty.sty {
63+
use rustc_apfloat::FloatConvert;
64+
match dest_ty.sty {
65+
// float -> uint
10166
TyUint(t) => {
10267
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
103-
match val.ty {
104-
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(val.bits).to_u128(width).value)),
105-
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(val.bits).to_u128(width).value)),
68+
match fty {
69+
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
70+
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
10671
}
10772
},
108-
73+
// float -> int
10974
TyInt(t) => {
11075
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
111-
match val.ty {
112-
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(val.bits).to_i128(width).value)),
113-
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(val.bits).to_i128(width).value)),
76+
match fty {
77+
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
78+
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
11479
}
11580
},
116-
117-
TyFloat(fty) => Ok(PrimVal::from_float(val.convert(fty))),
118-
_ => err!(Unimplemented(format!("float to {:?} cast", ty))),
81+
// f64 -> f32
82+
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
83+
Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
84+
},
85+
// f32 -> f64
86+
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
87+
Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
88+
},
89+
// identity cast
90+
TyFloat(_) => Ok(PrimVal::Bytes(bits)),
91+
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
11992
}
12093
}
12194

0 commit comments

Comments
 (0)