]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/const_eval.rs
Rollup merge of #57278 - mati865:config_clippy, r=alexcrichton
[rust.git] / src / librustc_mir / const_eval.rs
1 // Not in interpret to make sure we do not use private implementation details
2
3 use std::fmt;
4 use std::error::Error;
5 use std::borrow::{Borrow, Cow};
6 use std::hash::Hash;
7 use std::collections::hash_map::Entry;
8
9 use rustc::hir::{self, def_id::DefId};
10 use rustc::hir::def::Def;
11 use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
12 use rustc::mir;
13 use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
14 use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
15 use rustc::ty::subst::Subst;
16 use rustc::traits::Reveal;
17 use rustc_data_structures::indexed_vec::IndexVec;
18 use rustc_data_structures::fx::FxHashMap;
19 use rustc::util::common::ErrorReported;
20
21 use syntax::ast::Mutability;
22 use syntax::source_map::{Span, DUMMY_SP};
23
24 use crate::interpret::{self,
25     PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
26     EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
27     Allocation, AllocId, MemoryKind,
28     snapshot, RefTracking,
29 };
30
31 /// Number of steps until the detector even starts doing anything.
32 /// Also, a warning is shown to the user when this number is reached.
33 const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
34 /// The number of steps between loop detector snapshots.
35 /// Should be a power of two for performance reasons.
36 const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
37
38 pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
39     tcx: TyCtxt<'a, 'tcx, 'tcx>,
40     instance: Instance<'tcx>,
41     mir: &'mir mir::Mir<'tcx>,
42     span: Span,
43 ) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
44     debug!("mk_borrowck_eval_cx: {:?}", instance);
45     let param_env = tcx.param_env(instance.def_id());
46     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
47     // insert a stack frame so any queries have the correct substs
48     // cannot use `push_stack_frame`; if we do `const_prop` explodes
49     ecx.stack.push(interpret::Frame {
50         block: mir::START_BLOCK,
51         locals: IndexVec::new(),
52         instance,
53         span,
54         mir,
55         return_place: None,
56         return_to_block: StackPopCleanup::Goto(None), // never pop
57         stmt: 0,
58         extra: (),
59     });
60     Ok(ecx)
61 }
62
63 pub fn mk_eval_cx<'a, 'tcx>(
64     tcx: TyCtxt<'a, 'tcx, 'tcx>,
65     instance: Instance<'tcx>,
66     param_env: ty::ParamEnv<'tcx>,
67 ) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
68     debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
69     let span = tcx.def_span(instance.def_id());
70     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
71     let mir = ecx.load_mir(instance.def)?;
72     // insert a stack frame so any queries have the correct substs
73     ecx.push_stack_frame(
74         instance,
75         mir.span,
76         mir,
77         None,
78         StackPopCleanup::Goto(None), // never pop
79     )?;
80     Ok(ecx)
81 }
82
83 pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
84     tcx: TyCtxt<'a, 'tcx, 'tcx>,
85     cid: GlobalId<'tcx>,
86     mir: &'mir mir::Mir<'tcx>,
87     param_env: ty::ParamEnv<'tcx>,
88 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
89     let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
90     eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
91 }
92
93 // FIXME: These two conversion functions are bad hacks.  We should just always use allocations.
94 pub fn op_to_const<'tcx>(
95     ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
96     op: OpTy<'tcx>,
97     may_normalize: bool,
98 ) -> EvalResult<'tcx, ty::Const<'tcx>> {
99     // We do not normalize just any data.  Only scalar layout and fat pointers.
100     let normalize = may_normalize
101         && match op.layout.abi {
102             layout::Abi::Scalar(..) => true,
103             layout::Abi::ScalarPair(..) => {
104                 // Must be a fat pointer
105                 op.layout.ty.builtin_deref(true).is_some()
106             },
107             _ => false,
108         };
109     let normalized_op = if normalize {
110         ecx.try_read_immediate(op)?
111     } else {
112         match op.op {
113             Operand::Indirect(mplace) => Err(mplace),
114             Operand::Immediate(val) => Ok(val)
115         }
116     };
117     let val = match normalized_op {
118         Err(MemPlace { ptr, align, meta }) => {
119             // extract alloc-offset pair
120             assert!(meta.is_none());
121             let ptr = ptr.to_ptr()?;
122             let alloc = ecx.memory.get(ptr.alloc_id)?;
123             assert!(alloc.align >= align);
124             assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= op.layout.size.bytes());
125             let mut alloc = alloc.clone();
126             alloc.align = align;
127             // FIXME shouldn't it be the case that `mark_static_initialized` has already
128             // interned this?  I thought that is the entire point of that `FinishStatic` stuff?
129             let alloc = ecx.tcx.intern_const_alloc(alloc);
130             ConstValue::ByRef(ptr.alloc_id, alloc, ptr.offset)
131         },
132         Ok(Immediate::Scalar(x)) =>
133             ConstValue::Scalar(x.not_undef()?),
134         Ok(Immediate::ScalarPair(a, b)) =>
135             ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?),
136     };
137     Ok(ty::Const { val, ty: op.layout.ty })
138 }
139
140 pub fn lazy_const_to_op<'tcx>(
141     ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
142     cnst: ty::LazyConst<'tcx>,
143     ty: ty::Ty<'tcx>,
144 ) -> EvalResult<'tcx, OpTy<'tcx>> {
145     let op = ecx.const_value_to_op(cnst)?;
146     Ok(OpTy { op, layout: ecx.layout_of(ty)? })
147 }
148
149 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
150     tcx: TyCtxt<'a, 'tcx, 'tcx>,
151     cid: GlobalId<'tcx>,
152     mir: Option<&'mir mir::Mir<'tcx>>,
153     param_env: ty::ParamEnv<'tcx>,
154 ) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
155     // we start out with the best span we have
156     // and try improving it down the road when more information is available
157     let span = tcx.def_span(cid.instance.def_id());
158     let span = mir.map(|mir| mir.span).unwrap_or(span);
159     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
160     let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
161     (r, ecx)
162 }
163
164 // Returns a pointer to where the result lives
165 fn eval_body_using_ecx<'mir, 'tcx>(
166     ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
167     cid: GlobalId<'tcx>,
168     mir: Option<&'mir mir::Mir<'tcx>>,
169     param_env: ty::ParamEnv<'tcx>,
170 ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
171     debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
172     let tcx = ecx.tcx.tcx;
173     let mut mir = match mir {
174         Some(mir) => mir,
175         None => ecx.load_mir(cid.instance.def)?,
176     };
177     if let Some(index) = cid.promoted {
178         mir = &mir.promoted[index];
179     }
180     let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
181     assert!(!layout.is_unsized());
182     let ret = ecx.allocate(layout, MemoryKind::Stack);
183
184     let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
185     let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
186     trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom);
187     assert!(mir.arg_count == 0);
188     ecx.push_stack_frame(
189         cid.instance,
190         mir.span,
191         mir,
192         Some(ret.into()),
193         StackPopCleanup::None { cleanup: false },
194     )?;
195
196     // The main interpreter loop.
197     ecx.run()?;
198
199     // Intern the result
200     let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
201     let is_static = tcx.is_static(cid.instance.def_id());
202     let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable {
203         Mutability::Mutable
204     } else {
205         Mutability::Immutable
206     };
207     ecx.memory.intern_static(ret.ptr.to_ptr()?.alloc_id, mutability)?;
208
209     debug!("eval_body_using_ecx done: {:?}", *ret);
210     Ok(ret)
211 }
212
213 impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
214     fn into(self) -> EvalError<'tcx> {
215         EvalErrorKind::MachineError(self.to_string()).into()
216     }
217 }
218
219 #[derive(Clone, Debug)]
220 enum ConstEvalError {
221     NeedsRfc(String),
222 }
223
224 impl fmt::Display for ConstEvalError {
225     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226         use self::ConstEvalError::*;
227         match *self {
228             NeedsRfc(ref msg) => {
229                 write!(
230                     f,
231                     "\"{}\" needs an rfc before being allowed inside constants",
232                     msg
233                 )
234             }
235         }
236     }
237 }
238
239 impl Error for ConstEvalError {
240     fn description(&self) -> &str {
241         use self::ConstEvalError::*;
242         match *self {
243             NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
244         }
245     }
246
247     fn cause(&self) -> Option<&dyn Error> {
248         None
249     }
250 }
251
252 // Extra machine state for CTFE, and the Machine instance
253 pub struct CompileTimeInterpreter<'a, 'mir, 'tcx: 'a+'mir> {
254     /// When this value is negative, it indicates the number of interpreter
255     /// steps *until* the loop detector is enabled. When it is positive, it is
256     /// the number of steps after the detector has been enabled modulo the loop
257     /// detector period.
258     pub(super) steps_since_detector_enabled: isize,
259
260     /// Extra state to detect loops.
261     pub(super) loop_detector: snapshot::InfiniteLoopDetector<'a, 'mir, 'tcx>,
262 }
263
264 impl<'a, 'mir, 'tcx> CompileTimeInterpreter<'a, 'mir, 'tcx> {
265     fn new() -> Self {
266         CompileTimeInterpreter {
267             loop_detector: Default::default(),
268             steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED,
269         }
270     }
271 }
272
273 impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
274     #[inline(always)]
275     fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
276         where K: Borrow<Q>
277     {
278         FxHashMap::contains_key(self, k)
279     }
280
281     #[inline(always)]
282     fn insert(&mut self, k: K, v: V) -> Option<V>
283     {
284         FxHashMap::insert(self, k, v)
285     }
286
287     #[inline(always)]
288     fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
289         where K: Borrow<Q>
290     {
291         FxHashMap::remove(self, k)
292     }
293
294     #[inline(always)]
295     fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
296         self.iter()
297             .filter_map(move |(k, v)| f(k, &*v))
298             .collect()
299     }
300
301     #[inline(always)]
302     fn get_or<E>(
303         &self,
304         k: K,
305         vacant: impl FnOnce() -> Result<V, E>
306     ) -> Result<&V, E>
307     {
308         match self.get(&k) {
309             Some(v) => Ok(v),
310             None => {
311                 vacant()?;
312                 bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
313             }
314         }
315     }
316
317     #[inline(always)]
318     fn get_mut_or<E>(
319         &mut self,
320         k: K,
321         vacant: impl FnOnce() -> Result<V, E>
322     ) -> Result<&mut V, E>
323     {
324         match self.entry(k) {
325             Entry::Occupied(e) => Ok(e.into_mut()),
326             Entry::Vacant(e) => {
327                 let v = vacant()?;
328                 Ok(e.insert(v))
329             }
330         }
331     }
332 }
333
334 type CompileTimeEvalContext<'a, 'mir, 'tcx> =
335     EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
336
337 impl interpret::MayLeak for ! {
338     #[inline(always)]
339     fn may_leak(self) -> bool {
340         // `self` is uninhabited
341         self
342     }
343 }
344
345 impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
346     for CompileTimeInterpreter<'a, 'mir, 'tcx>
347 {
348     type MemoryKinds = !;
349     type PointerTag = ();
350
351     type FrameExtra = ();
352     type MemoryExtra = ();
353     type AllocExtra = ();
354
355     type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
356
357     const STATIC_KIND: Option<!> = None; // no copying of statics allowed
358
359     #[inline(always)]
360     fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
361         false // for now, we don't enforce validity
362     }
363
364     fn find_fn(
365         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
366         instance: ty::Instance<'tcx>,
367         args: &[OpTy<'tcx>],
368         dest: Option<PlaceTy<'tcx>>,
369         ret: Option<mir::BasicBlock>,
370     ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
371         debug!("eval_fn_call: {:?}", instance);
372         // Execution might have wandered off into other crates, so we cannot to a stability-
373         // sensitive check here.  But we can at least rule out functions that are not const
374         // at all.
375         if !ecx.tcx.is_const_fn_raw(instance.def_id()) {
376             // Some functions we support even if they are non-const -- but avoid testing
377             // that for const fn!  We certainly do *not* want to actually call the fn
378             // though, so be sure we return here.
379             return if ecx.hook_fn(instance, args, dest)? {
380                 ecx.goto_block(ret)?; // fully evaluated and done
381                 Ok(None)
382             } else {
383                 err!(MachineError(format!("calling non-const function `{}`", instance)))
384             };
385         }
386         // This is a const fn. Call it.
387         Ok(Some(match ecx.load_mir(instance.def) {
388             Ok(mir) => mir,
389             Err(err) => {
390                 if let EvalErrorKind::NoMirFor(ref path) = err.kind {
391                     return Err(
392                         ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
393                             .into(),
394                     );
395                 }
396                 return Err(err);
397             }
398         }))
399     }
400
401     fn call_intrinsic(
402         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
403         instance: ty::Instance<'tcx>,
404         args: &[OpTy<'tcx>],
405         dest: PlaceTy<'tcx>,
406     ) -> EvalResult<'tcx> {
407         if ecx.emulate_intrinsic(instance, args, dest)? {
408             return Ok(());
409         }
410         // An intrinsic that we do not support
411         let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..];
412         Err(
413             ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()
414         )
415     }
416
417     fn ptr_op(
418         _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
419         _bin_op: mir::BinOp,
420         _left: Scalar,
421         _left_layout: TyLayout<'tcx>,
422         _right: Scalar,
423         _right_layout: TyLayout<'tcx>,
424     ) -> EvalResult<'tcx, (Scalar, bool)> {
425         Err(
426             ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
427         )
428     }
429
430     fn find_foreign_static(
431         _def_id: DefId,
432         _tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
433         _memory_extra: &(),
434     ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
435         err!(ReadForeignStatic)
436     }
437
438     #[inline(always)]
439     fn adjust_static_allocation<'b>(
440         alloc: &'b Allocation,
441         _memory_extra: &(),
442     ) -> Cow<'b, Allocation<Self::PointerTag>> {
443         // We do not use a tag so we can just cheaply forward the reference
444         Cow::Borrowed(alloc)
445     }
446
447     fn box_alloc(
448         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
449         _dest: PlaceTy<'tcx>,
450     ) -> EvalResult<'tcx> {
451         Err(
452             ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
453         )
454     }
455
456     fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
457         {
458             let steps = &mut ecx.machine.steps_since_detector_enabled;
459
460             *steps += 1;
461             if *steps < 0 {
462                 return Ok(());
463             }
464
465             *steps %= DETECTOR_SNAPSHOT_PERIOD;
466             if *steps != 0 {
467                 return Ok(());
468             }
469         }
470
471         let span = ecx.frame().span;
472         ecx.machine.loop_detector.observe_and_analyze(
473             &ecx.tcx,
474             span,
475             &ecx.memory,
476             &ecx.stack[..],
477         )
478     }
479
480     #[inline(always)]
481     fn tag_new_allocation(
482         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
483         ptr: Pointer,
484         _kind: MemoryKind<Self::MemoryKinds>,
485     ) -> Pointer {
486         ptr
487     }
488
489     #[inline(always)]
490     fn stack_push(
491         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
492     ) -> EvalResult<'tcx> {
493         Ok(())
494     }
495
496     /// Called immediately before a stack frame gets popped
497     #[inline(always)]
498     fn stack_pop(
499         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
500         _extra: (),
501     ) -> EvalResult<'tcx> {
502         Ok(())
503     }
504 }
505
506 /// Project to a field of a (variant of a) const
507 pub fn const_field<'a, 'tcx>(
508     tcx: TyCtxt<'a, 'tcx, 'tcx>,
509     param_env: ty::ParamEnv<'tcx>,
510     instance: ty::Instance<'tcx>,
511     variant: Option<VariantIdx>,
512     field: mir::Field,
513     value: ty::Const<'tcx>,
514 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
515     trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
516     let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
517     let result = (|| {
518         // get the operand again
519         let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
520         // downcast
521         let down = match variant {
522             None => op,
523             Some(variant) => ecx.operand_downcast(op, variant)?
524         };
525         // then project
526         let field = ecx.operand_field(down, field.index() as u64)?;
527         // and finally move back to the const world, always normalizing because
528         // this is not called for statics.
529         op_to_const(&ecx, field, true)
530     })();
531     result.map_err(|error| {
532         let err = error_to_const_error(&ecx, error);
533         err.report_as_error(ecx.tcx, "could not access field of constant");
534         ErrorHandled::Reported
535     })
536 }
537
538 pub fn const_variant_index<'a, 'tcx>(
539     tcx: TyCtxt<'a, 'tcx, 'tcx>,
540     param_env: ty::ParamEnv<'tcx>,
541     instance: ty::Instance<'tcx>,
542     val: ty::Const<'tcx>,
543 ) -> EvalResult<'tcx, VariantIdx> {
544     trace!("const_variant_index: {:?}, {:?}", instance, val);
545     let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
546     let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
547     Ok(ecx.read_discriminant(op)?.1)
548 }
549
550 pub fn error_to_const_error<'a, 'mir, 'tcx>(
551     ecx: &EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
552     mut error: EvalError<'tcx>
553 ) -> ConstEvalErr<'tcx> {
554     error.print_backtrace();
555     let stacktrace = ecx.generate_stacktrace(None);
556     ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
557 }
558
559 fn validate_and_turn_into_const<'a, 'tcx>(
560     tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
561     constant: RawConst<'tcx>,
562     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
563 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
564     let cid = key.value;
565     let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
566     let val = (|| {
567         let op = ecx.raw_const_to_mplace(constant)?.into();
568         // FIXME: Once the visitor infrastructure landed, change validation to
569         // work directly on `MPlaceTy`.
570         let mut ref_tracking = RefTracking::new(op);
571         while let Some((op, path)) = ref_tracking.todo.pop() {
572             ecx.validate_operand(
573                 op,
574                 path,
575                 Some(&mut ref_tracking),
576                 /* const_mode */ true,
577             )?;
578         }
579         // Now that we validated, turn this into a proper constant
580         let def_id = cid.instance.def.def_id();
581         let normalize = tcx.is_static(def_id).is_none() && cid.promoted.is_none();
582         op_to_const(&ecx, op, normalize)
583     })();
584
585     val.map_err(|error| {
586         let err = error_to_const_error(&ecx, error);
587         match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
588             Ok(mut diag) => {
589                 diag.note("The rules on what exactly is undefined behavior aren't clear, \
590                     so this check might be overzealous. Please open an issue on the rust compiler \
591                     repository if you believe it should not be considered undefined behavior",
592                 );
593                 diag.emit();
594                 ErrorHandled::Reported
595             }
596             Err(err) => err,
597         }
598     })
599 }
600
601 pub fn const_eval_provider<'a, 'tcx>(
602     tcx: TyCtxt<'a, 'tcx, 'tcx>,
603     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
604 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
605     // see comment in const_eval_provider for what we're doing here
606     if key.param_env.reveal == Reveal::All {
607         let mut key = key.clone();
608         key.param_env.reveal = Reveal::UserFacing;
609         match tcx.const_eval(key) {
610             // try again with reveal all as requested
611             Err(ErrorHandled::TooGeneric) => {
612                 // Promoteds should never be "too generic" when getting evaluated.
613                 // They either don't get evaluated, or we are in a monomorphic context
614                 assert!(key.value.promoted.is_none());
615             },
616             // dedupliate calls
617             other => return other,
618         }
619     }
620     tcx.const_eval_raw(key).and_then(|val| {
621         validate_and_turn_into_const(tcx, val, key)
622     })
623 }
624
625 pub fn const_eval_raw_provider<'a, 'tcx>(
626     tcx: TyCtxt<'a, 'tcx, 'tcx>,
627     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
628 ) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> {
629     // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
630     // reporting the same error twice here. To resolve this, we check whether we can evaluate the
631     // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
632     // computed. For a large percentage of constants that will already have succeeded. Only
633     // associated constants of generic functions will fail due to not enough monomorphization
634     // information being available.
635
636     // In case we fail in the `UserFacing` variant, we just do the real computation.
637     if key.param_env.reveal == Reveal::All {
638         let mut key = key.clone();
639         key.param_env.reveal = Reveal::UserFacing;
640         match tcx.const_eval_raw(key) {
641             // try again with reveal all as requested
642             Err(ErrorHandled::TooGeneric) => {},
643             // dedupliate calls
644             other => return other,
645         }
646     }
647     // the first trace is for replicating an ice
648     // There's no tracking issue, but the next two lines concatenated link to the discussion on
649     // zulip. It's not really possible to test this, because it doesn't show up in diagnostics
650     // or MIR.
651     // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
652     // subject/anon_const_instance_printing/near/135980032
653     trace!("const eval: {}", key.value.instance);
654     trace!("const eval: {:?}", key);
655
656     let cid = key.value;
657     let def_id = cid.instance.def.def_id();
658
659     if let Some(id) = tcx.hir().as_local_node_id(def_id) {
660         let tables = tcx.typeck_tables_of(def_id);
661
662         // Do match-check before building MIR
663         if let Err(ErrorReported) = tcx.check_match(def_id) {
664             return Err(ErrorHandled::Reported)
665         }
666
667         if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(id) {
668             tcx.mir_const_qualif(def_id);
669         }
670
671         // Do not continue into miri if typeck errors occurred; it will fail horribly
672         if tables.tainted_by_errors {
673             return Err(ErrorHandled::Reported)
674         }
675     };
676
677     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
678     res.and_then(|place| {
679         Ok(RawConst {
680             alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
681             ty: place.layout.ty
682         })
683     }).map_err(|error| {
684         let err = error_to_const_error(&ecx, error);
685         // errors in statics are always emitted as fatal errors
686         if tcx.is_static(def_id).is_some() {
687             let reported_err = err.report_as_error(ecx.tcx,
688                                                    "could not evaluate static initializer");
689             // Ensure that if the above error was either `TooGeneric` or `Reported`
690             // an error must be reported.
691             if tcx.sess.err_count() == 0 {
692                 tcx.sess.delay_span_bug(err.span,
693                                         &format!("static eval failure did not emit an error: {:#?}",
694                                                  reported_err));
695             }
696             reported_err
697         } else if def_id.is_local() {
698             // constant defined in this crate, we can figure out a lint level!
699             match tcx.describe_def(def_id) {
700                 // constants never produce a hard error at the definition site. Anything else is
701                 // a backwards compatibility hazard (and will break old versions of winapi for sure)
702                 //
703                 // note that validation may still cause a hard error on this very same constant,
704                 // because any code that existed before validation could not have failed validation
705                 // thus preventing such a hard error from being a backwards compatibility hazard
706                 Some(Def::Const(_)) | Some(Def::AssociatedConst(_)) => {
707                     let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
708                     err.report_as_lint(
709                         tcx.at(tcx.def_span(def_id)),
710                         "any use of this value will cause an error",
711                         node_id,
712                     )
713                 },
714                 // promoting runtime code is only allowed to error if it references broken constants
715                 // any other kind of error will be reported to the user as a deny-by-default lint
716                 _ => if let Some(p) = cid.promoted {
717                     let span = tcx.optimized_mir(def_id).promoted[p].span;
718                     if let EvalErrorKind::ReferencedConstant = err.error {
719                         err.report_as_error(
720                             tcx.at(span),
721                             "evaluation of constant expression failed",
722                         )
723                     } else {
724                         err.report_as_lint(
725                             tcx.at(span),
726                             "reaching this expression at runtime will panic or abort",
727                             tcx.hir().as_local_node_id(def_id).unwrap(),
728                         )
729                     }
730                 // anything else (array lengths, enum initializers, constant patterns) are reported
731                 // as hard errors
732                 } else {
733                     err.report_as_error(
734                         ecx.tcx,
735                         "evaluation of constant value failed",
736                     )
737                 },
738             }
739         } else {
740             // use of broken constant from other crate
741             err.report_as_error(ecx.tcx, "could not evaluate constant")
742         }
743     })
744 }