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