]>
Commit | Line | Data |
---|---|---|
ff7c6d11 XL |
1 | use rustc::ty::{self, TyCtxt, Ty, Instance}; |
2 | use rustc::ty::layout::{self, LayoutOf}; | |
3 | use rustc::ty::subst::Substs; | |
4 | use rustc::hir::def_id::DefId; | |
5 | use rustc::mir; | |
6 | use rustc::middle::const_val::ErrKind::{CheckMatchError, TypeckError}; | |
7 | use rustc::middle::const_val::{ConstEvalErr, ConstVal}; | |
8 | use rustc_const_eval::{lookup_const_by_id, ConstContext}; | |
9 | use rustc::mir::Field; | |
10 | use rustc_data_structures::indexed_vec::Idx; | |
11 | ||
12 | use syntax::ast::Mutability; | |
13 | use syntax::codemap::Span; | |
14 | ||
2c00a5a8 | 15 | use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal}; |
ff7c6d11 XL |
16 | use super::{Place, EvalContext, StackPopCleanup, ValTy}; |
17 | ||
18 | use rustc_const_math::ConstInt; | |
19 | ||
20 | use std::fmt; | |
21 | use std::error::Error; | |
22 | ||
23 | ||
24 | pub fn mk_eval_cx<'a, 'tcx>( | |
25 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
26 | instance: Instance<'tcx>, | |
27 | param_env: ty::ParamEnv<'tcx>, | |
28 | ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, CompileTimeEvaluator>> { | |
29 | debug!("mk_eval_cx: {:?}, {:?}", instance, param_env); | |
30 | let limits = super::ResourceLimits::default(); | |
31 | let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); | |
32 | let mir = ecx.load_mir(instance.def)?; | |
33 | // insert a stack frame so any queries have the correct substs | |
34 | ecx.push_stack_frame( | |
35 | instance, | |
36 | mir.span, | |
37 | mir, | |
38 | Place::undef(), | |
39 | StackPopCleanup::None, | |
40 | )?; | |
41 | Ok(ecx) | |
42 | } | |
43 | ||
44 | pub fn eval_body<'a, 'tcx>( | |
45 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
46 | instance: Instance<'tcx>, | |
47 | param_env: ty::ParamEnv<'tcx>, | |
48 | ) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> { | |
49 | debug!("eval_body: {:?}, {:?}", instance, param_env); | |
50 | let limits = super::ResourceLimits::default(); | |
51 | let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); | |
52 | let cid = GlobalId { | |
53 | instance, | |
54 | promoted: None, | |
55 | }; | |
56 | ||
57 | if ecx.tcx.has_attr(instance.def_id(), "linkage") { | |
58 | return Err(ConstEvalError::NotConst("extern global".to_string()).into()); | |
59 | } | |
60 | let instance_ty = instance.ty(tcx); | |
61 | if tcx.interpret_interner.borrow().get_cached(cid).is_none() { | |
62 | let mir = ecx.load_mir(instance.def)?; | |
63 | let layout = ecx.layout_of(instance_ty)?; | |
64 | assert!(!layout.is_unsized()); | |
65 | let ptr = ecx.memory.allocate( | |
66 | layout.size.bytes(), | |
67 | layout.align, | |
68 | None, | |
69 | )?; | |
2c00a5a8 | 70 | tcx.interpret_interner.borrow_mut().cache(cid, ptr.alloc_id); |
ff7c6d11 XL |
71 | let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); |
72 | let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); | |
73 | trace!("const_eval: pushing stack frame for global: {}", name); | |
74 | ecx.push_stack_frame( | |
75 | instance, | |
76 | mir.span, | |
77 | mir, | |
78 | Place::from_ptr(ptr, layout.align), | |
79 | cleanup.clone(), | |
80 | )?; | |
81 | ||
82 | while ecx.step()? {} | |
83 | } | |
2c00a5a8 XL |
84 | let alloc = tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"); |
85 | Ok((MemoryPointer::new(alloc, 0).into(), instance_ty)) | |
ff7c6d11 XL |
86 | } |
87 | ||
88 | pub fn eval_body_as_integer<'a, 'tcx>( | |
89 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
90 | param_env: ty::ParamEnv<'tcx>, | |
91 | instance: Instance<'tcx>, | |
92 | ) -> EvalResult<'tcx, ConstInt> { | |
93 | let ptr_ty = eval_body(tcx, instance, param_env); | |
94 | let (ptr, ty) = ptr_ty?; | |
95 | let ecx = mk_eval_cx(tcx, instance, param_env)?; | |
96 | let prim = match ecx.try_read_value(ptr, ecx.layout_of(ty)?.align, ty)? { | |
97 | Some(Value::ByVal(prim)) => prim.to_bytes()?, | |
98 | _ => return err!(TypeNotPrimitive(ty)), | |
99 | }; | |
100 | use syntax::ast::{IntTy, UintTy}; | |
101 | use rustc::ty::TypeVariants::*; | |
102 | use rustc_const_math::{ConstIsize, ConstUsize}; | |
103 | Ok(match ty.sty { | |
104 | TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8), | |
105 | TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16), | |
106 | TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32), | |
107 | TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64), | |
108 | TyInt(IntTy::I128) => ConstInt::I128(prim as i128), | |
2c00a5a8 | 109 | TyInt(IntTy::Isize) => ConstInt::Isize( |
ff7c6d11 XL |
110 | ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty) |
111 | .expect("miri should already have errored"), | |
112 | ), | |
113 | TyUint(UintTy::U8) => ConstInt::U8(prim as u8), | |
114 | TyUint(UintTy::U16) => ConstInt::U16(prim as u16), | |
115 | TyUint(UintTy::U32) => ConstInt::U32(prim as u32), | |
116 | TyUint(UintTy::U64) => ConstInt::U64(prim as u64), | |
117 | TyUint(UintTy::U128) => ConstInt::U128(prim), | |
2c00a5a8 | 118 | TyUint(UintTy::Usize) => ConstInt::Usize( |
ff7c6d11 XL |
119 | ConstUsize::new(prim as u64, tcx.sess.target.usize_ty) |
120 | .expect("miri should already have errored"), | |
121 | ), | |
122 | _ => { | |
123 | return Err( | |
124 | ConstEvalError::NeedsRfc( | |
125 | "evaluating anything other than isize/usize during typeck".to_string(), | |
126 | ).into(), | |
127 | ) | |
128 | } | |
129 | }) | |
130 | } | |
131 | ||
132 | pub struct CompileTimeEvaluator; | |
133 | ||
134 | impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError { | |
135 | fn into(self) -> EvalError<'tcx> { | |
136 | EvalErrorKind::MachineError(Box::new(self)).into() | |
137 | } | |
138 | } | |
139 | ||
140 | #[derive(Clone, Debug)] | |
141 | enum ConstEvalError { | |
142 | NeedsRfc(String), | |
143 | NotConst(String), | |
144 | } | |
145 | ||
146 | impl fmt::Display for ConstEvalError { | |
147 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
148 | use self::ConstEvalError::*; | |
149 | match *self { | |
150 | NeedsRfc(ref msg) => { | |
151 | write!( | |
152 | f, | |
153 | "\"{}\" needs an rfc before being allowed inside constants", | |
154 | msg | |
155 | ) | |
156 | } | |
157 | NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | impl Error for ConstEvalError { | |
163 | fn description(&self) -> &str { | |
164 | use self::ConstEvalError::*; | |
165 | match *self { | |
166 | NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants", | |
167 | NotConst(_) => "this feature is not compatible with constant evaluation", | |
168 | } | |
169 | } | |
170 | ||
171 | fn cause(&self) -> Option<&Error> { | |
172 | None | |
173 | } | |
174 | } | |
175 | ||
176 | impl<'tcx> super::Machine<'tcx> for CompileTimeEvaluator { | |
177 | type MemoryData = (); | |
178 | type MemoryKinds = !; | |
179 | fn eval_fn_call<'a>( | |
180 | ecx: &mut EvalContext<'a, 'tcx, Self>, | |
181 | instance: ty::Instance<'tcx>, | |
182 | destination: Option<(Place, mir::BasicBlock)>, | |
183 | _args: &[ValTy<'tcx>], | |
184 | span: Span, | |
185 | _sig: ty::FnSig<'tcx>, | |
186 | ) -> EvalResult<'tcx, bool> { | |
187 | debug!("eval_fn_call: {:?}", instance); | |
188 | if !ecx.tcx.is_const_fn(instance.def_id()) { | |
189 | return Err( | |
190 | ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), | |
191 | ); | |
192 | } | |
193 | let mir = match ecx.load_mir(instance.def) { | |
194 | Ok(mir) => mir, | |
195 | Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { | |
196 | // some simple things like `malloc` might get accepted in the future | |
197 | return Err( | |
198 | ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) | |
199 | .into(), | |
200 | ); | |
201 | } | |
202 | Err(other) => return Err(other), | |
203 | }; | |
204 | let (return_place, return_to_block) = match destination { | |
205 | Some((place, block)) => (place, StackPopCleanup::Goto(block)), | |
206 | None => (Place::undef(), StackPopCleanup::None), | |
207 | }; | |
208 | ||
209 | ecx.push_stack_frame( | |
210 | instance, | |
211 | span, | |
212 | mir, | |
213 | return_place, | |
214 | return_to_block, | |
215 | )?; | |
216 | ||
217 | Ok(false) | |
218 | } | |
219 | ||
220 | ||
221 | fn call_intrinsic<'a>( | |
222 | ecx: &mut EvalContext<'a, 'tcx, Self>, | |
223 | instance: ty::Instance<'tcx>, | |
224 | _args: &[ValTy<'tcx>], | |
225 | dest: Place, | |
226 | dest_layout: layout::TyLayout<'tcx>, | |
227 | target: mir::BasicBlock, | |
228 | ) -> EvalResult<'tcx> { | |
229 | let substs = instance.substs; | |
230 | ||
231 | let intrinsic_name = &ecx.tcx.item_name(instance.def_id())[..]; | |
232 | match intrinsic_name { | |
233 | "min_align_of" => { | |
234 | let elem_ty = substs.type_at(0); | |
235 | let elem_align = ecx.layout_of(elem_ty)?.align.abi(); | |
236 | let align_val = PrimVal::from_u128(elem_align as u128); | |
237 | ecx.write_primval(dest, align_val, dest_layout.ty)?; | |
238 | } | |
239 | ||
240 | "size_of" => { | |
241 | let ty = substs.type_at(0); | |
242 | let size = ecx.layout_of(ty)?.size.bytes() as u128; | |
243 | ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; | |
244 | } | |
245 | ||
2c00a5a8 XL |
246 | "type_id" => { |
247 | let ty = substs.type_at(0); | |
248 | let type_id = ecx.tcx.type_id_hash(ty) as u128; | |
249 | ecx.write_primval(dest, PrimVal::from_u128(type_id), dest_layout.ty)?; | |
250 | } | |
251 | ||
ff7c6d11 XL |
252 | name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()), |
253 | } | |
254 | ||
255 | ecx.goto_block(target); | |
256 | ||
257 | // Since we pushed no stack frame, the main loop will act | |
258 | // as if the call just completed and it's returning to the | |
259 | // current frame. | |
260 | Ok(()) | |
261 | } | |
262 | ||
263 | fn try_ptr_op<'a>( | |
264 | _ecx: &EvalContext<'a, 'tcx, Self>, | |
265 | _bin_op: mir::BinOp, | |
266 | left: PrimVal, | |
267 | _left_ty: Ty<'tcx>, | |
268 | right: PrimVal, | |
269 | _right_ty: Ty<'tcx>, | |
270 | ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { | |
271 | if left.is_bytes() && right.is_bytes() { | |
272 | Ok(None) | |
273 | } else { | |
274 | Err( | |
275 | ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into(), | |
276 | ) | |
277 | } | |
278 | } | |
279 | ||
280 | fn mark_static_initialized(m: !) -> EvalResult<'tcx> { | |
281 | m | |
282 | } | |
283 | ||
284 | fn box_alloc<'a>( | |
285 | _ecx: &mut EvalContext<'a, 'tcx, Self>, | |
286 | _ty: Ty<'tcx>, | |
287 | _dest: Place, | |
288 | ) -> EvalResult<'tcx> { | |
289 | Err( | |
290 | ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(), | |
291 | ) | |
292 | } | |
293 | ||
294 | fn global_item_with_linkage<'a>( | |
295 | _ecx: &mut EvalContext<'a, 'tcx, Self>, | |
296 | _instance: ty::Instance<'tcx>, | |
297 | _mutability: Mutability, | |
298 | ) -> EvalResult<'tcx> { | |
299 | Err( | |
300 | ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(), | |
301 | ) | |
302 | } | |
303 | } | |
304 | ||
305 | pub fn const_eval_provider<'a, 'tcx>( | |
306 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
307 | key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>, | |
308 | ) -> ::rustc::middle::const_val::EvalResult<'tcx> { | |
309 | trace!("const eval: {:?}", key); | |
310 | let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) { | |
311 | resolved | |
312 | } else { | |
313 | return Err(ConstEvalErr { | |
314 | span: tcx.def_span(key.value.0), | |
315 | kind: TypeckError | |
316 | }); | |
317 | }; | |
318 | ||
319 | let tables = tcx.typeck_tables_of(def_id); | |
320 | let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { | |
321 | let body_id = tcx.hir.body_owned_by(id); | |
322 | ||
323 | // Do match-check before building MIR | |
324 | if tcx.check_match(def_id).is_err() { | |
325 | return Err(ConstEvalErr { | |
326 | span: tcx.def_span(key.value.0), | |
327 | kind: CheckMatchError, | |
328 | }); | |
329 | } | |
330 | ||
331 | tcx.mir_const_qualif(def_id); | |
332 | tcx.hir.body(body_id) | |
333 | } else { | |
334 | tcx.extern_const_body(def_id).body | |
335 | }; | |
336 | ||
337 | // do not continue into miri if typeck errors occurred | |
338 | // it will fail horribly | |
339 | if tables.tainted_by_errors { | |
340 | return Err(ConstEvalErr { span: body.value.span, kind: TypeckError }) | |
341 | } | |
342 | ||
343 | trace!("running old const eval"); | |
344 | let old_result = ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value); | |
345 | trace!("old const eval produced {:?}", old_result); | |
346 | if tcx.sess.opts.debugging_opts.miri { | |
347 | let instance = ty::Instance::new(def_id, substs); | |
348 | trace!("const eval instance: {:?}, {:?}", instance, key.param_env); | |
349 | let miri_result = ::interpret::eval_body(tcx, instance, key.param_env); | |
350 | match (miri_result, old_result) { | |
351 | (Err(err), Ok(ok)) => { | |
352 | trace!("miri failed, ctfe returned {:?}", ok); | |
353 | tcx.sess.span_warn( | |
354 | tcx.def_span(key.value.0), | |
355 | "miri failed to eval, while ctfe succeeded", | |
356 | ); | |
357 | let ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); | |
358 | let () = unwrap_miri(&ecx, Err(err)); | |
359 | Ok(ok) | |
360 | }, | |
361 | (_, Err(err)) => Err(err), | |
362 | (Ok((miri_val, miri_ty)), Ok(ctfe)) => { | |
363 | let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); | |
364 | let layout = ecx.layout_of(miri_ty).unwrap(); | |
365 | let miri_place = Place::from_primval_ptr(miri_val, layout.align); | |
366 | check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); | |
367 | Ok(ctfe) | |
368 | } | |
369 | } | |
370 | } else { | |
371 | old_result | |
372 | } | |
373 | } | |
374 | ||
375 | fn check_ctfe_against_miri<'a, 'tcx>( | |
376 | ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, | |
377 | miri_place: Place, | |
378 | miri_ty: Ty<'tcx>, | |
379 | ctfe: ConstVal<'tcx>, | |
380 | ) { | |
381 | use rustc::middle::const_val::ConstAggregate::*; | |
382 | use rustc_const_math::ConstFloat; | |
383 | use rustc::ty::TypeVariants::*; | |
384 | let miri_val = ValTy { | |
385 | value: ecx.read_place(miri_place).unwrap(), | |
386 | ty: miri_ty | |
387 | }; | |
388 | match miri_ty.sty { | |
389 | TyInt(int_ty) => { | |
390 | let prim = get_prim(ecx, miri_val); | |
391 | let c = ConstInt::new_signed_truncating(prim as i128, | |
392 | int_ty, | |
393 | ecx.tcx.sess.target.isize_ty); | |
394 | let c = ConstVal::Integral(c); | |
395 | assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); | |
396 | }, | |
397 | TyUint(uint_ty) => { | |
398 | let prim = get_prim(ecx, miri_val); | |
399 | let c = ConstInt::new_unsigned_truncating(prim, | |
400 | uint_ty, | |
401 | ecx.tcx.sess.target.usize_ty); | |
402 | let c = ConstVal::Integral(c); | |
403 | assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); | |
404 | }, | |
405 | TyFloat(ty) => { | |
406 | let prim = get_prim(ecx, miri_val); | |
407 | let f = ConstVal::Float(ConstFloat { bits: prim, ty }); | |
408 | assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe); | |
409 | }, | |
410 | TyBool => { | |
411 | let bits = get_prim(ecx, miri_val); | |
412 | if bits > 1 { | |
413 | bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe); | |
414 | } | |
415 | let b = ConstVal::Bool(bits == 1); | |
416 | assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe); | |
417 | }, | |
418 | TyChar => { | |
419 | let bits = get_prim(ecx, miri_val); | |
420 | if let Some(cm) = ::std::char::from_u32(bits as u32) { | |
421 | assert_eq!( | |
422 | ConstVal::Char(cm), ctfe, | |
423 | "miri evaluated to {:?}, but expected {:?}", cm, ctfe, | |
424 | ); | |
425 | } else { | |
426 | bug!("miri evaluated to {}, but expected a char {:?}", bits, ctfe); | |
427 | } | |
428 | }, | |
429 | TyStr => { | |
430 | let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty); | |
431 | if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value { | |
432 | let bytes = ecx | |
433 | .memory | |
434 | .read_bytes(ptr.into(), len as u64) | |
435 | .expect("bad miri memory for str"); | |
436 | if let Ok(s) = ::std::str::from_utf8(bytes) { | |
437 | if let ConstVal::Str(s2) = ctfe { | |
438 | assert_eq!(s, s2, "miri produced {:?}, but expected {:?}", s, s2); | |
439 | } else { | |
440 | bug!("miri produced {:?}, but expected {:?}", s, ctfe); | |
441 | } | |
442 | } else { | |
443 | bug!( | |
444 | "miri failed to produce valid utf8 {:?}, while ctfe produced {:?}", | |
445 | bytes, | |
446 | ctfe, | |
447 | ); | |
448 | } | |
449 | } else { | |
450 | bug!("miri evaluated to {:?}, but expected a str {:?}", value, ctfe); | |
451 | } | |
452 | }, | |
453 | TyArray(elem_ty, n) => { | |
454 | let n = n.val.to_const_int().unwrap().to_u64().unwrap(); | |
455 | let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { | |
456 | ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { | |
457 | (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) | |
458 | }).collect(), | |
459 | ConstVal::Aggregate(Array(v)) => { | |
460 | v.iter().map(|c| (c.val, c.ty)).collect() | |
461 | }, | |
462 | ConstVal::Aggregate(Repeat(v, n)) => { | |
463 | vec![(v.val, v.ty); n as usize] | |
464 | }, | |
465 | _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), | |
466 | }; | |
467 | let layout = ecx.layout_of(miri_ty).unwrap(); | |
468 | for (i, elem) in vec.into_iter().enumerate() { | |
469 | assert!((i as u64) < n); | |
470 | let (field_place, _) = | |
471 | ecx.place_field(miri_place, Field::new(i), layout).unwrap(); | |
472 | check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0); | |
473 | } | |
474 | }, | |
475 | TyTuple(..) => { | |
476 | let vec = match ctfe { | |
477 | ConstVal::Aggregate(Tuple(v)) => v, | |
478 | _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), | |
479 | }; | |
480 | let layout = ecx.layout_of(miri_ty).unwrap(); | |
481 | for (i, elem) in vec.into_iter().enumerate() { | |
482 | let (field_place, _) = | |
483 | ecx.place_field(miri_place, Field::new(i), layout).unwrap(); | |
484 | check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); | |
485 | } | |
486 | }, | |
487 | TyAdt(def, _) => { | |
488 | let mut miri_place = miri_place; | |
489 | let struct_variant = if def.is_enum() { | |
490 | let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap(); | |
491 | let variant = def.discriminants(ecx.tcx).position(|variant_discr| { | |
492 | variant_discr.to_u128_unchecked() == discr | |
493 | }).expect("miri produced invalid enum discriminant"); | |
494 | miri_place = ecx.place_downcast(miri_place, variant).unwrap(); | |
495 | &def.variants[variant] | |
496 | } else { | |
2c00a5a8 | 497 | def.non_enum_variant() |
ff7c6d11 XL |
498 | }; |
499 | let vec = match ctfe { | |
500 | ConstVal::Aggregate(Struct(v)) => v, | |
501 | ConstVal::Variant(did) => { | |
502 | assert_eq!(struct_variant.fields.len(), 0); | |
503 | assert_eq!(did, struct_variant.did); | |
504 | return; | |
505 | }, | |
506 | ctfe => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), | |
507 | }; | |
508 | let layout = ecx.layout_of(miri_ty).unwrap(); | |
509 | for &(name, elem) in vec.into_iter() { | |
510 | let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap(); | |
511 | let (field_place, _) = | |
512 | ecx.place_field(miri_place, Field::new(field), layout).unwrap(); | |
513 | check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); | |
514 | } | |
515 | }, | |
516 | TySlice(_) => bug!("miri produced a slice?"), | |
517 | // not supported by ctfe | |
518 | TyRawPtr(_) | | |
519 | TyRef(..) => {} | |
520 | TyDynamic(..) => bug!("miri produced a trait object"), | |
521 | TyClosure(..) => bug!("miri produced a closure"), | |
522 | TyGenerator(..) => bug!("miri produced a generator"), | |
2c00a5a8 | 523 | TyGeneratorWitness(..) => bug!("miri produced a generator witness"), |
ff7c6d11 XL |
524 | TyNever => bug!("miri produced a value of the never type"), |
525 | TyProjection(_) => bug!("miri produced a projection"), | |
526 | TyAnon(..) => bug!("miri produced an impl Trait type"), | |
527 | TyParam(_) => bug!("miri produced an unmonomorphized type"), | |
528 | TyInfer(_) => bug!("miri produced an uninferred type"), | |
529 | TyError => bug!("miri produced a type error"), | |
530 | TyForeign(_) => bug!("miri produced an extern type"), | |
531 | // should be fine | |
532 | TyFnDef(..) => {} | |
533 | TyFnPtr(_) => { | |
534 | let value = ecx.value_to_primval(miri_val); | |
535 | let ptr = match value { | |
536 | Ok(PrimVal::Ptr(ptr)) => ptr, | |
537 | value => bug!("expected fn ptr, got {:?}", value), | |
538 | }; | |
539 | let inst = ecx.memory.get_fn(ptr).unwrap(); | |
540 | match ctfe { | |
541 | ConstVal::Function(did, substs) => { | |
542 | let ctfe = ty::Instance::resolve( | |
543 | ecx.tcx, | |
544 | ecx.param_env, | |
545 | did, | |
546 | substs, | |
547 | ).unwrap(); | |
548 | assert_eq!(inst, ctfe, "expected fn ptr {:?}, but got {:?}", ctfe, inst); | |
549 | }, | |
550 | _ => bug!("ctfe produced {:?}, but miri produced function {:?}", ctfe, inst), | |
551 | } | |
552 | }, | |
553 | } | |
554 | } | |
555 | ||
556 | fn get_prim<'a, 'tcx>( | |
557 | ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, | |
558 | val: ValTy<'tcx>, | |
559 | ) -> u128 { | |
560 | let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes()); | |
561 | unwrap_miri(ecx, res) | |
562 | } | |
563 | ||
564 | fn unwrap_miri<'a, 'tcx, T>( | |
565 | ecx: &EvalContext<'a, 'tcx, CompileTimeEvaluator>, | |
566 | res: Result<T, EvalError<'tcx>>, | |
567 | ) -> T { | |
568 | match res { | |
569 | Ok(val) => val, | |
570 | Err(mut err) => { | |
571 | ecx.report(&mut err); | |
572 | ecx.tcx.sess.abort_if_errors(); | |
573 | bug!("{:#?}", err); | |
574 | } | |
575 | } | |
576 | } |