Skip to content

Commit 2ad303e

Browse files
committed
make floating point casts nicer with generics
1 parent de7bcca commit 2ad303e

File tree

3 files changed

+50
-38
lines changed

3 files changed

+50
-38
lines changed

src/librustc/ty/sty.rs

+8
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
20352035
}
20362036
}
20372037

2038+
#[inline]
2039+
pub fn is_fn_ptr(&self) -> bool {
2040+
match self.sty {
2041+
FnPtr(_) => true,
2042+
_ => false,
2043+
}
2044+
}
2045+
20382046
pub fn is_impl_trait(&self) -> bool {
20392047
match self.sty {
20402048
Opaque(..) => true,

src/librustc_mir/interpret/cast.rs

+34-34
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
55
use syntax::symbol::sym;
66

77
use rustc_apfloat::ieee::{Single, Double};
8+
use rustc_apfloat::{Float, FloatConvert};
89
use rustc::mir::interpret::{
910
Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
1011
};
1112
use rustc::mir::CastKind;
12-
use rustc_apfloat::Float;
1313

1414
use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};
1515

@@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
126126
Ok(())
127127
}
128128

129-
pub(super) fn cast_scalar(
129+
fn cast_scalar(
130130
&self,
131131
val: Scalar<M::PointerTag>,
132132
src_layout: TyLayout<'tcx>,
@@ -135,23 +135,33 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
135135
use rustc::ty::TyKind::*;
136136
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
137137

138-
match val.to_bits_or_ptr(src_layout.size, self) {
139-
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
140-
Ok(data) => {
141-
match src_layout.ty.sty {
142-
Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
143-
_ => self.cast_from_int(data, src_layout, dest_layout),
138+
match src_layout.ty.sty {
139+
// Floating point
140+
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
141+
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
142+
// Integer(-like), including fn ptr casts
143+
_ => {
144+
assert!(
145+
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
146+
src_layout.ty.is_integral() || src_layout.ty.is_region_ptr() ||
147+
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr(),
148+
"Unexpected cast from type {:?}", src_layout.ty
149+
);
150+
match val.to_bits_or_ptr(src_layout.size, self) {
151+
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
152+
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
144153
}
145154
}
146155
}
147156
}
148157

149158
fn cast_from_int(
150159
&self,
151-
v: u128,
160+
v: u128, // raw bits
152161
src_layout: TyLayout<'tcx>,
153162
dest_layout: TyLayout<'tcx>,
154163
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
164+
// Let's make sure v is sign-extended *if* it has a signed type.
155165
let signed = src_layout.abi.is_signed();
156166
let v = if signed {
157167
self.sign_extend(v, src_layout)
@@ -190,46 +200,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
190200
}
191201
}
192202

193-
fn cast_from_float(
203+
fn cast_from_float<F>(
194204
&self,
195-
bits: u128,
196-
fty: FloatTy,
205+
f: F,
197206
dest_ty: Ty<'tcx>
198-
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
207+
) -> InterpResult<'tcx, Scalar<M::PointerTag>>
208+
where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
209+
{
199210
use rustc::ty::TyKind::*;
200-
use rustc_apfloat::FloatConvert;
201211
match dest_ty.sty {
202212
// float -> uint
203213
Uint(t) => {
204214
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
205-
let v = match fty {
206-
FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
207-
FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
208-
};
215+
let v = f.to_u128(width).value;
209216
// This should already fit the bit width
210217
Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
211218
},
212219
// float -> int
213220
Int(t) => {
214221
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
215-
let v = match fty {
216-
FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
217-
FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
218-
};
222+
let v = f.to_i128(width).value;
219223
Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
220224
},
221-
// f64 -> f32
222-
Float(FloatTy::F32) if fty == FloatTy::F64 =>
223-
Ok(Scalar::from_f32(Double::from_bits(bits).convert(&mut false).value)),
224-
// f32 -> f64
225-
Float(FloatTy::F64) if fty == FloatTy::F32 =>
226-
Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)),
227-
// identity cast
228-
Float(FloatTy::F64) if fty == FloatTy::F64 =>
229-
Ok(Scalar::from_uint(bits, Size::from_bits(64))),
230-
Float(FloatTy::F32) if fty == FloatTy::F32 =>
231-
Ok(Scalar::from_uint(bits, Size::from_bits(32))),
232-
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
225+
// float -> f32
226+
Float(FloatTy::F32) =>
227+
Ok(Scalar::from_f32(f.convert(&mut false).value)),
228+
// float -> f64
229+
Float(FloatTy::F64) =>
230+
Ok(Scalar::from_f64(f.convert(&mut false).value)),
231+
// That's it.
232+
_ => bug!("invalid float to {:?} cast", dest_ty),
233233
}
234234
}
235235

src/librustc_mir/interpret/operator.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
292292
}
293293
_ => {
294294
// Must be integer(-like) types. Don't forget about == on fn pointers.
295-
assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() ||
296-
left.layout.ty.is_fn());
297-
assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() ||
298-
right.layout.ty.is_fn());
295+
assert!(
296+
left.layout.ty.is_integral() ||
297+
left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(),
298+
"Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op);
299+
assert!(
300+
right.layout.ty.is_integral() ||
301+
right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(),
302+
"Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op);
299303

300304
// Handle operations that support pointer values
301305
if left.to_scalar_ptr()?.is_ptr() ||

0 commit comments

Comments
 (0)