Skip to content

Commit 3188d24

Browse files
committed
address nits
1 parent f86c476 commit 3188d24

File tree

11 files changed

+178
-128
lines changed

11 files changed

+178
-128
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,6 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
517517
InvalidMemoryAccess |
518518
InvalidFunctionPointer |
519519
InvalidBool |
520-
InvalidDiscriminant |
521520
InvalidNullPointerUsage |
522521
ReadPointerAsBytes |
523522
ReadBytesAsPointer |
@@ -550,6 +549,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
550549
GeneratorResumedAfterReturn |
551550
GeneratorResumedAfterPanic |
552551
InfiniteLoop => {}
552+
InvalidDiscriminant(val) => val.hash_stable(hcx, hasher),
553553
Panic { ref msg, ref file, line, col } => {
554554
msg.hash_stable(hcx, hasher);
555555
file.hash_stable(hcx, hasher);

src/librustc/mir/interpret/error.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub enum EvalErrorKind<'tcx, O> {
190190
InvalidMemoryAccess,
191191
InvalidFunctionPointer,
192192
InvalidBool,
193-
InvalidDiscriminant,
193+
InvalidDiscriminant(u128),
194194
PointerOutOfBounds {
195195
ptr: Pointer,
196196
access: bool,
@@ -302,8 +302,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
302302
"tried to use a function pointer after offsetting it",
303303
InvalidBool =>
304304
"invalid boolean value read",
305-
InvalidDiscriminant =>
306-
"invalid enum discriminant value read or written",
305+
InvalidDiscriminant(..) =>
306+
"invalid enum discriminant value read",
307307
PointerOutOfBounds { .. } =>
308308
"pointer offset outside bounds of allocation",
309309
InvalidNullPointerUsage =>
@@ -488,6 +488,8 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
488488
align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()),
489489
Panic { ref msg, line, col, ref file } =>
490490
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
491+
InvalidDiscriminant(val) =>
492+
write!(f, "encountered invalid enum discriminant {}", val),
491493
_ => write!(f, "{}", self.description()),
492494
}
493495
}

src/librustc/ty/structural_impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
498498
InvalidMemoryAccess => InvalidMemoryAccess,
499499
InvalidFunctionPointer => InvalidFunctionPointer,
500500
InvalidBool => InvalidBool,
501-
InvalidDiscriminant => InvalidDiscriminant,
501+
InvalidDiscriminant(val) => InvalidDiscriminant(val),
502502
PointerOutOfBounds {
503503
ptr,
504504
access,

src/librustc_mir/interpret/operand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
585585
.expect("tagged layout for non adt")
586586
.discriminants(self.tcx.tcx)
587587
.position(|var| var.val == real_discr)
588-
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant)?;
588+
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
589589
(real_discr, index)
590590
},
591591
layout::Variants::NicheFilling {

src/librustc_mir/interpret/operator.rs

Lines changed: 149 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -48,111 +48,100 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
4848
}
4949

5050
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
51-
/// Returns the result of the specified operation and whether it overflowed.
52-
pub fn binary_op(
51+
fn binary_char_op(
5352
&self,
5453
bin_op: mir::BinOp,
55-
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
56-
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
54+
l: char,
55+
r: char,
5756
) -> EvalResult<'tcx, (Scalar, bool)> {
5857
use rustc::mir::BinOp::*;
5958

60-
let left = left.to_scalar()?;
61-
let right = right.to_scalar()?;
59+
let res = match bin_op {
60+
Eq => l == r,
61+
Ne => l != r,
62+
Lt => l < r,
63+
Le => l <= r,
64+
Gt => l > r,
65+
Ge => l >= r,
66+
_ => bug!("Invalid operation on char: {:?}", bin_op),
67+
};
68+
return Ok((Scalar::from_bool(res), false));
69+
}
6270

63-
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
64-
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
71+
fn binary_bool_op(
72+
&self,
73+
bin_op: mir::BinOp,
74+
l: bool,
75+
r: bool,
76+
) -> EvalResult<'tcx, (Scalar, bool)> {
77+
use rustc::mir::BinOp::*;
6578

66-
// Handle non-integer operations
67-
if let ty::Char = left_layout.ty.sty {
68-
assert_eq!(right_layout.ty.sty, ty::Char);
69-
let l = left.to_char()?;
70-
let r = right.to_char()?;
71-
let res = match bin_op {
72-
Eq => l == r,
73-
Ne => l != r,
74-
Lt => l < r,
75-
Le => l <= r,
76-
Gt => l > r,
77-
Ge => l >= r,
78-
_ => bug!("Invalid operation on char: {:?}", bin_op),
79-
};
80-
return Ok((Scalar::from_bool(res), false));
81-
}
82-
if let ty::Bool = left_layout.ty.sty {
83-
assert_eq!(right_layout.ty.sty, ty::Bool);
84-
let l = left.to_bool()?;
85-
let r = right.to_bool()?;
86-
let res = match bin_op {
87-
Eq => l == r,
88-
Ne => l != r,
89-
Lt => l < r,
90-
Le => l <= r,
91-
Gt => l > r,
92-
Ge => l >= r,
93-
BitAnd => l & r,
94-
BitOr => l | r,
95-
BitXor => l ^ r,
96-
_ => bug!("Invalid operation on bool: {:?}", bin_op),
97-
};
98-
return Ok((Scalar::from_bool(res), false));
99-
}
100-
if let ty::Float(fty) = left_layout.ty.sty {
101-
let l = left.to_bits(left_layout.size)?;
102-
let r = right.to_bits(right_layout.size)?;
103-
assert_eq!(right_layout.ty.sty, ty::Float(fty));
104-
macro_rules! float_math {
105-
($ty:path, $size:expr) => {{
106-
let l = <$ty>::from_bits(l);
107-
let r = <$ty>::from_bits(r);
108-
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
109-
bits: res.value.to_bits(),
110-
size: $size,
111-
};
112-
let val = match bin_op {
113-
Eq => Scalar::from_bool(l == r),
114-
Ne => Scalar::from_bool(l != r),
115-
Lt => Scalar::from_bool(l < r),
116-
Le => Scalar::from_bool(l <= r),
117-
Gt => Scalar::from_bool(l > r),
118-
Ge => Scalar::from_bool(l >= r),
119-
Add => bitify(l + r),
120-
Sub => bitify(l - r),
121-
Mul => bitify(l * r),
122-
Div => bitify(l / r),
123-
Rem => bitify(l % r),
124-
_ => bug!("invalid float op: `{:?}`", bin_op),
125-
};
126-
return Ok((val, false));
127-
}};
128-
}
129-
match fty {
130-
FloatTy::F32 => float_math!(Single, 4),
131-
FloatTy::F64 => float_math!(Double, 8),
132-
}
133-
}
134-
// Only integers left
135-
#[inline]
136-
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
137-
match ty.sty {
138-
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
139-
_ => false,
140-
}
79+
let res = match bin_op {
80+
Eq => l == r,
81+
Ne => l != r,
82+
Lt => l < r,
83+
Le => l <= r,
84+
Gt => l > r,
85+
Ge => l >= r,
86+
BitAnd => l & r,
87+
BitOr => l | r,
88+
BitXor => l ^ r,
89+
_ => bug!("Invalid operation on bool: {:?}", bin_op),
90+
};
91+
return Ok((Scalar::from_bool(res), false));
92+
}
93+
94+
fn binary_float_op(
95+
&self,
96+
bin_op: mir::BinOp,
97+
fty: FloatTy,
98+
// passing in raw bits
99+
l: u128,
100+
r: u128,
101+
) -> EvalResult<'tcx, (Scalar, bool)> {
102+
use rustc::mir::BinOp::*;
103+
104+
macro_rules! float_math {
105+
($ty:path, $size:expr) => {{
106+
let l = <$ty>::from_bits(l);
107+
let r = <$ty>::from_bits(r);
108+
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
109+
bits: res.value.to_bits(),
110+
size: $size,
111+
};
112+
let val = match bin_op {
113+
Eq => Scalar::from_bool(l == r),
114+
Ne => Scalar::from_bool(l != r),
115+
Lt => Scalar::from_bool(l < r),
116+
Le => Scalar::from_bool(l <= r),
117+
Gt => Scalar::from_bool(l > r),
118+
Ge => Scalar::from_bool(l >= r),
119+
Add => bitify(l + r),
120+
Sub => bitify(l - r),
121+
Mul => bitify(l * r),
122+
Div => bitify(l / r),
123+
Rem => bitify(l % r),
124+
_ => bug!("invalid float op: `{:?}`", bin_op),
125+
};
126+
return Ok((val, false));
127+
}};
141128
}
142-
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
143-
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
144-
145-
// Handle operations that support pointers
146-
if let Some(handled) =
147-
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
148-
{
149-
return Ok(handled);
129+
match fty {
130+
FloatTy::F32 => float_math!(Single, 4),
131+
FloatTy::F64 => float_math!(Double, 8),
150132
}
133+
}
151134

152-
// From now on, everything must be bytes, no pointer values
153-
// (this is independent of the type)
154-
let l = left.to_bits(left_layout.size)?;
155-
let r = right.to_bits(right_layout.size)?;
135+
fn binary_int_op(
136+
&self,
137+
bin_op: mir::BinOp,
138+
// passing in raw bits
139+
l: u128,
140+
left_layout: TyLayout<'tcx>,
141+
r: u128,
142+
right_layout: TyLayout<'tcx>,
143+
) -> EvalResult<'tcx, (Scalar, bool)> {
144+
use rustc::mir::BinOp::*;
156145

157146
// Shift ops can have an RHS with a different numeric type.
158147
if bin_op == Shl || bin_op == Shr {
@@ -189,11 +178,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
189178
// For the remaining ops, the types must be the same on both sides
190179
if left_layout.ty != right_layout.ty {
191180
let msg = format!(
192-
"unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
181+
"unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
193182
bin_op,
194-
left,
183+
l,
195184
left_layout.ty,
196-
right,
185+
r,
197186
right_layout.ty
198187
);
199188
return err!(Unimplemented(msg));
@@ -289,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
289278

290279
_ => {
291280
let msg = format!(
292-
"unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})",
281+
"unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
293282
bin_op,
294-
left,
295-
left_layout.ty,
296-
right,
283+
l,
284+
r,
297285
right_layout.ty,
298286
);
299287
return err!(Unimplemented(msg));
@@ -303,6 +291,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
303291
Ok((val, false))
304292
}
305293

294+
/// Returns the result of the specified operation and whether it overflowed.
295+
pub fn binary_op(
296+
&self,
297+
bin_op: mir::BinOp,
298+
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
299+
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
300+
) -> EvalResult<'tcx, (Scalar, bool)> {
301+
let left = left.to_scalar()?;
302+
let right = right.to_scalar()?;
303+
304+
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
305+
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
306+
307+
match left_layout.ty.sty {
308+
ty::Char => {
309+
assert_eq!(left_layout.ty, right_layout.ty);
310+
let l = left.to_char()?;
311+
let r = right.to_char()?;
312+
self.binary_char_op(bin_op, l, r)
313+
}
314+
ty::Bool => {
315+
assert_eq!(left_layout.ty, right_layout.ty);
316+
let l = left.to_bool()?;
317+
let r = right.to_bool()?;
318+
self.binary_bool_op(bin_op, l, r)
319+
}
320+
ty::Float(fty) => {
321+
assert_eq!(left_layout.ty, right_layout.ty);
322+
let l = left.to_bits(left_layout.size)?;
323+
let r = right.to_bits(right_layout.size)?;
324+
self.binary_float_op(bin_op, fty, l, r)
325+
}
326+
_ => {
327+
// Must be integer(-like) types
328+
#[inline]
329+
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
330+
match ty.sty {
331+
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
332+
_ => false,
333+
}
334+
}
335+
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
336+
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
337+
338+
// Handle operations that support pointer values
339+
if let Some(handled) =
340+
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
341+
{
342+
return Ok(handled);
343+
}
344+
345+
// Everything else only works with "proper" bits
346+
let l = left.to_bits(left_layout.size)?;
347+
let r = right.to_bits(right_layout.size)?;
348+
self.binary_int_op(bin_op, l, left_layout, r, right_layout)
349+
}
350+
}
351+
}
352+
306353
pub fn unary_op(
307354
&self,
308355
un_op: mir::UnOp,

src/librustc_mir/interpret/place.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
660660
// a fake pointer? Are we even called for ZST?
661661

662662
// We need the layout of the local. We can NOT use the layout we got,
663-
// that might e.g. be a downcast variant!
663+
// that might e.g. be an inner field of a struct with `Scalar` layout,
664+
// that has different alignment than the outer field.
664665
let local_layout = self.layout_of_local(frame, local)?;
665666
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
666667
self.write_value_to_mplace(value, ptr)?;
@@ -695,15 +696,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
695696
) -> EvalResult<'tcx> {
696697
match dest.layout.variants {
697698
layout::Variants::Single { index } => {
698-
if index != variant_index {
699-
return err!(InvalidDiscriminant);
700-
}
699+
assert_eq!(index, variant_index);
701700
}
702701
layout::Variants::Tagged { ref tag, .. } => {
703702
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
704-
if variant_index >= adt_def.variants.len() {
705-
return err!(InvalidDiscriminant);
706-
}
703+
assert!(variant_index < adt_def.variants.len());
707704
let discr_val = adt_def
708705
.discriminant_for_variant(*self.tcx, variant_index)
709706
.val;
@@ -727,9 +724,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
727724
niche_start,
728725
..
729726
} => {
730-
if variant_index >= dest.layout.ty.ty_adt_def().unwrap().variants.len() {
731-
return err!(InvalidDiscriminant);
732-
}
727+
assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
733728
if variant_index != dataful_variant {
734729
let niche_dest =
735730
self.place_field(dest, 0)?;

0 commit comments

Comments
 (0)