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