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