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