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