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