]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/qualify_consts.rs
Create fewer basic blocks in match MIR lowering
[rust.git] / src / librustc_mir / transform / qualify_consts.rs
1 //! A pass that qualifies constness of temporaries in constants,
2 //! static initializers and functions and also drives promotion.
3 //!
4 //! The Qualif flags below can be used to also provide better
5 //! diagnostics as to why a constant rvalue wasn't promoted.
6
7 use rustc_data_structures::bit_set::BitSet;
8 use rustc_data_structures::indexed_vec::IndexVec;
9 use rustc_data_structures::fx::FxHashSet;
10 use rustc_target::spec::abi::Abi;
11 use rustc::hir;
12 use rustc::hir::def_id::DefId;
13 use rustc::traits::{self, TraitEngine};
14 use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
15 use rustc::ty::cast::CastTy;
16 use rustc::ty::query::Providers;
17 use rustc::mir::*;
18 use rustc::mir::interpret::ConstValue;
19 use rustc::mir::traversal::ReversePostorder;
20 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
21 use rustc::middle::lang_items;
22 use rustc::session::config::nightly_options;
23 use syntax::ast::LitKind;
24 use syntax::feature_gate::{emit_feature_err, GateIssue};
25 use syntax::symbol::sym;
26 use syntax_pos::{Span, DUMMY_SP};
27
28 use std::fmt;
29 use std::ops::{Deref, Index, IndexMut};
30 use std::usize;
31
32 use crate::transform::{MirPass, MirSource};
33 use super::promote_consts::{self, Candidate, TempState};
34
35 /// What kind of item we are in.
36 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
37 enum Mode {
38     /// A `static` item.
39     Static,
40     /// A `static mut` item.
41     StaticMut,
42     /// A `const fn` item.
43     ConstFn,
44     /// A `const` item or an anonymous constant (e.g. in array lengths).
45     Const,
46     /// Other type of `fn`.
47     NonConstFn,
48 }
49
50 impl Mode {
51     /// Determine whether we have to do full const-checking because syntactically, we
52     /// are required to be "const".
53     #[inline]
54     fn requires_const_checking(self) -> bool {
55         self != Mode::NonConstFn
56     }
57 }
58
59 impl fmt::Display for Mode {
60     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61         match *self {
62             Mode::Const => write!(f, "constant"),
63             Mode::Static | Mode::StaticMut => write!(f, "static"),
64             Mode::ConstFn => write!(f, "constant function"),
65             Mode::NonConstFn => write!(f, "function")
66         }
67     }
68 }
69
70 const QUALIF_COUNT: usize = 4;
71
72 // FIXME(eddyb) once we can use const generics, replace this array with
73 // something like `IndexVec` but for fixed-size arrays (`IndexArray`?).
74 #[derive(Copy, Clone, Default)]
75 struct PerQualif<T>([T; QUALIF_COUNT]);
76
77 impl<T: Clone> PerQualif<T> {
78     fn new(x: T) -> Self {
79         PerQualif([x.clone(), x.clone(), x.clone(), x])
80     }
81 }
82
83 impl<T> PerQualif<T> {
84     fn as_mut(&mut self) -> PerQualif<&mut T> {
85         let [x0, x1, x2, x3] = &mut self.0;
86         PerQualif([x0, x1, x2, x3])
87     }
88
89     fn zip<U>(self, other: PerQualif<U>) -> PerQualif<(T, U)> {
90         let [x0, x1, x2, x3] = self.0;
91         let [y0, y1, y2, y3] = other.0;
92         PerQualif([(x0, y0), (x1, y1), (x2, y2), (x3, y3)])
93     }
94 }
95
96 impl PerQualif<bool> {
97     fn encode_to_bits(self) -> u8 {
98         self.0.iter().enumerate().fold(0, |bits, (i, &qualif)| {
99             bits | ((qualif as u8) << i)
100         })
101     }
102
103     fn decode_from_bits(bits: u8) -> Self {
104         let mut qualifs = Self::default();
105         for (i, qualif) in qualifs.0.iter_mut().enumerate() {
106             *qualif = (bits & (1 << i)) != 0;
107         }
108         qualifs
109     }
110 }
111
112 impl<Q: Qualif, T> Index<Q> for PerQualif<T> {
113     type Output = T;
114
115     fn index(&self, _: Q) -> &T {
116         &self.0[Q::IDX]
117     }
118 }
119
120 impl<Q: Qualif, T> IndexMut<Q> for PerQualif<T> {
121     fn index_mut(&mut self, _: Q) -> &mut T {
122         &mut self.0[Q::IDX]
123     }
124 }
125
126 struct ConstCx<'a, 'tcx> {
127     tcx: TyCtxt<'tcx, 'tcx>,
128     param_env: ty::ParamEnv<'tcx>,
129     mode: Mode,
130     body: &'a Body<'tcx>,
131
132     per_local: PerQualif<BitSet<Local>>,
133 }
134
135 impl<'a, 'tcx> ConstCx<'a, 'tcx> {
136     fn is_const_panic_fn(&self, def_id: DefId) -> bool {
137         Some(def_id) == self.tcx.lang_items().panic_fn() ||
138         Some(def_id) == self.tcx.lang_items().begin_panic_fn()
139     }
140 }
141
142 #[derive(Copy, Clone, Debug)]
143 enum ValueSource<'a, 'tcx> {
144     Rvalue(&'a Rvalue<'tcx>),
145     Call {
146         callee: &'a Operand<'tcx>,
147         args: &'a [Operand<'tcx>],
148         return_ty: Ty<'tcx>,
149     },
150 }
151
152 /// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some
153 /// code for promotion or prevent it from evaluating at compile time. So `return true` means
154 /// "I found something bad, no reason to go on searching". `false` is only returned if we
155 /// definitely cannot find anything bad anywhere.
156 ///
157 /// The default implementations proceed structurally.
158 trait Qualif {
159     const IDX: usize;
160
161     /// Return the qualification that is (conservatively) correct for any value
162     /// of the type, or `None` if the qualification is not value/type-based.
163     fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> Option<bool> {
164         None
165     }
166
167     /// Return a mask for the qualification, given a type. This is `false` iff
168     /// no value of that type can have the qualification.
169     fn mask_for_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
170         Self::in_any_value_of_ty(cx, ty).unwrap_or(true)
171     }
172
173     fn in_local(cx: &ConstCx<'_, '_>, local: Local) -> bool {
174         cx.per_local.0[Self::IDX].contains(local)
175     }
176
177     fn in_static(_cx: &ConstCx<'_, 'tcx>, _static: &Static<'tcx>) -> bool {
178         // FIXME(eddyb) should we do anything here for value properties?
179         false
180     }
181
182     fn in_projection_structurally(
183         cx: &ConstCx<'_, 'tcx>,
184         proj: &Projection<'tcx>,
185     ) -> bool {
186         let base_qualif = Self::in_place(cx, &proj.base);
187         let qualif = base_qualif && Self::mask_for_ty(
188             cx,
189             proj.base.ty(cx.body, cx.tcx)
190                 .projection_ty(cx.tcx, &proj.elem)
191                 .ty,
192         );
193         match proj.elem {
194             ProjectionElem::Deref |
195             ProjectionElem::Subslice { .. } |
196             ProjectionElem::Field(..) |
197             ProjectionElem::ConstantIndex { .. } |
198             ProjectionElem::Downcast(..) => qualif,
199
200             ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
201         }
202     }
203
204     fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool {
205         Self::in_projection_structurally(cx, proj)
206     }
207
208     fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
209         match *place {
210             Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
211             Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) =>
212                 bug!("qualifying already promoted MIR"),
213             Place::Base(PlaceBase::Static(ref static_)) => {
214                 Self::in_static(cx, static_)
215             },
216             Place::Projection(ref proj) => Self::in_projection(cx, proj),
217         }
218     }
219
220     fn in_operand(cx: &ConstCx<'_, 'tcx>, operand: &Operand<'tcx>) -> bool {
221         match *operand {
222             Operand::Copy(ref place) |
223             Operand::Move(ref place) => Self::in_place(cx, place),
224
225             Operand::Constant(ref constant) => {
226                 if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
227                     // Don't peek inside trait associated constants.
228                     if cx.tcx.trait_of_item(def_id).is_some() {
229                         Self::in_any_value_of_ty(cx, constant.ty).unwrap_or(false)
230                     } else {
231                         let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id);
232
233                         let qualif = PerQualif::decode_from_bits(bits).0[Self::IDX];
234
235                         // Just in case the type is more specific than
236                         // the definition, e.g., impl associated const
237                         // with type parameters, take it into account.
238                         qualif && Self::mask_for_ty(cx, constant.ty)
239                     }
240                 } else {
241                     false
242                 }
243             }
244         }
245     }
246
247     fn in_rvalue_structurally(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
248         match *rvalue {
249             Rvalue::NullaryOp(..) => false,
250
251             Rvalue::Discriminant(ref place) |
252             Rvalue::Len(ref place) => Self::in_place(cx, place),
253
254             Rvalue::Use(ref operand) |
255             Rvalue::Repeat(ref operand, _) |
256             Rvalue::UnaryOp(_, ref operand) |
257             Rvalue::Cast(_, ref operand, _) => Self::in_operand(cx, operand),
258
259             Rvalue::BinaryOp(_, ref lhs, ref rhs) |
260             Rvalue::CheckedBinaryOp(_, ref lhs, ref rhs) => {
261                 Self::in_operand(cx, lhs) || Self::in_operand(cx, rhs)
262             }
263
264             Rvalue::Ref(_, _, ref place) => {
265                 // Special-case reborrows to be more like a copy of the reference.
266                 if let Place::Projection(ref proj) = *place {
267                     if let ProjectionElem::Deref = proj.elem {
268                         let base_ty = proj.base.ty(cx.body, cx.tcx).ty;
269                         if let ty::Ref(..) = base_ty.sty {
270                             return Self::in_place(cx, &proj.base);
271                         }
272                     }
273                 }
274
275                 Self::in_place(cx, place)
276             }
277
278             Rvalue::Aggregate(_, ref operands) => {
279                 operands.iter().any(|o| Self::in_operand(cx, o))
280             }
281         }
282     }
283
284     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
285         Self::in_rvalue_structurally(cx, rvalue)
286     }
287
288     fn in_call(
289         cx: &ConstCx<'_, 'tcx>,
290         _callee: &Operand<'tcx>,
291         _args: &[Operand<'tcx>],
292         return_ty: Ty<'tcx>,
293     ) -> bool {
294         // Be conservative about the returned value of a const fn.
295         Self::in_any_value_of_ty(cx, return_ty).unwrap_or(false)
296     }
297
298     fn in_value(cx: &ConstCx<'_, 'tcx>, source: ValueSource<'_, 'tcx>) -> bool {
299         match source {
300             ValueSource::Rvalue(rvalue) => Self::in_rvalue(cx, rvalue),
301             ValueSource::Call { callee, args, return_ty } => {
302                 Self::in_call(cx, callee, args, return_ty)
303             }
304         }
305     }
306 }
307
308 /// Constant containing interior mutability (`UnsafeCell<T>`).
309 /// This must be ruled out to make sure that evaluating the constant at compile-time
310 /// and at *any point* during the run-time would produce the same result. In particular,
311 /// promotion of temporaries must not change program behavior; if the promoted could be
312 /// written to, that would be a problem.
313 struct HasMutInterior;
314
315 impl Qualif for HasMutInterior {
316     const IDX: usize = 0;
317
318     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<bool> {
319         Some(!ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP))
320     }
321
322     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
323         match *rvalue {
324             // Returning `true` for `Rvalue::Ref` indicates the borrow isn't
325             // allowed in constants (and the `Checker` will error), and/or it
326             // won't be promoted, due to `&mut ...` or interior mutability.
327             Rvalue::Ref(_, kind, ref place) => {
328                 let ty = place.ty(cx.body, cx.tcx).ty;
329
330                 if let BorrowKind::Mut { .. } = kind {
331                     // In theory, any zero-sized value could be borrowed
332                     // mutably without consequences. However, only &mut []
333                     // is allowed right now, and only in functions.
334                     if cx.mode == Mode::StaticMut {
335                         // Inside a `static mut`, &mut [...] is also allowed.
336                         match ty.sty {
337                             ty::Array(..) | ty::Slice(_) => {}
338                             _ => return true,
339                         }
340                     } else if let ty::Array(_, len) = ty.sty {
341                         // FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition
342                         // seems unnecessary, given that this is merely a ZST.
343                         match len.assert_usize(cx.tcx) {
344                             Some(0) if cx.mode == Mode::NonConstFn => {},
345                             _ => return true,
346                         }
347                     } else {
348                         return true;
349                     }
350                 }
351             }
352
353             Rvalue::Aggregate(ref kind, _) => {
354                 if let AggregateKind::Adt(def, ..) = **kind {
355                     if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() {
356                         let ty = rvalue.ty(cx.body, cx.tcx);
357                         assert_eq!(Self::in_any_value_of_ty(cx, ty), Some(true));
358                         return true;
359                     }
360                 }
361             }
362
363             _ => {}
364         }
365
366         Self::in_rvalue_structurally(cx, rvalue)
367     }
368 }
369
370 /// Constant containing an ADT that implements `Drop`.
371 /// This must be ruled out (a) because we cannot run `Drop` during compile-time
372 /// as that might not be a `const fn`, and (b) because implicit promotion would
373 /// remove side-effects that occur as part of dropping that value.
374 struct NeedsDrop;
375
376 impl Qualif for NeedsDrop {
377     const IDX: usize = 1;
378
379     fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<bool> {
380         Some(ty.needs_drop(cx.tcx, cx.param_env))
381     }
382
383     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
384         if let Rvalue::Aggregate(ref kind, _) = *rvalue {
385             if let AggregateKind::Adt(def, ..) = **kind {
386                 if def.has_dtor(cx.tcx) {
387                     return true;
388                 }
389             }
390         }
391
392         Self::in_rvalue_structurally(cx, rvalue)
393     }
394 }
395
396 /// Not promotable at all - non-`const fn` calls, `asm!`,
397 /// pointer comparisons, ptr-to-int casts, etc.
398 /// Inside a const context all constness rules apply, so promotion simply has to follow the regular
399 /// constant rules (modulo interior mutability or `Drop` rules which are handled `HasMutInterior`
400 /// and `NeedsDrop` respectively). Basically this duplicates the checks that the const-checking
401 /// visitor enforces by emitting errors when working in const context.
402 struct IsNotPromotable;
403
404 impl Qualif for IsNotPromotable {
405     const IDX: usize = 2;
406
407     fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool {
408         match static_.kind {
409             StaticKind::Promoted(_) => unreachable!(),
410             StaticKind::Static(def_id) => {
411                 // Only allow statics (not consts) to refer to other statics.
412                 let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut;
413
414                 !allowed ||
415                     cx.tcx.get_attrs(def_id).iter().any(
416                         |attr| attr.check_name(sym::thread_local)
417                     )
418             }
419         }
420     }
421
422     fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool {
423         match proj.elem {
424             ProjectionElem::Deref |
425             ProjectionElem::Downcast(..) => return true,
426
427             ProjectionElem::ConstantIndex {..} |
428             ProjectionElem::Subslice {..} |
429             ProjectionElem::Index(_) => {}
430
431             ProjectionElem::Field(..) => {
432                 if cx.mode == Mode::NonConstFn {
433                     let base_ty = proj.base.ty(cx.body, cx.tcx).ty;
434                     if let Some(def) = base_ty.ty_adt_def() {
435                         // No promotion of union field accesses.
436                         if def.is_union() {
437                             return true;
438                         }
439                     }
440                 }
441             }
442         }
443
444         Self::in_projection_structurally(cx, proj)
445     }
446
447     fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
448         match *rvalue {
449             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::NonConstFn => {
450                 let operand_ty = operand.ty(cx.body, cx.tcx);
451                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
452                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
453                 match (cast_in, cast_out) {
454                     (CastTy::Ptr(_), CastTy::Int(_)) |
455                     (CastTy::FnPtr, CastTy::Int(_)) => {
456                         // in normal functions, mark such casts as not promotable
457                         return true;
458                     }
459                     _ => {}
460                 }
461             }
462
463             Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::NonConstFn => {
464                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.body, cx.tcx).sty {
465                     assert!(op == BinOp::Eq || op == BinOp::Ne ||
466                             op == BinOp::Le || op == BinOp::Lt ||
467                             op == BinOp::Ge || op == BinOp::Gt ||
468                             op == BinOp::Offset);
469
470                     // raw pointer operations are not allowed inside promoteds
471                     return true;
472                 }
473             }
474
475             Rvalue::NullaryOp(NullOp::Box, _) => return true,
476
477             _ => {}
478         }
479
480         Self::in_rvalue_structurally(cx, rvalue)
481     }
482
483     fn in_call(
484         cx: &ConstCx<'_, 'tcx>,
485         callee: &Operand<'tcx>,
486         args: &[Operand<'tcx>],
487         _return_ty: Ty<'tcx>,
488     ) -> bool {
489         let fn_ty = callee.ty(cx.body, cx.tcx);
490         match fn_ty.sty {
491             ty::FnDef(def_id, _) => {
492                 match cx.tcx.fn_sig(def_id).abi() {
493                     Abi::RustIntrinsic |
494                     Abi::PlatformIntrinsic => {
495                         assert!(!cx.tcx.is_const_fn(def_id));
496                         match &cx.tcx.item_name(def_id).as_str()[..] {
497                             | "size_of"
498                             | "min_align_of"
499                             | "needs_drop"
500                             | "type_id"
501                             | "bswap"
502                             | "bitreverse"
503                             | "ctpop"
504                             | "cttz"
505                             | "cttz_nonzero"
506                             | "ctlz"
507                             | "ctlz_nonzero"
508                             | "overflowing_add"
509                             | "overflowing_sub"
510                             | "overflowing_mul"
511                             | "unchecked_shl"
512                             | "unchecked_shr"
513                             | "rotate_left"
514                             | "rotate_right"
515                             | "add_with_overflow"
516                             | "sub_with_overflow"
517                             | "mul_with_overflow"
518                             | "saturating_add"
519                             | "saturating_sub"
520                             | "transmute"
521                             => return true,
522
523                             _ => {}
524                         }
525                     }
526                     _ => {
527                         let is_const_fn =
528                             cx.tcx.is_const_fn(def_id) ||
529                             cx.tcx.is_unstable_const_fn(def_id).is_some() ||
530                             cx.is_const_panic_fn(def_id);
531                         if !is_const_fn {
532                             return true;
533                         }
534                     }
535                 }
536             }
537             _ => return true,
538         }
539
540         Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
541     }
542 }
543
544 /// Refers to temporaries which cannot be promoted *implicitly*.
545 /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`.
546 /// Implicit promotion has almost the same rules, except that disallows `const fn` except for
547 /// those marked `#[rustc_promotable]`. This is to avoid changing a legitimate run-time operation
548 /// into a failing compile-time operation e.g. due to addresses being compared inside the function.
549 struct IsNotImplicitlyPromotable;
550
551 impl Qualif for IsNotImplicitlyPromotable {
552     const IDX: usize = 3;
553
554     fn in_call(
555         cx: &ConstCx<'_, 'tcx>,
556         callee: &Operand<'tcx>,
557         args: &[Operand<'tcx>],
558         _return_ty: Ty<'tcx>,
559     ) -> bool {
560         if cx.mode == Mode::NonConstFn {
561             if let ty::FnDef(def_id, _) = callee.ty(cx.body, cx.tcx).sty {
562                 // Never promote runtime `const fn` calls of
563                 // functions without `#[rustc_promotable]`.
564                 if !cx.tcx.is_promotable_const_fn(def_id) {
565                     return true;
566                 }
567             }
568         }
569
570         Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
571     }
572 }
573
574 // Ensure the `IDX` values are sequential (`0..QUALIF_COUNT`).
575 macro_rules! static_assert_seq_qualifs {
576     ($i:expr => $first:ident $(, $rest:ident)*) => {
577         static_assert!({
578             static_assert_seq_qualifs!($i + 1 => $($rest),*);
579
580             $first::IDX == $i
581         });
582     };
583     ($i:expr =>) => {
584         static_assert!(QUALIF_COUNT == $i);
585     };
586 }
587 static_assert_seq_qualifs!(
588     0 => HasMutInterior, NeedsDrop, IsNotPromotable, IsNotImplicitlyPromotable
589 );
590
591 impl ConstCx<'_, 'tcx> {
592     fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif<bool> {
593         let mut qualifs = PerQualif::default();
594         qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false);
595         qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false);
596         qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
597         qualifs[IsNotImplicitlyPromotable] =
598             IsNotImplicitlyPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
599         qualifs
600     }
601
602     fn qualifs_in_local(&self, local: Local) -> PerQualif<bool> {
603         let mut qualifs = PerQualif::default();
604         qualifs[HasMutInterior] = HasMutInterior::in_local(self, local);
605         qualifs[NeedsDrop] = NeedsDrop::in_local(self, local);
606         qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local);
607         qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_local(self, local);
608         qualifs
609     }
610
611     fn qualifs_in_value(&self, source: ValueSource<'_, 'tcx>) -> PerQualif<bool> {
612         let mut qualifs = PerQualif::default();
613         qualifs[HasMutInterior] = HasMutInterior::in_value(self, source);
614         qualifs[NeedsDrop] = NeedsDrop::in_value(self, source);
615         qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source);
616         qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_value(self, source);
617         qualifs
618     }
619 }
620
621 /// Checks MIR for being admissible as a compile-time constant, using `ConstCx`
622 /// for value qualifications, and accumulates writes of
623 /// rvalue/call results to locals, in `local_qualif`.
624 /// It also records candidates for promotion in `promotion_candidates`,
625 /// both in functions and const/static items.
626 struct Checker<'a, 'tcx> {
627     cx: ConstCx<'a, 'tcx>,
628
629     span: Span,
630     def_id: DefId,
631     rpo: ReversePostorder<'a, 'tcx>,
632
633     temp_promotion_state: IndexVec<Local, TempState>,
634     promotion_candidates: Vec<Candidate>,
635 }
636
637 macro_rules! unleash_miri {
638     ($this:expr) => {{
639         if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
640             $this.tcx.sess.span_warn($this.span, "skipping const checks");
641             return;
642         }
643     }}
644 }
645
646 impl Deref for Checker<'a, 'tcx> {
647     type Target = ConstCx<'a, 'tcx>;
648
649     fn deref(&self) -> &Self::Target {
650         &self.cx
651     }
652 }
653
654 impl<'a, 'tcx> Checker<'a, 'tcx> {
655     fn new(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId, body: &'a Body<'tcx>, mode: Mode) -> Self {
656         assert!(def_id.is_local());
657         let mut rpo = traversal::reverse_postorder(body);
658         let temps = promote_consts::collect_temps(body, &mut rpo);
659         rpo.reset();
660
661         let param_env = tcx.param_env(def_id);
662
663         let mut cx = ConstCx {
664             tcx,
665             param_env,
666             mode,
667             body,
668             per_local: PerQualif::new(BitSet::new_empty(body.local_decls.len())),
669         };
670
671         for (local, decl) in body.local_decls.iter_enumerated() {
672             if let LocalKind::Arg = body.local_kind(local) {
673                 let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty);
674                 for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 {
675                     if *qualif {
676                         per_local.insert(local);
677                     }
678                 }
679             }
680             if !temps[local].is_promotable() {
681                 cx.per_local[IsNotPromotable].insert(local);
682             }
683             if let LocalKind::Var = body.local_kind(local) {
684                 // Sanity check to prevent implicit and explicit promotion of
685                 // named locals
686                 assert!(cx.per_local[IsNotPromotable].contains(local));
687             }
688         }
689
690         Checker {
691             cx,
692             span: body.span,
693             def_id,
694             rpo,
695             temp_promotion_state: temps,
696             promotion_candidates: vec![]
697         }
698     }
699
700     // FIXME(eddyb) we could split the errors into meaningful
701     // categories, but enabling full miri would make that
702     // slightly pointless (even with feature-gating).
703     fn not_const(&mut self) {
704         unleash_miri!(self);
705         if self.mode.requires_const_checking() {
706             let mut err = struct_span_err!(
707                 self.tcx.sess,
708                 self.span,
709                 E0019,
710                 "{} contains unimplemented expression type",
711                 self.mode
712             );
713             if self.tcx.sess.teach(&err.get_code().unwrap()) {
714                 err.note("A function call isn't allowed in the const's initialization expression \
715                           because the expression's value must be known at compile-time.");
716                 err.note("Remember: you can't use a function call inside a const's initialization \
717                           expression! However, you can use it anywhere else.");
718             }
719             err.emit();
720         }
721     }
722
723     /// Assigns an rvalue/call qualification to the given destination.
724     fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) {
725         trace!("assign: {:?} <- {:?}", dest, source);
726
727         let mut qualifs = self.qualifs_in_value(source);
728
729         if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
730             // Getting `true` from `HasMutInterior::in_rvalue` means
731             // the borrowed place is disallowed from being borrowed,
732             // due to either a mutable borrow (with some exceptions),
733             // or an shared borrow of a value with interior mutability.
734             // Then `HasMutInterior` is replaced with `IsNotPromotable`,
735             // to avoid duplicate errors (e.g. from reborrowing).
736             if qualifs[HasMutInterior] {
737                 qualifs[HasMutInterior] = false;
738                 qualifs[IsNotPromotable] = true;
739
740                 if self.mode.requires_const_checking() {
741                     if let BorrowKind::Mut { .. } = kind {
742                         let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
743                                                        "references in {}s may only refer \
744                                                         to immutable values", self.mode);
745                         err.span_label(self.span, format!("{}s require immutable values",
746                                                             self.mode));
747                         if self.tcx.sess.teach(&err.get_code().unwrap()) {
748                             err.note("References in statics and constants may only refer to \
749                                       immutable values.\n\n\
750                                       Statics are shared everywhere, and if they refer to \
751                                       mutable data one might violate memory safety since \
752                                       holding multiple mutable references to shared data is \
753                                       not allowed.\n\n\
754                                       If you really want global mutable state, try using \
755                                       static mut or a global UnsafeCell.");
756                         }
757                         err.emit();
758                     } else {
759                         span_err!(self.tcx.sess, self.span, E0492,
760                                   "cannot borrow a constant which may contain \
761                                    interior mutability, create a static instead");
762                     }
763                 }
764             } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
765                 // Don't promote BorrowKind::Shallow borrows, as they don't
766                 // reach codegen.
767
768                 // We might have a candidate for promotion.
769                 let candidate = Candidate::Ref(location);
770                 // Start by traversing to the "base", with non-deref projections removed.
771                 let mut place = place;
772                 while let Place::Projection(ref proj) = *place {
773                     if proj.elem == ProjectionElem::Deref {
774                         break;
775                     }
776                     place = &proj.base;
777                 }
778                 debug!("qualify_consts: promotion candidate: place={:?}", place);
779                 // We can only promote interior borrows of promotable temps (non-temps
780                 // don't get promoted anyway).
781                 // (If we bailed out of the loop due to a `Deref` above, we will definitely
782                 // not enter the conditional here.)
783                 if let Place::Base(PlaceBase::Local(local)) = *place {
784                     if self.body.local_kind(local) == LocalKind::Temp {
785                         debug!("qualify_consts: promotion candidate: local={:?}", local);
786                         // The borrowed place doesn't have `HasMutInterior`
787                         // (from `in_rvalue`), so we can safely ignore
788                         // `HasMutInterior` from the local's qualifications.
789                         // This allows borrowing fields which don't have
790                         // `HasMutInterior`, from a type that does, e.g.:
791                         // `let _: &'static _ = &(Cell::new(1), 2).1;`
792                         let mut local_qualifs = self.qualifs_in_local(local);
793                         // Any qualifications, except HasMutInterior (see above), disqualify
794                         // from promotion.
795                         // This is, in particular, the "implicit promotion" version of
796                         // the check making sure that we don't run drop glue during const-eval.
797                         local_qualifs[HasMutInterior] = false;
798                         if !local_qualifs.0.iter().any(|&qualif| qualif) {
799                             debug!("qualify_consts: promotion candidate: {:?}", candidate);
800                             self.promotion_candidates.push(candidate);
801                         }
802                     }
803                 }
804             }
805         }
806
807         let mut dest = dest;
808         let index = loop {
809             match dest {
810                 // We treat all locals equal in constants
811                 Place::Base(PlaceBase::Local(index)) => break *index,
812                 // projections are transparent for assignments
813                 // we qualify the entire destination at once, even if just a field would have
814                 // stricter qualification
815                 Place::Projection(proj) => {
816                     // Catch more errors in the destination. `visit_place` also checks various
817                     // projection rules like union field access and raw pointer deref
818                     self.visit_place(
819                         dest,
820                         PlaceContext::MutatingUse(MutatingUseContext::Store),
821                         location
822                     );
823                     dest = &proj.base;
824                 },
825                 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
826                     bug!("promoteds don't exist yet during promotion"),
827                 Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
828                     // Catch more errors in the destination. `visit_place` also checks that we
829                     // do not try to access statics from constants or try to mutate statics
830                     self.visit_place(
831                         dest,
832                         PlaceContext::MutatingUse(MutatingUseContext::Store),
833                         location
834                     );
835                     return;
836                 }
837             }
838         };
839
840         let kind = self.body.local_kind(index);
841         debug!("store to {:?} {:?}", kind, index);
842
843         // Only handle promotable temps in non-const functions.
844         if self.mode == Mode::NonConstFn {
845             if kind != LocalKind::Temp ||
846                !self.temp_promotion_state[index].is_promotable() {
847                 return;
848             }
849         }
850
851         // this is overly restrictive, because even full assignments do not clear the qualif
852         // While we could special case full assignments, this would be inconsistent with
853         // aggregates where we overwrite all fields via assignments, which would not get
854         // that feature.
855         for (per_local, qualif) in &mut self.cx.per_local.as_mut().zip(qualifs).0 {
856             if *qualif {
857                 per_local.insert(index);
858             }
859         }
860
861         // Ensure the `IsNotPromotable` qualification is preserved.
862         // NOTE(eddyb) this is actually unnecessary right now, as
863         // we never replace the local's qualif, but we might in
864         // the future, and so it serves to catch changes that unset
865         // important bits (in which case, asserting `contains` could
866         // be replaced with calling `insert` to re-set the bit).
867         if kind == LocalKind::Temp {
868             if !self.temp_promotion_state[index].is_promotable() {
869                 assert!(self.cx.per_local[IsNotPromotable].contains(index));
870             }
871         }
872     }
873
874     /// Check a whole const, static initializer or const fn.
875     fn check_const(&mut self) -> (u8, &'tcx BitSet<Local>) {
876         debug!("const-checking {} {:?}", self.mode, self.def_id);
877
878         let body = self.body;
879
880         let mut seen_blocks = BitSet::new_empty(body.basic_blocks().len());
881         let mut bb = START_BLOCK;
882         loop {
883             seen_blocks.insert(bb.index());
884
885             self.visit_basic_block_data(bb, &body[bb]);
886
887             let target = match body[bb].terminator().kind {
888                 TerminatorKind::Goto { target } |
889                 TerminatorKind::Drop { target, .. } |
890                 TerminatorKind::Assert { target, .. } |
891                 TerminatorKind::Call { destination: Some((_, target)), .. } => {
892                     Some(target)
893                 }
894
895                 // Non-terminating calls cannot produce any value.
896                 TerminatorKind::Call { destination: None, .. } => {
897                     break;
898                 }
899
900                 TerminatorKind::SwitchInt {..} |
901                 TerminatorKind::DropAndReplace { .. } |
902                 TerminatorKind::Resume |
903                 TerminatorKind::Abort |
904                 TerminatorKind::GeneratorDrop |
905                 TerminatorKind::Yield { .. } |
906                 TerminatorKind::Unreachable |
907                 TerminatorKind::FalseEdges { .. } |
908                 TerminatorKind::FalseUnwind { .. } => None,
909
910                 TerminatorKind::Return => {
911                     break;
912                 }
913             };
914
915             match target {
916                 // No loops allowed.
917                 Some(target) if !seen_blocks.contains(target.index()) => {
918                     bb = target;
919                 }
920                 _ => {
921                     self.not_const();
922                     break;
923                 }
924             }
925         }
926
927
928         // Collect all the temps we need to promote.
929         let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
930
931         debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
932         for candidate in &self.promotion_candidates {
933             match *candidate {
934                 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
935                     match self.body[bb].statements[stmt_idx].kind {
936                         StatementKind::Assign(
937                             _,
938                             box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
939                         ) => {
940                             promoted_temps.insert(index);
941                         }
942                         _ => {}
943                     }
944                 }
945                 Candidate::Argument { .. } => {}
946             }
947         }
948
949         let mut qualifs = self.qualifs_in_local(RETURN_PLACE);
950
951         // Account for errors in consts by using the
952         // conservative type qualification instead.
953         if qualifs[IsNotPromotable] {
954             qualifs = self.qualifs_in_any_value_of_ty(body.return_ty());
955         }
956
957         (qualifs.encode_to_bits(), self.tcx.arena.alloc(promoted_temps))
958     }
959 }
960
961 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
962     fn visit_place_base(
963         &mut self,
964         place_base: &PlaceBase<'tcx>,
965         context: PlaceContext,
966         location: Location,
967     ) {
968         self.super_place_base(place_base, context, location);
969         match place_base {
970             PlaceBase::Local(_) => {}
971             PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
972                 unreachable!()
973             }
974             PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
975                 if self.tcx
976                         .get_attrs(*def_id)
977                         .iter()
978                         .any(|attr| attr.check_name(sym::thread_local)) {
979                     if self.mode.requires_const_checking() {
980                         span_err!(self.tcx.sess, self.span, E0625,
981                                     "thread-local statics cannot be \
982                                     accessed at compile-time");
983                     }
984                     return;
985                 }
986
987                 // Only allow statics (not consts) to refer to other statics.
988                 if self.mode == Mode::Static || self.mode == Mode::StaticMut {
989                     if self.mode == Mode::Static && context.is_mutating_use() {
990                         // this is not strictly necessary as miri will also bail out
991                         // For interior mutability we can't really catch this statically as that
992                         // goes through raw pointers and intermediate temporaries, so miri has
993                         // to catch this anyway
994                         self.tcx.sess.span_err(
995                             self.span,
996                             "cannot mutate statics in the initializer of another static",
997                         );
998                     }
999                     return;
1000                 }
1001                 unleash_miri!(self);
1002
1003                 if self.mode.requires_const_checking() {
1004                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
1005                                                     "{}s cannot refer to statics, use \
1006                                                     a constant instead", self.mode);
1007                     if self.tcx.sess.teach(&err.get_code().unwrap()) {
1008                         err.note(
1009                             "Static and const variables can refer to other const variables. \
1010                                 But a const variable cannot refer to a static variable."
1011                         );
1012                         err.help(
1013                             "To fix this, the value can be extracted as a const and then used."
1014                         );
1015                     }
1016                     err.emit()
1017                 }
1018             }
1019         }
1020     }
1021
1022     fn visit_projection(
1023         &mut self,
1024         proj: &Projection<'tcx>,
1025         context: PlaceContext,
1026         location: Location,
1027     ) {
1028         debug!(
1029             "visit_place_projection: proj={:?} context={:?} location={:?}",
1030             proj, context, location,
1031         );
1032         self.super_projection(proj, context, location);
1033         match proj.elem {
1034             ProjectionElem::Deref => {
1035                 if context.is_mutating_use() {
1036                     // `not_const` errors out in const contexts
1037                     self.not_const()
1038                 }
1039                 let base_ty = proj.base.ty(self.body, self.tcx).ty;
1040                 match self.mode {
1041                     Mode::NonConstFn => {},
1042                     _ => {
1043                         if let ty::RawPtr(_) = base_ty.sty {
1044                             if !self.tcx.features().const_raw_ptr_deref {
1045                                 emit_feature_err(
1046                                     &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
1047                                     self.span, GateIssue::Language,
1048                                     &format!(
1049                                         "dereferencing raw pointers in {}s is unstable",
1050                                         self.mode,
1051                                     ),
1052                                 );
1053                             }
1054                         }
1055                     }
1056                 }
1057             }
1058
1059             ProjectionElem::ConstantIndex {..} |
1060             ProjectionElem::Subslice {..} |
1061             ProjectionElem::Field(..) |
1062             ProjectionElem::Index(_) => {
1063                 let base_ty = proj.base.ty(self.body, self.tcx).ty;
1064                 if let Some(def) = base_ty.ty_adt_def() {
1065                     if def.is_union() {
1066                         match self.mode {
1067                             Mode::ConstFn => {
1068                                 if !self.tcx.features().const_fn_union {
1069                                     emit_feature_err(
1070                                         &self.tcx.sess.parse_sess, sym::const_fn_union,
1071                                         self.span, GateIssue::Language,
1072                                         "unions in const fn are unstable",
1073                                     );
1074                                 }
1075                             },
1076
1077                             | Mode::NonConstFn
1078                             | Mode::Static
1079                             | Mode::StaticMut
1080                             | Mode::Const
1081                             => {},
1082                         }
1083                     }
1084                 }
1085             }
1086
1087             ProjectionElem::Downcast(..) => {
1088                 self.not_const()
1089             }
1090         }
1091     }
1092
1093     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
1094         debug!("visit_operand: operand={:?} location={:?}", operand, location);
1095         self.super_operand(operand, location);
1096
1097         match *operand {
1098             Operand::Move(ref place) => {
1099                 // Mark the consumed locals to indicate later drops are noops.
1100                 if let Place::Base(PlaceBase::Local(local)) = *place {
1101                     self.cx.per_local[NeedsDrop].remove(local);
1102                 }
1103             }
1104             Operand::Copy(_) |
1105             Operand::Constant(_) => {}
1106         }
1107     }
1108
1109     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
1110         debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
1111
1112         // Check nested operands and places.
1113         if let Rvalue::Ref(_, kind, ref place) = *rvalue {
1114             // Special-case reborrows.
1115             let mut reborrow_place = None;
1116             if let Place::Projection(ref proj) = *place {
1117                 if let ProjectionElem::Deref = proj.elem {
1118                     let base_ty = proj.base.ty(self.body, self.tcx).ty;
1119                     if let ty::Ref(..) = base_ty.sty {
1120                         reborrow_place = Some(&proj.base);
1121                     }
1122                 }
1123             }
1124
1125             if let Some(place) = reborrow_place {
1126                 let ctx = match kind {
1127                     BorrowKind::Shared => PlaceContext::NonMutatingUse(
1128                         NonMutatingUseContext::SharedBorrow,
1129                     ),
1130                     BorrowKind::Shallow => PlaceContext::NonMutatingUse(
1131                         NonMutatingUseContext::ShallowBorrow,
1132                     ),
1133                     BorrowKind::Unique => PlaceContext::NonMutatingUse(
1134                         NonMutatingUseContext::UniqueBorrow,
1135                     ),
1136                     BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
1137                         MutatingUseContext::Borrow,
1138                     ),
1139                 };
1140                 self.visit_place(place, ctx, location);
1141             } else {
1142                 self.super_rvalue(rvalue, location);
1143             }
1144         } else {
1145             self.super_rvalue(rvalue, location);
1146         }
1147
1148         match *rvalue {
1149             Rvalue::Use(_) |
1150             Rvalue::Repeat(..) |
1151             Rvalue::UnaryOp(UnOp::Neg, _) |
1152             Rvalue::UnaryOp(UnOp::Not, _) |
1153             Rvalue::NullaryOp(NullOp::SizeOf, _) |
1154             Rvalue::CheckedBinaryOp(..) |
1155             Rvalue::Cast(CastKind::Pointer(_), ..) |
1156             Rvalue::Discriminant(..) |
1157             Rvalue::Len(_) |
1158             Rvalue::Ref(..) |
1159             Rvalue::Aggregate(..) => {}
1160
1161             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
1162                 let operand_ty = operand.ty(self.body, self.tcx);
1163                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
1164                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
1165                 match (cast_in, cast_out) {
1166                     (CastTy::Ptr(_), CastTy::Int(_)) |
1167                     (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::NonConstFn => {
1168                         unleash_miri!(self);
1169                         if !self.tcx.features().const_raw_ptr_to_usize_cast {
1170                             // in const fn and constants require the feature gate
1171                             // FIXME: make it unsafe inside const fn and constants
1172                             emit_feature_err(
1173                                 &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
1174                                 self.span, GateIssue::Language,
1175                                 &format!(
1176                                     "casting pointers to integers in {}s is unstable",
1177                                     self.mode,
1178                                 ),
1179                             );
1180                         }
1181                     }
1182                     _ => {}
1183                 }
1184             }
1185
1186             Rvalue::BinaryOp(op, ref lhs, _) => {
1187                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty {
1188                     assert!(op == BinOp::Eq || op == BinOp::Ne ||
1189                             op == BinOp::Le || op == BinOp::Lt ||
1190                             op == BinOp::Ge || op == BinOp::Gt ||
1191                             op == BinOp::Offset);
1192
1193                     unleash_miri!(self);
1194                     if self.mode.requires_const_checking() &&
1195                         !self.tcx.features().const_compare_raw_pointers
1196                     {
1197                         // require the feature gate inside constants and const fn
1198                         // FIXME: make it unsafe to use these operations
1199                         emit_feature_err(
1200                             &self.tcx.sess.parse_sess,
1201                             sym::const_compare_raw_pointers,
1202                             self.span,
1203                             GateIssue::Language,
1204                             &format!("comparing raw pointers inside {}", self.mode),
1205                         );
1206                     }
1207                 }
1208             }
1209
1210             Rvalue::NullaryOp(NullOp::Box, _) => {
1211                 unleash_miri!(self);
1212                 if self.mode.requires_const_checking() {
1213                     let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
1214                                                    "allocations are not allowed in {}s", self.mode);
1215                     err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
1216                     if self.tcx.sess.teach(&err.get_code().unwrap()) {
1217                         err.note(
1218                             "The value of statics and constants must be known at compile time, \
1219                              and they live for the entire lifetime of a program. Creating a boxed \
1220                              value allocates memory on the heap at runtime, and therefore cannot \
1221                              be done at compile time."
1222                         );
1223                     }
1224                     err.emit();
1225                 }
1226             }
1227         }
1228     }
1229
1230     fn visit_terminator_kind(&mut self,
1231                              kind: &TerminatorKind<'tcx>,
1232                              location: Location) {
1233         debug!("visit_terminator_kind: kind={:?} location={:?}", kind, location);
1234         if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
1235             if let Some((ref dest, _)) = *destination {
1236                 self.assign(dest, ValueSource::Call {
1237                     callee: func,
1238                     args,
1239                     return_ty: dest.ty(self.body, self.tcx).ty,
1240                 }, location);
1241             }
1242
1243             let fn_ty = func.ty(self.body, self.tcx);
1244             let mut callee_def_id = None;
1245             let mut is_shuffle = false;
1246             match fn_ty.sty {
1247                 ty::FnDef(def_id, _) => {
1248                     callee_def_id = Some(def_id);
1249                     match self.tcx.fn_sig(def_id).abi() {
1250                         Abi::RustIntrinsic |
1251                         Abi::PlatformIntrinsic => {
1252                             assert!(!self.tcx.is_const_fn(def_id));
1253                             match &self.tcx.item_name(def_id).as_str()[..] {
1254                                 // special intrinsic that can be called diretly without an intrinsic
1255                                 // feature gate needs a language feature gate
1256                                 "transmute" => {
1257                                     if self.mode.requires_const_checking() {
1258                                         // const eval transmute calls only with the feature gate
1259                                         if !self.tcx.features().const_transmute {
1260                                             emit_feature_err(
1261                                                 &self.tcx.sess.parse_sess, sym::const_transmute,
1262                                                 self.span, GateIssue::Language,
1263                                                 &format!("The use of std::mem::transmute() \
1264                                                 is gated in {}s", self.mode));
1265                                         }
1266                                     }
1267                                 }
1268
1269                                 name if name.starts_with("simd_shuffle") => {
1270                                     is_shuffle = true;
1271                                 }
1272
1273                                 // no need to check feature gates, intrinsics are only callable
1274                                 // from the libstd or with forever unstable feature gates
1275                                 _ => {}
1276                             }
1277                         }
1278                         _ => {
1279                             // In normal functions no calls are feature-gated.
1280                             if self.mode.requires_const_checking() {
1281                                 let unleash_miri = self
1282                                     .tcx
1283                                     .sess
1284                                     .opts
1285                                     .debugging_opts
1286                                     .unleash_the_miri_inside_of_you;
1287                                 if self.tcx.is_const_fn(def_id) || unleash_miri {
1288                                     // stable const fns or unstable const fns
1289                                     // with their feature gate active
1290                                     // FIXME(eddyb) move stability checks from `is_const_fn` here.
1291                                 } else if self.is_const_panic_fn(def_id) {
1292                                     // Check the const_panic feature gate.
1293                                     // FIXME: cannot allow this inside `allow_internal_unstable`
1294                                     // because that would make `panic!` insta stable in constants,
1295                                     // since the macro is marked with the attribute.
1296                                     if !self.tcx.features().const_panic {
1297                                         // Don't allow panics in constants without the feature gate.
1298                                         emit_feature_err(
1299                                             &self.tcx.sess.parse_sess,
1300                                             sym::const_panic,
1301                                             self.span,
1302                                             GateIssue::Language,
1303                                             &format!("panicking in {}s is unstable", self.mode),
1304                                         );
1305                                     }
1306                                 } else if let Some(feature)
1307                                               = self.tcx.is_unstable_const_fn(def_id) {
1308                                     // Check `#[unstable]` const fns or `#[rustc_const_unstable]`
1309                                     // functions without the feature gate active in this crate in
1310                                     // order to report a better error message than the one below.
1311                                     if !self.span.allows_unstable(feature) {
1312                                         let mut err = self.tcx.sess.struct_span_err(self.span,
1313                                             &format!("`{}` is not yet stable as a const fn",
1314                                                     self.tcx.def_path_str(def_id)));
1315                                         if nightly_options::is_nightly_build() {
1316                                             help!(&mut err,
1317                                                   "add `#![feature({})]` to the \
1318                                                    crate attributes to enable",
1319                                                   feature);
1320                                         }
1321                                         err.emit();
1322                                     }
1323                                 } else {
1324                                     let mut err = struct_span_err!(
1325                                         self.tcx.sess,
1326                                         self.span,
1327                                         E0015,
1328                                         "calls in {}s are limited to constant functions, \
1329                                          tuple structs and tuple variants",
1330                                         self.mode,
1331                                     );
1332                                     err.emit();
1333                                 }
1334                             }
1335                         }
1336                     }
1337                 }
1338                 ty::FnPtr(_) => {
1339                     if self.mode.requires_const_checking() {
1340                         let mut err = self.tcx.sess.struct_span_err(
1341                             self.span,
1342                             &format!("function pointers are not allowed in const fn"));
1343                         err.emit();
1344                     }
1345                 }
1346                 _ => {
1347                     self.not_const();
1348                 }
1349             }
1350
1351             // No need to do anything in constants and statics, as everything is "constant" anyway
1352             // so promotion would be useless.
1353             if self.mode != Mode::Static && self.mode != Mode::Const {
1354                 let constant_args = callee_def_id.and_then(|id| {
1355                     args_required_const(self.tcx, id)
1356                 }).unwrap_or_default();
1357                 for (i, arg) in args.iter().enumerate() {
1358                     if !(is_shuffle && i == 2 || constant_args.contains(&i)) {
1359                         continue;
1360                     }
1361
1362                     let candidate = Candidate::Argument { bb: location.block, index: i };
1363                     // Since the argument is required to be constant,
1364                     // we care about constness, not promotability.
1365                     // If we checked for promotability, we'd miss out on
1366                     // the results of function calls (which are never promoted
1367                     // in runtime code).
1368                     // This is not a problem, because the argument explicitly
1369                     // requests constness, in contrast to regular promotion
1370                     // which happens even without the user requesting it.
1371                     // We can error out with a hard error if the argument is not
1372                     // constant here.
1373                     if !IsNotPromotable::in_operand(self, arg) {
1374                         debug!("visit_terminator_kind: candidate={:?}", candidate);
1375                         self.promotion_candidates.push(candidate);
1376                     } else {
1377                         if is_shuffle {
1378                             span_err!(self.tcx.sess, self.span, E0526,
1379                                       "shuffle indices are not constant");
1380                         } else {
1381                             self.tcx.sess.span_err(self.span,
1382                                 &format!("argument {} is required to be a constant",
1383                                          i + 1));
1384                         }
1385                     }
1386                 }
1387             }
1388
1389             // Check callee and argument operands.
1390             self.visit_operand(func, location);
1391             for arg in args {
1392                 self.visit_operand(arg, location);
1393             }
1394         } else if let TerminatorKind::Drop { location: ref place, .. } = *kind {
1395             self.super_terminator_kind(kind, location);
1396
1397             // Deny *any* live drops anywhere other than functions.
1398             if self.mode.requires_const_checking() {
1399                 unleash_miri!(self);
1400                 // HACK(eddyb): emulate a bit of dataflow analysis,
1401                 // conservatively, that drop elaboration will do.
1402                 let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place {
1403                     if NeedsDrop::in_local(self, local) {
1404                         Some(self.body.local_decls[local].source_info.span)
1405                     } else {
1406                         None
1407                     }
1408                 } else {
1409                     Some(self.span)
1410                 };
1411
1412                 if let Some(span) = needs_drop {
1413                     // Double-check the type being dropped, to minimize false positives.
1414                     let ty = place.ty(self.body, self.tcx).ty;
1415                     if ty.needs_drop(self.tcx, self.param_env) {
1416                         struct_span_err!(self.tcx.sess, span, E0493,
1417                                          "destructors cannot be evaluated at compile-time")
1418                             .span_label(span, format!("{}s cannot evaluate destructors",
1419                                                       self.mode))
1420                             .emit();
1421                     }
1422                 }
1423             }
1424         } else {
1425             // Qualify any operands inside other terminators.
1426             self.super_terminator_kind(kind, location);
1427         }
1428     }
1429
1430     fn visit_assign(&mut self,
1431                     dest: &Place<'tcx>,
1432                     rvalue: &Rvalue<'tcx>,
1433                     location: Location) {
1434         debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
1435         self.assign(dest, ValueSource::Rvalue(rvalue), location);
1436
1437         self.visit_rvalue(rvalue, location);
1438     }
1439
1440     fn visit_source_info(&mut self, source_info: &SourceInfo) {
1441         debug!("visit_source_info: source_info={:?}", source_info);
1442         self.span = source_info.span;
1443     }
1444
1445     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
1446         debug!("visit_statement: statement={:?} location={:?}", statement, location);
1447         match statement.kind {
1448             StatementKind::Assign(..) => {
1449                 self.super_statement(statement, location);
1450             }
1451             StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
1452                 self.not_const();
1453             }
1454             // FIXME(eddyb) should these really do nothing?
1455             StatementKind::FakeRead(..) |
1456             StatementKind::SetDiscriminant { .. } |
1457             StatementKind::StorageLive(_) |
1458             StatementKind::StorageDead(_) |
1459             StatementKind::InlineAsm {..} |
1460             StatementKind::Retag { .. } |
1461             StatementKind::AscribeUserType(..) |
1462             StatementKind::Nop => {}
1463         }
1464     }
1465 }
1466
1467 pub fn provide(providers: &mut Providers<'_>) {
1468     *providers = Providers {
1469         mir_const_qualif,
1470         ..*providers
1471     };
1472 }
1473
1474 fn mir_const_qualif<'tcx>(tcx: TyCtxt<'tcx, 'tcx>, def_id: DefId) -> (u8, &'tcx BitSet<Local>) {
1475     // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
1476     // cannot yet be stolen), because `mir_validated()`, which steals
1477     // from `mir_const(), forces this query to execute before
1478     // performing the steal.
1479     let body = &tcx.mir_const(def_id).borrow();
1480
1481     if body.return_ty().references_error() {
1482         tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
1483         return (1 << IsNotPromotable::IDX, tcx.arena.alloc(BitSet::new_empty(0)));
1484     }
1485
1486     Checker::new(tcx, def_id, body, Mode::Const).check_const()
1487 }
1488
1489 pub struct QualifyAndPromoteConstants;
1490
1491 impl MirPass for QualifyAndPromoteConstants {
1492     fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx, 'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
1493         // There's not really any point in promoting errorful MIR.
1494         if body.return_ty().references_error() {
1495             tcx.sess.delay_span_bug(body.span, "QualifyAndPromoteConstants: MIR had errors");
1496             return;
1497         }
1498
1499         if src.promoted.is_some() {
1500             return;
1501         }
1502
1503         let def_id = src.def_id();
1504         let id = tcx.hir().as_local_hir_id(def_id).unwrap();
1505         let mut const_promoted_temps = None;
1506         let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
1507             hir::BodyOwnerKind::Closure => Mode::NonConstFn,
1508             hir::BodyOwnerKind::Fn => {
1509                 if tcx.is_const_fn(def_id) {
1510                     Mode::ConstFn
1511                 } else {
1512                     Mode::NonConstFn
1513                 }
1514             }
1515             hir::BodyOwnerKind::Const => {
1516                 const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1517                 Mode::Const
1518             }
1519             hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
1520             hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
1521         };
1522
1523         debug!("run_pass: mode={:?}", mode);
1524         if mode == Mode::NonConstFn || mode == Mode::ConstFn {
1525             // This is ugly because Checker holds onto mir,
1526             // which can't be mutated until its scope ends.
1527             let (temps, candidates) = {
1528                 let mut checker = Checker::new(tcx, def_id, body, mode);
1529                 if mode == Mode::ConstFn {
1530                     if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
1531                         checker.check_const();
1532                     } else if tcx.is_min_const_fn(def_id) {
1533                         // enforce `min_const_fn` for stable const fns
1534                         use super::qualify_min_const_fn::is_min_const_fn;
1535                         if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) {
1536                             let mut diag = struct_span_err!(
1537                                 tcx.sess,
1538                                 span,
1539                                 E0723,
1540                                 "{}",
1541                                 err,
1542                             );
1543                             diag.note("for more information, see issue \
1544                                        https://github.com/rust-lang/rust/issues/57563");
1545                             diag.help(
1546                                 "add #![feature(const_fn)] to the crate attributes to enable",
1547                             );
1548                             diag.emit();
1549                         } else {
1550                             // this should not produce any errors, but better safe than sorry
1551                             // FIXME(#53819)
1552                             checker.check_const();
1553                         }
1554                     } else {
1555                         // Enforce a constant-like CFG for `const fn`.
1556                         checker.check_const();
1557                     }
1558                 } else {
1559                     while let Some((bb, data)) = checker.rpo.next() {
1560                         checker.visit_basic_block_data(bb, data);
1561                     }
1562                 }
1563
1564                 (checker.temp_promotion_state, checker.promotion_candidates)
1565             };
1566
1567             // Do the actual promotion, now that we know what's viable.
1568             promote_consts::promote_candidates(body, tcx, temps, candidates);
1569         } else {
1570             if !body.control_flow_destroyed.is_empty() {
1571                 let mut locals = body.vars_iter();
1572                 if let Some(local) = locals.next() {
1573                     let span = body.local_decls[local].source_info.span;
1574                     let mut error = tcx.sess.struct_span_err(
1575                         span,
1576                         &format!(
1577                             "new features like let bindings are not permitted in {}s \
1578                             which also use short circuiting operators",
1579                             mode,
1580                         ),
1581                     );
1582                     for (span, kind) in body.control_flow_destroyed.iter() {
1583                         error.span_note(
1584                             *span,
1585                             &format!("use of {} here does not actually short circuit due to \
1586                             the const evaluator presently not being able to do control flow. \
1587                             See https://github.com/rust-lang/rust/issues/49146 for more \
1588                             information.", kind),
1589                         );
1590                     }
1591                     for local in locals {
1592                         let span = body.local_decls[local].source_info.span;
1593                         error.span_note(
1594                             span,
1595                             "more locals defined here",
1596                         );
1597                     }
1598                     error.emit();
1599                 }
1600             }
1601             let promoted_temps = if mode == Mode::Const {
1602                 // Already computed by `mir_const_qualif`.
1603                 const_promoted_temps.unwrap()
1604             } else {
1605                 Checker::new(tcx, def_id, body, mode).check_const().1
1606             };
1607
1608             // In `const` and `static` everything without `StorageDead`
1609             // is `'static`, we don't have to create promoted MIR fragments,
1610             // just remove `Drop` and `StorageDead` on "promoted" locals.
1611             debug!("run_pass: promoted_temps={:?}", promoted_temps);
1612             for block in body.basic_blocks_mut() {
1613                 block.statements.retain(|statement| {
1614                     match statement.kind {
1615                         StatementKind::StorageDead(index) => {
1616                             !promoted_temps.contains(index)
1617                         }
1618                         _ => true
1619                     }
1620                 });
1621                 let terminator = block.terminator_mut();
1622                 match terminator.kind {
1623                     TerminatorKind::Drop {
1624                         location: Place::Base(PlaceBase::Local(index)),
1625                         target,
1626                         ..
1627                     } => {
1628                         if promoted_temps.contains(index) {
1629                             terminator.kind = TerminatorKind::Goto {
1630                                 target,
1631                             };
1632                         }
1633                     }
1634                     _ => {}
1635                 }
1636             }
1637         }
1638
1639         // Statics must be Sync.
1640         if mode == Mode::Static {
1641             // `#[thread_local]` statics don't have to be `Sync`.
1642             for attr in &tcx.get_attrs(def_id)[..] {
1643                 if attr.check_name(sym::thread_local) {
1644                     return;
1645                 }
1646             }
1647             let ty = body.return_ty();
1648             tcx.infer_ctxt().enter(|infcx| {
1649                 let param_env = ty::ParamEnv::empty();
1650                 let cause = traits::ObligationCause::new(body.span, id, traits::SharedStatic);
1651                 let mut fulfillment_cx = traits::FulfillmentContext::new();
1652                 fulfillment_cx.register_bound(&infcx,
1653                                               param_env,
1654                                               ty,
1655                                               tcx.require_lang_item(lang_items::SyncTraitLangItem),
1656                                               cause);
1657                 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
1658                     infcx.report_fulfillment_errors(&err, None, false);
1659                 }
1660             });
1661         }
1662     }
1663 }
1664
1665 fn args_required_const(tcx: TyCtxt<'_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
1666     let attrs = tcx.get_attrs(def_id);
1667     let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
1668     let mut ret = FxHashSet::default();
1669     for meta in attr.meta_item_list()? {
1670         match meta.literal()?.node {
1671             LitKind::Int(a, _) => { ret.insert(a as usize); }
1672             _ => return None,
1673         }
1674     }
1675     Some(ret)
1676 }