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