]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/const_eval.rs
New upstream version 1.39.0+dfsg1
[rustc.git] / src / librustc_mir / const_eval.rs
CommitLineData
b7449926
XL
1// Not in interpret to make sure we do not use private implementation details
2
3use std::fmt;
4use std::error::Error;
0bf4aa26
XL
5use std::borrow::{Borrow, Cow};
6use std::hash::Hash;
7use std::collections::hash_map::Entry;
dc9dc135 8use std::convert::TryInto;
b7449926 9
48663c56
XL
10use rustc::hir::def::DefKind;
11use rustc::hir::def_id::DefId;
dc9dc135 12use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
b7449926 13use rustc::mir;
e1599b0c 14use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
dc9dc135 15use rustc::ty::layout::{self, LayoutOf, VariantIdx};
a1dfa0c6 16use rustc::traits::Reveal;
532ac7d7 17use rustc_data_structures::fx::FxHashMap;
e1599b0c 18use crate::interpret::eval_nullary_intrinsic;
b7449926 19
0bf4aa26 20use syntax::source_map::{Span, DUMMY_SP};
b7449926 21
a1dfa0c6 22use crate::interpret::{self,
416331ca 23 PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
9fa01778 24 RawConst, ConstValue,
416331ca 25 InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
dc9dc135
XL
26 Allocation, AllocId, MemoryKind, Memory,
27 snapshot, RefTracking, intern_const_alloc_recursive,
b7449926
XL
28};
29
0bf4aa26
XL
30/// Number of steps until the detector even starts doing anything.
31/// Also, a warning is shown to the user when this number is reached.
32const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
33/// The number of steps between loop detector snapshots.
34/// Should be a power of two for performance reasons.
35const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
36
416331ca 37/// The `InterpCx` is only meant to be used to do field and index projections into constants for
0731742a
XL
38/// `simd_shuffle` and const patterns in match arms.
39///
40/// The function containing the `match` that is currently being analyzed may have generic bounds
9fa01778 41/// that inform us about the generic bounds of the constant. E.g., using an associated constant
0731742a
XL
42/// of a function's generic parameter will require knowledge about the bounds on the generic
43/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
dc9dc135
XL
44pub(crate) fn mk_eval_cx<'mir, 'tcx>(
45 tcx: TyCtxt<'tcx>,
9fa01778 46 span: Span,
b7449926 47 param_env: ty::ParamEnv<'tcx>,
dc9dc135 48) -> CompileTimeEvalContext<'mir, 'tcx> {
9fa01778 49 debug!("mk_eval_cx: {:?}", param_env);
416331ca 50 InterpCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default())
b7449926
XL
51}
52
9fa01778 53fn op_to_const<'tcx>(
dc9dc135 54 ecx: &CompileTimeEvalContext<'_, 'tcx>,
b7449926 55 op: OpTy<'tcx>,
dc9dc135
XL
56) -> &'tcx ty::Const<'tcx> {
57 // We do not have value optmizations for everything.
58 // Only scalars and slices, since they are very common.
59 // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result
60 // from scalar unions that are initialized with one of their zero sized variants. We could
61 // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all
62 // the usual cases of extracting e.g. a `usize`, without there being a real use case for the
63 // `Undef` situation.
64 let try_as_immediate = match op.layout.abi {
65 layout::Abi::Scalar(..) => true,
66 layout::Abi::ScalarPair(..) => match op.layout.ty.sty {
67 ty::Ref(_, inner, _) => match inner.sty {
68 ty::Slice(elem) => elem == ecx.tcx.types.u8,
69 ty::Str => true,
70 _ => false,
71 },
72 _ => false,
73 },
9fa01778
XL
74 _ => false,
75 };
dc9dc135
XL
76 let immediate = if try_as_immediate {
77 Err(ecx.read_immediate(op).expect("normalization works on validated constants"))
b7449926 78 } else {
dc9dc135
XL
79 // It is guaranteed that any non-slice scalar pair is actually ByRef here.
80 // When we come back from raw const eval, we are always by-ref. The only way our op here is
81 // by-val is if we are in const_field, i.e., if this is (a field of) something that we
82 // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
83 // structs containing such.
9fa01778 84 op.try_as_mplace()
b7449926 85 };
dc9dc135
XL
86 let val = match immediate {
87 Ok(mplace) => {
88 let ptr = mplace.ptr.to_ptr().unwrap();
89 let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
416331ca 90 ConstValue::ByRef { alloc, offset: ptr.offset }
dc9dc135
XL
91 },
92 // see comment on `let try_as_immediate` above
93 Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x {
94 ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s),
95 ScalarMaybeUndef::Undef => {
96 // When coming out of "normal CTFE", we'll always have an `Indirect` operand as
97 // argument and we will not need this. The only way we can already have an
98 // `Immediate` is when we are called from `const_field`, and that `Immediate`
99 // comes from a constant so it can happen have `Undef`, because the indirect
100 // memory that was read had undefined bytes.
416331ca 101 let mplace = op.assert_mem_place();
dc9dc135
XL
102 let ptr = mplace.ptr.to_ptr().unwrap();
103 let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
416331ca 104 ConstValue::ByRef { alloc, offset: ptr.offset }
dc9dc135
XL
105 },
106 },
107 Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => {
108 let (data, start) = match a.not_undef().unwrap() {
109 Scalar::Ptr(ptr) => (
110 ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
111 ptr.offset.bytes(),
112 ),
113 Scalar::Raw { .. } => (
114 ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(
115 b"" as &[u8],
116 )),
117 0,
118 ),
119 };
120 let len = b.to_usize(&ecx.tcx.tcx).unwrap();
121 let start = start.try_into().unwrap();
122 let len: usize = len.try_into().unwrap();
123 ConstValue::Slice {
124 data,
125 start,
126 end: start + len,
127 }
128 },
b7449926 129 };
dc9dc135 130 ecx.tcx.mk_const(ty::Const { val, ty: op.layout.ty })
b7449926 131}
0731742a 132
b7449926 133// Returns a pointer to where the result lives
0bf4aa26 134fn eval_body_using_ecx<'mir, 'tcx>(
dc9dc135 135 ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
b7449926 136 cid: GlobalId<'tcx>,
dc9dc135 137 body: &'mir mir::Body<'tcx>,
dc9dc135 138) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
e1599b0c 139 debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
b7449926 140 let tcx = ecx.tcx.tcx;
dc9dc135 141 let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
b7449926 142 assert!(!layout.is_unsized());
0731742a 143 let ret = ecx.allocate(layout, MemoryKind::Stack);
b7449926 144
532ac7d7 145 let name = ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()));
b7449926
XL
146 let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
147 trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom);
dc9dc135 148 assert!(body.arg_count == 0);
b7449926
XL
149 ecx.push_stack_frame(
150 cid.instance,
dc9dc135
XL
151 body.span,
152 body,
0bf4aa26 153 Some(ret.into()),
b7449926
XL
154 StackPopCleanup::None { cleanup: false },
155 )?;
156
157 // The main interpreter loop.
158 ecx.run()?;
159
160 // Intern the result
dc9dc135
XL
161 intern_const_alloc_recursive(
162 ecx,
163 cid.instance.def_id(),
164 ret,
dc9dc135 165 )?;
b7449926
XL
166
167 debug!("eval_body_using_ecx done: {:?}", *ret);
a1dfa0c6 168 Ok(ret)
b7449926
XL
169}
170
b7449926
XL
171#[derive(Clone, Debug)]
172enum ConstEvalError {
173 NeedsRfc(String),
b7449926
XL
174}
175
416331ca
XL
176impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalError {
177 fn into(self) -> InterpErrorInfo<'tcx> {
178 err_unsup!(Unsupported(self.to_string())).into()
179 }
180}
181
b7449926 182impl fmt::Display for ConstEvalError {
9fa01778 183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
b7449926
XL
184 use self::ConstEvalError::*;
185 match *self {
186 NeedsRfc(ref msg) => {
187 write!(
188 f,
189 "\"{}\" needs an rfc before being allowed inside constants",
190 msg
191 )
192 }
b7449926
XL
193 }
194 }
195}
196
197impl Error for ConstEvalError {
198 fn description(&self) -> &str {
199 use self::ConstEvalError::*;
200 match *self {
201 NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
b7449926
XL
202 }
203 }
204
205 fn cause(&self) -> Option<&dyn Error> {
206 None
207 }
208}
209
0bf4aa26 210// Extra machine state for CTFE, and the Machine instance
dc9dc135 211pub struct CompileTimeInterpreter<'mir, 'tcx> {
0bf4aa26
XL
212 /// When this value is negative, it indicates the number of interpreter
213 /// steps *until* the loop detector is enabled. When it is positive, it is
214 /// the number of steps after the detector has been enabled modulo the loop
215 /// detector period.
216 pub(super) steps_since_detector_enabled: isize,
217
218 /// Extra state to detect loops.
dc9dc135 219 pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>,
0bf4aa26
XL
220}
221
dc9dc135 222impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
0bf4aa26
XL
223 fn new() -> Self {
224 CompileTimeInterpreter {
225 loop_detector: Default::default(),
226 steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED,
227 }
228 }
229}
230
231impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
232 #[inline(always)]
233 fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
234 where K: Borrow<Q>
235 {
236 FxHashMap::contains_key(self, k)
237 }
238
239 #[inline(always)]
240 fn insert(&mut self, k: K, v: V) -> Option<V>
241 {
242 FxHashMap::insert(self, k, v)
243 }
244
245 #[inline(always)]
246 fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
247 where K: Borrow<Q>
248 {
249 FxHashMap::remove(self, k)
250 }
251
252 #[inline(always)]
253 fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
254 self.iter()
255 .filter_map(move |(k, v)| f(k, &*v))
256 .collect()
257 }
258
259 #[inline(always)]
260 fn get_or<E>(
261 &self,
262 k: K,
263 vacant: impl FnOnce() -> Result<V, E>
264 ) -> Result<&V, E>
265 {
266 match self.get(&k) {
267 Some(v) => Ok(v),
268 None => {
269 vacant()?;
270 bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
271 }
272 }
273 }
274
275 #[inline(always)]
276 fn get_mut_or<E>(
277 &mut self,
278 k: K,
279 vacant: impl FnOnce() -> Result<V, E>
280 ) -> Result<&mut V, E>
281 {
282 match self.entry(k) {
283 Entry::Occupied(e) => Ok(e.into_mut()),
284 Entry::Vacant(e) => {
285 let v = vacant()?;
286 Ok(e.insert(v))
287 }
288 }
289 }
290}
291
dc9dc135 292crate type CompileTimeEvalContext<'mir, 'tcx> =
416331ca 293 InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
0bf4aa26
XL
294
295impl interpret::MayLeak for ! {
296 #[inline(always)]
297 fn may_leak(self) -> bool {
298 // `self` is uninhabited
299 self
300 }
301}
302
dc9dc135 303impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
b7449926 304 type MemoryKinds = !;
0bf4aa26 305 type PointerTag = ();
416331ca 306 type ExtraFnVal = !;
0bf4aa26 307
a1dfa0c6
XL
308 type FrameExtra = ();
309 type MemoryExtra = ();
310 type AllocExtra = ();
311
0bf4aa26 312 type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
b7449926 313
0bf4aa26 314 const STATIC_KIND: Option<!> = None; // no copying of statics allowed
b7449926 315
416331ca
XL
316 // We do not check for alignment to avoid having to carry an `Align`
317 // in `ConstValue::ByRef`.
318 const CHECK_ALIGN: bool = false;
319
0bf4aa26 320 #[inline(always)]
416331ca 321 fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
0bf4aa26
XL
322 false // for now, we don't enforce validity
323 }
324
325 fn find_fn(
416331ca 326 ecx: &mut InterpCx<'mir, 'tcx, Self>,
b7449926
XL
327 instance: ty::Instance<'tcx>,
328 args: &[OpTy<'tcx>],
329 dest: Option<PlaceTy<'tcx>>,
330 ret: Option<mir::BasicBlock>,
dc9dc135 331 ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
b7449926 332 debug!("eval_fn_call: {:?}", instance);
9fa01778
XL
333 // Only check non-glue functions
334 if let ty::InstanceDef::Item(def_id) = instance.def {
416331ca 335 // Execution might have wandered off into other crates, so we cannot do a stability-
9fa01778
XL
336 // sensitive check here. But we can at least rule out functions that are not const
337 // at all.
338 if !ecx.tcx.is_const_fn_raw(def_id) {
339 // Some functions we support even if they are non-const -- but avoid testing
340 // that for const fn! We certainly do *not* want to actually call the fn
341 // though, so be sure we return here.
342 return if ecx.hook_fn(instance, args, dest)? {
343 ecx.goto_block(ret)?; // fully evaluated and done
344 Ok(None)
345 } else {
416331ca 346 throw_unsup_format!("calling non-const function `{}`", instance)
9fa01778
XL
347 };
348 }
b7449926
XL
349 }
350 // This is a const fn. Call it.
e1599b0c 351 Ok(Some(match ecx.load_mir(instance.def, None) {
dc9dc135 352 Ok(body) => body,
b7449926 353 Err(err) => {
416331ca 354 if let err_unsup!(NoMirFor(ref path)) = err.kind {
b7449926
XL
355 return Err(
356 ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
357 .into(),
358 );
359 }
360 return Err(err);
361 }
362 }))
363 }
364
416331ca
XL
365 fn call_extra_fn(
366 _ecx: &mut InterpCx<'mir, 'tcx, Self>,
367 fn_val: !,
368 _args: &[OpTy<'tcx>],
369 _dest: Option<PlaceTy<'tcx>>,
370 _ret: Option<mir::BasicBlock>,
371 ) -> InterpResult<'tcx> {
372 match fn_val {}
373 }
374
0bf4aa26 375 fn call_intrinsic(
416331ca 376 ecx: &mut InterpCx<'mir, 'tcx, Self>,
b7449926
XL
377 instance: ty::Instance<'tcx>,
378 args: &[OpTy<'tcx>],
379 dest: PlaceTy<'tcx>,
dc9dc135 380 ) -> InterpResult<'tcx> {
b7449926
XL
381 if ecx.emulate_intrinsic(instance, args, dest)? {
382 return Ok(());
383 }
384 // An intrinsic that we do not support
e1599b0c 385 let intrinsic_name = ecx.tcx.item_name(instance.def_id());
b7449926
XL
386 Err(
387 ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()
388 )
389 }
390
416331ca
XL
391 fn ptr_to_int(
392 _mem: &Memory<'mir, 'tcx, Self>,
393 _ptr: Pointer,
394 ) -> InterpResult<'tcx, u64> {
395 Err(
396 ConstEvalError::NeedsRfc("pointer-to-integer cast".to_string()).into(),
397 )
398 }
399
400 fn binary_ptr_op(
401 _ecx: &InterpCx<'mir, 'tcx, Self>,
b7449926 402 _bin_op: mir::BinOp,
9fa01778
XL
403 _left: ImmTy<'tcx>,
404 _right: ImmTy<'tcx>,
e1599b0c 405 ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
b7449926
XL
406 Err(
407 ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
408 )
409 }
410
0bf4aa26 411 fn find_foreign_static(
416331ca 412 _tcx: TyCtxt<'tcx>,
b7449926 413 _def_id: DefId,
dc9dc135 414 ) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
416331ca 415 throw_unsup!(ReadForeignStatic)
b7449926
XL
416 }
417
0bf4aa26 418 #[inline(always)]
dc9dc135 419 fn tag_allocation<'b>(
416331ca 420 _memory_extra: &(),
dc9dc135
XL
421 _id: AllocId,
422 alloc: Cow<'b, Allocation>,
423 _kind: Option<MemoryKind<!>>,
dc9dc135
XL
424 ) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
425 // We do not use a tag so we can just cheaply forward the allocation
426 (alloc, ())
0bf4aa26
XL
427 }
428
48663c56 429 #[inline(always)]
dc9dc135 430 fn tag_static_base_pointer(
416331ca 431 _memory_extra: &(),
dc9dc135 432 _id: AllocId,
dc9dc135
XL
433 ) -> Self::PointerTag {
434 ()
48663c56
XL
435 }
436
0bf4aa26 437 fn box_alloc(
416331ca 438 _ecx: &mut InterpCx<'mir, 'tcx, Self>,
b7449926 439 _dest: PlaceTy<'tcx>,
dc9dc135 440 ) -> InterpResult<'tcx> {
b7449926
XL
441 Err(
442 ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
443 )
444 }
0bf4aa26 445
416331ca 446 fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
0bf4aa26
XL
447 {
448 let steps = &mut ecx.machine.steps_since_detector_enabled;
449
450 *steps += 1;
451 if *steps < 0 {
452 return Ok(());
453 }
454
455 *steps %= DETECTOR_SNAPSHOT_PERIOD;
456 if *steps != 0 {
457 return Ok(());
458 }
459 }
460
461 let span = ecx.frame().span;
462 ecx.machine.loop_detector.observe_and_analyze(
48663c56 463 *ecx.tcx,
0bf4aa26
XL
464 span,
465 &ecx.memory,
466 &ecx.stack[..],
467 )
468 }
469
a1dfa0c6 470 #[inline(always)]
416331ca 471 fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
0bf4aa26
XL
472 Ok(())
473 }
474
9fa01778 475 /// Called immediately before a stack frame gets popped.
0bf4aa26 476 #[inline(always)]
416331ca 477 fn stack_pop(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _extra: ()) -> InterpResult<'tcx> {
0bf4aa26
XL
478 Ok(())
479 }
b7449926
XL
480}
481
dc9dc135 482/// Extracts a field of a (variant of a) const.
532ac7d7
XL
483// this function uses `unwrap` copiously, because an already validated constant must have valid
484// fields and can thus never fail outside of compiler bugs
dc9dc135
XL
485pub fn const_field<'tcx>(
486 tcx: TyCtxt<'tcx>,
b7449926 487 param_env: ty::ParamEnv<'tcx>,
a1dfa0c6 488 variant: Option<VariantIdx>,
b7449926 489 field: mir::Field,
dc9dc135
XL
490 value: &'tcx ty::Const<'tcx>,
491) -> &'tcx ty::Const<'tcx> {
9fa01778
XL
492 trace!("const_field: {:?}, {:?}", field, value);
493 let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
532ac7d7
XL
494 // get the operand again
495 let op = ecx.eval_const_to_op(value, None).unwrap();
496 // downcast
497 let down = match variant {
498 None => op,
499 Some(variant) => ecx.operand_downcast(op, variant).unwrap(),
500 };
501 // then project
502 let field = ecx.operand_field(down, field.index() as u64).unwrap();
503 // and finally move back to the const world, always normalizing because
504 // this is not called for statics.
505 op_to_const(&ecx, field)
b7449926
XL
506}
507
532ac7d7
XL
508// this function uses `unwrap` copiously, because an already validated constant must have valid
509// fields and can thus never fail outside of compiler bugs
dc9dc135
XL
510pub fn const_variant_index<'tcx>(
511 tcx: TyCtxt<'tcx>,
b7449926 512 param_env: ty::ParamEnv<'tcx>,
dc9dc135 513 val: &'tcx ty::Const<'tcx>,
532ac7d7 514) -> VariantIdx {
9fa01778
XL
515 trace!("const_variant_index: {:?}", val);
516 let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
532ac7d7
XL
517 let op = ecx.eval_const_to_op(val, None).unwrap();
518 ecx.read_discriminant(op).unwrap().1
b7449926
XL
519}
520
e1599b0c
XL
521/// Turn an interpreter error into something to report to the user.
522/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
523/// Should be called only if the error is actually going to to be reported!
dc9dc135 524pub fn error_to_const_error<'mir, 'tcx>(
416331ca 525 ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
dc9dc135 526 mut error: InterpErrorInfo<'tcx>,
a1dfa0c6
XL
527) -> ConstEvalErr<'tcx> {
528 error.print_backtrace();
529 let stacktrace = ecx.generate_stacktrace(None);
530 ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span }
531}
532
e1599b0c
XL
533pub fn note_on_undefined_behavior_error() -> &'static str {
534 "The rules on what exactly is undefined behavior aren't clear, \
535 so this check might be overzealous. Please open an issue on the rustc \
536 repository if you believe it should not be considered undefined behavior."
537}
538
dc9dc135
XL
539fn validate_and_turn_into_const<'tcx>(
540 tcx: TyCtxt<'tcx>,
a1dfa0c6
XL
541 constant: RawConst<'tcx>,
542 key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
543) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
544 let cid = key.value;
9fa01778 545 let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env);
a1dfa0c6 546 let val = (|| {
9fa01778
XL
547 let mplace = ecx.raw_const_to_mplace(constant)?;
548 let mut ref_tracking = RefTracking::new(mplace);
549 while let Some((mplace, path)) = ref_tracking.todo.pop() {
a1dfa0c6 550 ecx.validate_operand(
9fa01778 551 mplace.into(),
a1dfa0c6
XL
552 path,
553 Some(&mut ref_tracking),
a1dfa0c6
XL
554 )?;
555 }
9fa01778 556 // Now that we validated, turn this into a proper constant.
dc9dc135
XL
557 // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
558 // whether they become immediates.
a1dfa0c6 559 let def_id = cid.instance.def.def_id();
48663c56 560 if tcx.is_static(def_id) || cid.promoted.is_some() {
dc9dc135
XL
561 let ptr = mplace.ptr.to_ptr()?;
562 Ok(tcx.mk_const(ty::Const {
563 val: ConstValue::ByRef {
dc9dc135 564 alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
416331ca 565 offset: ptr.offset,
dc9dc135
XL
566 },
567 ty: mplace.layout.ty,
568 }))
9fa01778 569 } else {
532ac7d7 570 Ok(op_to_const(&ecx, mplace.into()))
9fa01778 571 }
a1dfa0c6
XL
572 })();
573
574 val.map_err(|error| {
575 let err = error_to_const_error(&ecx, error);
576 match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
577 Ok(mut diag) => {
e1599b0c 578 diag.note(note_on_undefined_behavior_error());
a1dfa0c6
XL
579 diag.emit();
580 ErrorHandled::Reported
581 }
582 Err(err) => err,
583 }
584 })
b7449926
XL
585}
586
dc9dc135
XL
587pub fn const_eval_provider<'tcx>(
588 tcx: TyCtxt<'tcx>,
b7449926
XL
589 key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
590) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
e1599b0c 591 // see comment in const_eval_raw_provider for what we're doing here
a1dfa0c6
XL
592 if key.param_env.reveal == Reveal::All {
593 let mut key = key.clone();
594 key.param_env.reveal = Reveal::UserFacing;
595 match tcx.const_eval(key) {
596 // try again with reveal all as requested
597 Err(ErrorHandled::TooGeneric) => {
598 // Promoteds should never be "too generic" when getting evaluated.
599 // They either don't get evaluated, or we are in a monomorphic context
600 assert!(key.value.promoted.is_none());
601 },
602 // dedupliate calls
603 other => return other,
604 }
605 }
e1599b0c
XL
606
607 // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
608 // Catch such calls and evaluate them instead of trying to load a constant's MIR.
609 if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
610 let ty = key.value.instance.ty(tcx);
611 let substs = match ty.sty {
612 ty::FnDef(_, substs) => substs,
613 _ => bug!("intrinsic with type {:?}", ty),
614 };
615 return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs)
616 .map_err(|error| {
617 let span = tcx.def_span(def_id);
618 let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
619 error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
620 })
621 }
622
a1dfa0c6
XL
623 tcx.const_eval_raw(key).and_then(|val| {
624 validate_and_turn_into_const(tcx, val, key)
625 })
626}
627
dc9dc135
XL
628pub fn const_eval_raw_provider<'tcx>(
629 tcx: TyCtxt<'tcx>,
a1dfa0c6
XL
630 key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
631) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> {
632 // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
633 // reporting the same error twice here. To resolve this, we check whether we can evaluate the
634 // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
635 // computed. For a large percentage of constants that will already have succeeded. Only
636 // associated constants of generic functions will fail due to not enough monomorphization
637 // information being available.
638
639 // In case we fail in the `UserFacing` variant, we just do the real computation.
640 if key.param_env.reveal == Reveal::All {
641 let mut key = key.clone();
642 key.param_env.reveal = Reveal::UserFacing;
643 match tcx.const_eval_raw(key) {
644 // try again with reveal all as requested
645 Err(ErrorHandled::TooGeneric) => {},
646 // dedupliate calls
647 other => return other,
648 }
649 }
532ac7d7
XL
650 if cfg!(debug_assertions) {
651 // Make sure we format the instance even if we do not print it.
652 // This serves as a regression test against an ICE on printing.
653 // The next two lines concatenated contain some discussion:
654 // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
655 // subject/anon_const_instance_printing/near/135980032
656 let instance = key.value.instance.to_string();
657 trace!("const eval: {:?} ({})", key, instance);
658 }
a1dfa0c6 659
b7449926
XL
660 let cid = key.value;
661 let def_id = cid.instance.def.def_id();
662
48663c56
XL
663 if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors {
664 return Err(ErrorHandled::Reported);
665 }
b7449926 666
48663c56 667 let span = tcx.def_span(cid.instance.def_id());
416331ca
XL
668 let mut ecx = InterpCx::new(
669 tcx.at(span),
670 key.param_env,
671 CompileTimeInterpreter::new(),
672 Default::default()
673 );
b7449926 674
e1599b0c
XL
675 let res = ecx.load_mir(cid.instance.def, cid.promoted);
676 res.and_then(
677 |body| eval_body_using_ecx(&mut ecx, cid, body)
48663c56 678 ).and_then(|place| {
a1dfa0c6 679 Ok(RawConst {
416331ca 680 alloc_id: place.ptr.assert_ptr().alloc_id,
a1dfa0c6
XL
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
48663c56 686 if tcx.is_static(def_id) {
0731742a
XL
687 // Ensure that if the above error was either `TooGeneric` or `Reported`
688 // an error must be reported.
dc9dc135
XL
689 let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer");
690 tcx.sess.delay_span_bug(
691 err.span,
692 &format!("static eval failure did not emit an error: {:#?}", v)
693 );
694 v
a1dfa0c6
XL
695 } else if def_id.is_local() {
696 // constant defined in this crate, we can figure out a lint level!
48663c56 697 match tcx.def_kind(def_id) {
a1dfa0c6
XL
698 // constants never produce a hard error at the definition site. Anything else is
699 // a backwards compatibility hazard (and will break old versions of winapi for sure)
700 //
701 // note that validation may still cause a hard error on this very same constant,
702 // because any code that existed before validation could not have failed validation
703 // thus preventing such a hard error from being a backwards compatibility hazard
dc9dc135 704 Some(DefKind::Const) | Some(DefKind::AssocConst) => {
532ac7d7 705 let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
a1dfa0c6
XL
706 err.report_as_lint(
707 tcx.at(tcx.def_span(def_id)),
708 "any use of this value will cause an error",
532ac7d7
XL
709 hir_id,
710 Some(err.span),
a1dfa0c6
XL
711 )
712 },
713 // promoting runtime code is only allowed to error if it references broken constants
714 // any other kind of error will be reported to the user as a deny-by-default lint
715 _ => if let Some(p) = cid.promoted {
416331ca
XL
716 let span = tcx.promoted_mir(def_id)[p].span;
717 if let err_inval!(ReferencedConstant) = err.error {
a1dfa0c6
XL
718 err.report_as_error(
719 tcx.at(span),
720 "evaluation of constant expression failed",
721 )
722 } else {
723 err.report_as_lint(
724 tcx.at(span),
725 "reaching this expression at runtime will panic or abort",
532ac7d7
XL
726 tcx.hir().as_local_hir_id(def_id).unwrap(),
727 Some(err.span),
a1dfa0c6
XL
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 },
b7449926 738 }
a1dfa0c6
XL
739 } else {
740 // use of broken constant from other crate
741 err.report_as_error(ecx.tcx, "could not evaluate constant")
b7449926 742 }
b7449926
XL
743 })
744}