1 //! A pass that qualifies constness of temporaries in constants,
2 //! static initializers and functions and also drives promotion.
4 //! The Qualif flags below can be used to also provide better
5 //! diagnostics as to why a constant rvalue wasn't promoted.
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;
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;
19 use rustc::mir::interpret::ConstValue;
20 use rustc::mir::traversal::ReversePostorder;
21 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
22 use rustc::middle::lang_items;
23 use rustc::session::config::nightly_options;
24 use syntax::ast::LitKind;
25 use syntax::feature_gate::{emit_feature_err, GateIssue};
26 use syntax_pos::{Span, DUMMY_SP};
29 use std::ops::{Deref, Index, IndexMut};
32 use crate::transform::{MirPass, MirSource};
33 use super::promote_consts::{self, Candidate, TempState};
35 /// What kind of item we are in.
36 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
45 impl fmt::Display for Mode {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 Mode::Const => write!(f, "constant"),
49 Mode::Static | Mode::StaticMut => write!(f, "static"),
50 Mode::ConstFn => write!(f, "constant function"),
51 Mode::Fn => write!(f, "function")
56 const QUALIF_COUNT: usize = 4;
58 // FIXME(eddyb) once we can use const generics, replace this array with
59 // something like `IndexVec` but for fixed-size arrays (`IndexArray`?).
60 #[derive(Copy, Clone, Default)]
61 struct PerQualif<T>([T; QUALIF_COUNT]);
63 impl<T: Clone> PerQualif<T> {
64 fn new(x: T) -> Self {
65 PerQualif([x.clone(), x.clone(), x.clone(), x])
69 impl<T> PerQualif<T> {
70 fn as_mut(&mut self) -> PerQualif<&mut T> {
71 let [x0, x1, x2, x3] = &mut self.0;
72 PerQualif([x0, x1, x2, x3])
75 fn zip<U>(self, other: PerQualif<U>) -> PerQualif<(T, U)> {
76 let [x0, x1, x2, x3] = self.0;
77 let [y0, y1, y2, y3] = other.0;
78 PerQualif([(x0, y0), (x1, y1), (x2, y2), (x3, y3)])
82 impl PerQualif<bool> {
83 fn encode_to_bits(self) -> u8 {
84 self.0.iter().enumerate().fold(0, |bits, (i, &qualif)| {
85 bits | ((qualif as u8) << i)
89 fn decode_from_bits(bits: u8) -> Self {
90 let mut qualifs = Self::default();
91 for (i, qualif) in qualifs.0.iter_mut().enumerate() {
92 *qualif = (bits & (1 << i)) != 0;
98 impl<Q: Qualif, T> Index<Q> for PerQualif<T> {
101 fn index(&self, _: Q) -> &T {
106 impl<Q: Qualif, T> IndexMut<Q> for PerQualif<T> {
107 fn index_mut(&mut self, _: Q) -> &mut T {
112 struct ConstCx<'a, 'tcx> {
113 tcx: TyCtxt<'a, 'tcx, 'tcx>,
114 param_env: ty::ParamEnv<'tcx>,
118 per_local: PerQualif<BitSet<Local>>,
121 impl<'a, 'tcx> ConstCx<'a, 'tcx> {
122 fn is_const_panic_fn(&self, def_id: DefId) -> bool {
123 Some(def_id) == self.tcx.lang_items().panic_fn() ||
124 Some(def_id) == self.tcx.lang_items().begin_panic_fn()
128 #[derive(Copy, Clone, Debug)]
129 enum ValueSource<'a, 'tcx> {
130 Rvalue(&'a Rvalue<'tcx>),
132 callee: &'a Operand<'tcx>,
133 args: &'a [Operand<'tcx>],
141 /// Return the qualification that is (conservatively) correct for any value
142 /// of the type, or `None` if the qualification is not value/type-based.
143 fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> Option<bool> {
147 /// Return a mask for the qualification, given a type. This is `false` iff
148 /// no value of that type can have the qualification.
149 fn mask_for_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
150 Self::in_any_value_of_ty(cx, ty).unwrap_or(true)
153 fn in_local(cx: &ConstCx<'_, '_>, local: Local) -> bool {
154 cx.per_local.0[Self::IDX].contains(local)
157 fn in_static(_cx: &ConstCx<'_, 'tcx>, _static: &Static<'tcx>) -> bool {
158 // FIXME(eddyb) should we do anything here for value properties?
162 fn in_projection_structurally(
163 cx: &ConstCx<'_, 'tcx>,
164 proj: &PlaceProjection<'tcx>,
166 let base_qualif = Self::in_place(cx, &proj.base);
167 let qualif = base_qualif && Self::mask_for_ty(
169 proj.base.ty(cx.mir, cx.tcx)
170 .projection_ty(cx.tcx, &proj.elem)
174 ProjectionElem::Deref |
175 ProjectionElem::Subslice { .. } |
176 ProjectionElem::Field(..) |
177 ProjectionElem::ConstantIndex { .. } |
178 ProjectionElem::Downcast(..) => qualif,
180 ProjectionElem::Index(local) => qualif || Self::in_local(cx, local),
184 fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &PlaceProjection<'tcx>) -> bool {
185 Self::in_projection_structurally(cx, proj)
188 fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
190 Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
191 Place::Base(PlaceBase::Static(box Static {kind: StaticKind::Promoted(_), .. })) =>
192 bug!("qualifying already promoted MIR"),
193 Place::Base(PlaceBase::Static(ref static_)) => {
194 Self::in_static(cx, static_)
196 Place::Projection(ref proj) => Self::in_projection(cx, proj),
200 fn in_operand(cx: &ConstCx<'_, 'tcx>, operand: &Operand<'tcx>) -> bool {
202 Operand::Copy(ref place) |
203 Operand::Move(ref place) => Self::in_place(cx, place),
205 Operand::Constant(ref constant) => {
206 if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
207 // Don't peek inside trait associated constants.
208 if cx.tcx.trait_of_item(def_id).is_some() {
209 Self::in_any_value_of_ty(cx, constant.ty).unwrap_or(false)
211 let (bits, _) = cx.tcx.at(constant.span).mir_const_qualif(def_id);
213 let qualif = PerQualif::decode_from_bits(bits).0[Self::IDX];
215 // Just in case the type is more specific than
216 // the definition, e.g., impl associated const
217 // with type parameters, take it into account.
218 qualif && Self::mask_for_ty(cx, constant.ty)
227 fn in_rvalue_structurally(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
229 Rvalue::NullaryOp(..) => false,
231 Rvalue::Discriminant(ref place) |
232 Rvalue::Len(ref place) => Self::in_place(cx, place),
234 Rvalue::Use(ref operand) |
235 Rvalue::Repeat(ref operand, _) |
236 Rvalue::UnaryOp(_, ref operand) |
237 Rvalue::Cast(_, ref operand, _) => Self::in_operand(cx, operand),
239 Rvalue::BinaryOp(_, ref lhs, ref rhs) |
240 Rvalue::CheckedBinaryOp(_, ref lhs, ref rhs) => {
241 Self::in_operand(cx, lhs) || Self::in_operand(cx, rhs)
244 Rvalue::Ref(_, _, ref place) => {
245 // Special-case reborrows to be more like a copy of the reference.
246 if let Place::Projection(ref proj) = *place {
247 if let ProjectionElem::Deref = proj.elem {
248 let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx);
249 if let ty::Ref(..) = base_ty.sty {
250 return Self::in_place(cx, &proj.base);
255 Self::in_place(cx, place)
258 Rvalue::Aggregate(_, ref operands) => {
259 operands.iter().any(|o| Self::in_operand(cx, o))
264 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
265 Self::in_rvalue_structurally(cx, rvalue)
269 cx: &ConstCx<'_, 'tcx>,
270 _callee: &Operand<'tcx>,
271 _args: &[Operand<'tcx>],
274 // Be conservative about the returned value of a const fn.
275 Self::in_any_value_of_ty(cx, return_ty).unwrap_or(false)
278 fn in_value(cx: &ConstCx<'_, 'tcx>, source: ValueSource<'_, 'tcx>) -> bool {
280 ValueSource::Rvalue(rvalue) => Self::in_rvalue(cx, rvalue),
281 ValueSource::Call { callee, args, return_ty } => {
282 Self::in_call(cx, callee, args, return_ty)
288 // Constant containing interior mutability (UnsafeCell).
289 struct HasMutInterior;
291 impl Qualif for HasMutInterior {
292 const IDX: usize = 0;
294 fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<bool> {
295 Some(!ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP))
298 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
300 // Returning `true` for `Rvalue::Ref` indicates the borrow isn't
301 // allowed in constants (and the `Checker` will error), and/or it
302 // won't be promoted, due to `&mut ...` or interior mutability.
303 Rvalue::Ref(_, kind, ref place) => {
304 let ty = place.ty(cx.mir, cx.tcx).to_ty(cx.tcx);
306 if let BorrowKind::Mut { .. } = kind {
307 // In theory, any zero-sized value could be borrowed
308 // mutably without consequences. However, only &mut []
309 // is allowed right now, and only in functions.
310 if cx.mode == Mode::StaticMut {
311 // Inside a `static mut`, &mut [...] is also allowed.
313 ty::Array(..) | ty::Slice(_) => {}
316 } else if let ty::Array(_, len) = ty.sty {
317 // FIXME(eddyb) the `cx.mode == Mode::Fn` condition
318 // seems unnecessary, given that this is merely a ZST.
319 if !(len.unwrap_usize(cx.tcx) == 0 && cx.mode == Mode::Fn) {
328 Rvalue::Aggregate(ref kind, _) => {
329 if let AggregateKind::Adt(def, ..) = **kind {
330 if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() {
331 let ty = rvalue.ty(cx.mir, cx.tcx);
332 assert_eq!(Self::in_any_value_of_ty(cx, ty), Some(true));
341 Self::in_rvalue_structurally(cx, rvalue)
345 // Constant containing an ADT that implements Drop.
348 impl Qualif for NeedsDrop {
349 const IDX: usize = 1;
351 fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<bool> {
352 Some(ty.needs_drop(cx.tcx, cx.param_env))
355 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
356 if let Rvalue::Aggregate(ref kind, _) = *rvalue {
357 if let AggregateKind::Adt(def, ..) = **kind {
358 if def.has_dtor(cx.tcx) {
364 Self::in_rvalue_structurally(cx, rvalue)
368 // Not constant at all - non-`const fn` calls, asm!,
369 // pointer comparisons, ptr-to-int casts, etc.
372 impl Qualif for IsNotConst {
373 const IDX: usize = 2;
375 fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool {
377 StaticKind::Promoted(_) => unreachable!(),
378 StaticKind::Static(def_id) => {
379 // Only allow statics (not consts) to refer to other statics.
380 let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut;
383 cx.tcx.get_attrs(def_id).iter().any(
384 |attr| attr.check_name("thread_local"
390 fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &PlaceProjection<'tcx>) -> bool {
392 ProjectionElem::Deref |
393 ProjectionElem::Downcast(..) => return true,
395 ProjectionElem::ConstantIndex {..} |
396 ProjectionElem::Subslice {..} |
397 ProjectionElem::Index(_) => {}
399 ProjectionElem::Field(..) => {
400 if cx.mode == Mode::Fn {
401 let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx);
402 if let Some(def) = base_ty.ty_adt_def() {
411 Self::in_projection_structurally(cx, proj)
414 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
416 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::Fn => {
417 let operand_ty = operand.ty(cx.mir, cx.tcx);
418 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
419 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
420 match (cast_in, cast_out) {
421 (CastTy::Ptr(_), CastTy::Int(_)) |
422 (CastTy::FnPtr, CastTy::Int(_)) => {
423 // in normal functions, mark such casts as not promotable
430 Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::Fn => {
431 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.mir, cx.tcx).sty {
432 assert!(op == BinOp::Eq || op == BinOp::Ne ||
433 op == BinOp::Le || op == BinOp::Lt ||
434 op == BinOp::Ge || op == BinOp::Gt ||
435 op == BinOp::Offset);
437 // raw pointer operations are not allowed inside promoteds
442 Rvalue::NullaryOp(NullOp::Box, _) => return true,
447 Self::in_rvalue_structurally(cx, rvalue)
451 cx: &ConstCx<'_, 'tcx>,
452 callee: &Operand<'tcx>,
453 args: &[Operand<'tcx>],
454 _return_ty: Ty<'tcx>,
456 let fn_ty = callee.ty(cx.mir, cx.tcx);
458 ty::FnDef(def_id, _) => {
459 match cx.tcx.fn_sig(def_id).abi() {
461 Abi::PlatformIntrinsic => {
462 assert!(!cx.tcx.is_const_fn(def_id));
463 match &cx.tcx.item_name(def_id).as_str()[..] {
482 | "add_with_overflow"
483 | "sub_with_overflow"
484 | "mul_with_overflow"
495 cx.tcx.is_const_fn(def_id) ||
496 cx.tcx.is_unstable_const_fn(def_id).is_some() ||
497 cx.is_const_panic_fn(def_id);
507 Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
511 // Refers to temporaries which cannot be promoted as
512 // promote_consts decided they weren't simple enough.
513 // FIXME(oli-obk,eddyb): Remove this flag entirely and
514 // solely process this information via `IsNotConst`.
515 struct IsNotPromotable;
517 impl Qualif for IsNotPromotable {
518 const IDX: usize = 3;
521 cx: &ConstCx<'_, 'tcx>,
522 callee: &Operand<'tcx>,
523 args: &[Operand<'tcx>],
524 _return_ty: Ty<'tcx>,
526 if cx.mode == Mode::Fn {
527 if let ty::FnDef(def_id, _) = callee.ty(cx.mir, cx.tcx).sty {
528 // Never promote runtime `const fn` calls of
529 // functions without `#[rustc_promotable]`.
530 if !cx.tcx.is_promotable_const_fn(def_id) {
536 Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
540 // Ensure the `IDX` values are sequential (`0..QUALIF_COUNT`).
541 macro_rules! static_assert_seq_qualifs {
542 ($i:expr => $first:ident $(, $rest:ident)*) => {
543 static_assert!(SEQ_QUALIFS: {
544 static_assert_seq_qualifs!($i + 1 => $($rest),*);
550 static_assert!(SEQ_QUALIFS: QUALIF_COUNT == $i);
553 static_assert_seq_qualifs!(0 => HasMutInterior, NeedsDrop, IsNotConst, IsNotPromotable);
555 impl ConstCx<'_, 'tcx> {
556 fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif<bool> {
557 let mut qualifs = PerQualif::default();
558 qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false);
559 qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false);
560 qualifs[IsNotConst] = IsNotConst::in_any_value_of_ty(self, ty).unwrap_or(false);
561 qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
565 fn qualifs_in_local(&self, local: Local) -> PerQualif<bool> {
566 let mut qualifs = PerQualif::default();
567 qualifs[HasMutInterior] = HasMutInterior::in_local(self, local);
568 qualifs[NeedsDrop] = NeedsDrop::in_local(self, local);
569 qualifs[IsNotConst] = IsNotConst::in_local(self, local);
570 qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local);
574 fn qualifs_in_value(&self, source: ValueSource<'_, 'tcx>) -> PerQualif<bool> {
575 let mut qualifs = PerQualif::default();
576 qualifs[HasMutInterior] = HasMutInterior::in_value(self, source);
577 qualifs[NeedsDrop] = NeedsDrop::in_value(self, source);
578 qualifs[IsNotConst] = IsNotConst::in_value(self, source);
579 qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source);
584 struct Checker<'a, 'tcx> {
585 cx: ConstCx<'a, 'tcx>,
589 rpo: ReversePostorder<'a, 'tcx>,
591 temp_promotion_state: IndexVec<Local, TempState>,
592 promotion_candidates: Vec<Candidate>,
595 macro_rules! unleash_miri {
597 if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
598 $this.tcx.sess.span_warn($this.span, "skipping const checks");
604 impl Deref for Checker<'a, 'tcx> {
605 type Target = ConstCx<'a, 'tcx>;
607 fn deref(&self) -> &Self::Target {
612 impl<'a, 'tcx> Checker<'a, 'tcx> {
613 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
618 assert!(def_id.is_local());
619 let mut rpo = traversal::reverse_postorder(mir);
620 let temps = promote_consts::collect_temps(mir, &mut rpo);
623 let param_env = tcx.param_env(def_id);
625 let mut cx = ConstCx {
630 per_local: PerQualif::new(BitSet::new_empty(mir.local_decls.len())),
633 for (local, decl) in mir.local_decls.iter_enumerated() {
634 match mir.local_kind(local) {
636 let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty);
637 for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 {
639 per_local.insert(local);
642 cx.per_local[IsNotPromotable].insert(local);
645 LocalKind::Var if mode == Mode::Fn => {
646 cx.per_local[IsNotConst].insert(local);
649 LocalKind::Temp if !temps[local].is_promotable() => {
650 cx.per_local[IsNotPromotable].insert(local);
662 temp_promotion_state: temps,
663 promotion_candidates: vec![]
667 // FIXME(eddyb) we could split the errors into meaningful
668 // categories, but enabling full miri would make that
669 // slightly pointless (even with feature-gating).
670 fn not_const(&mut self) {
672 if self.mode != Mode::Fn {
673 let mut err = struct_span_err!(
677 "{} contains unimplemented expression type",
680 if self.tcx.sess.teach(&err.get_code().unwrap()) {
681 err.note("A function call isn't allowed in the const's initialization expression \
682 because the expression's value must be known at compile-time.");
683 err.note("Remember: you can't use a function call inside a const's initialization \
684 expression! However, you can use it anywhere else.");
690 /// Assigns an rvalue/call qualification to the given destination.
691 fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) {
692 trace!("assign: {:?} <- {:?}", dest, source);
694 let mut qualifs = self.qualifs_in_value(source);
696 if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
697 // Getting `true` from `HasMutInterior::in_rvalue` means
698 // the borrowed place is disallowed from being borrowed,
699 // due to either a mutable borrow (with some exceptions),
700 // or an shared borrow of a value with interior mutability.
701 // Then `HasMutInterior` is replaced with `IsNotConst`,
702 // to avoid duplicate errors (e.g. from reborrowing).
703 if qualifs[HasMutInterior] {
704 qualifs[HasMutInterior] = false;
705 qualifs[IsNotConst] = true;
707 if self.mode != Mode::Fn {
708 if let BorrowKind::Mut { .. } = kind {
709 let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
710 "references in {}s may only refer \
711 to immutable values", self.mode);
712 err.span_label(self.span, format!("{}s require immutable values",
714 if self.tcx.sess.teach(&err.get_code().unwrap()) {
715 err.note("References in statics and constants may only refer to \
716 immutable values.\n\n\
717 Statics are shared everywhere, and if they refer to \
718 mutable data one might violate memory safety since \
719 holding multiple mutable references to shared data is \
721 If you really want global mutable state, try using \
722 static mut or a global UnsafeCell.");
726 span_err!(self.tcx.sess, self.span, E0492,
727 "cannot borrow a constant which may contain \
728 interior mutability, create a static instead");
732 // We might have a candidate for promotion.
733 let candidate = Candidate::Ref(location);
734 // We can only promote interior borrows of promotable temps.
735 let mut place = place;
736 while let Place::Projection(ref proj) = *place {
737 if proj.elem == ProjectionElem::Deref {
742 debug!("qualify_consts: promotion candidate: place={:?}", place);
743 if let Place::Base(PlaceBase::Local(local)) = *place {
744 if self.mir.local_kind(local) == LocalKind::Temp {
745 debug!("qualify_consts: promotion candidate: local={:?}", local);
746 // The borrowed place doesn't have `HasMutInterior`
747 // (from `in_rvalue`), so we can safely ignore
748 // `HasMutInterior` from the local's qualifications.
749 // This allows borrowing fields which don't have
750 // `HasMutInterior`, from a type that does, e.g.:
751 // `let _: &'static _ = &(Cell::new(1), 2).1;`
752 let mut local_qualifs = self.qualifs_in_local(local);
753 local_qualifs[HasMutInterior] = false;
754 if !local_qualifs.0.iter().any(|&qualif| qualif) {
755 debug!("qualify_consts: promotion candidate: {:?}", candidate);
756 self.promotion_candidates.push(candidate);
766 // We treat all locals equal in constants
767 Place::Base(PlaceBase::Local(index)) => break *index,
768 // projections are transparent for assignments
769 // we qualify the entire destination at once, even if just a field would have
770 // stricter qualification
771 Place::Projection(proj) => {
772 // Catch more errors in the destination. `visit_place` also checks various
773 // projection rules like union field access and raw pointer deref
776 PlaceContext::MutatingUse(MutatingUseContext::Store),
781 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
782 bug!("promoteds don't exist yet during promotion"),
783 Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
784 // Catch more errors in the destination. `visit_place` also checks that we
785 // do not try to access statics from constants or try to mutate statics
788 PlaceContext::MutatingUse(MutatingUseContext::Store),
796 let kind = self.mir.local_kind(index);
797 debug!("store to {:?} {:?}", kind, index);
799 // Only handle promotable temps in non-const functions.
800 if self.mode == Mode::Fn {
801 if kind != LocalKind::Temp ||
802 !self.temp_promotion_state[index].is_promotable() {
807 // this is overly restrictive, because even full assignments do not clear the qualif
808 // While we could special case full assignments, this would be inconsistent with
809 // aggregates where we overwrite all fields via assignments, which would not get
811 for (per_local, qualif) in &mut self.cx.per_local.as_mut().zip(qualifs).0 {
813 per_local.insert(index);
817 // Ensure the `IsNotPromotable` qualification is preserved.
818 // NOTE(eddyb) this is actually unnecessary right now, as
819 // we never replace the local's qualif, but we might in
820 // the future, and so it serves to catch changes that unset
821 // important bits (in which case, asserting `contains` could
822 // be replaced with calling `insert` to re-set the bit).
823 if kind == LocalKind::Temp {
824 if !self.temp_promotion_state[index].is_promotable() {
825 assert!(self.cx.per_local[IsNotPromotable].contains(index));
830 /// Check a whole const, static initializer or const fn.
831 fn check_const(&mut self) -> (u8, Lrc<BitSet<Local>>) {
832 debug!("const-checking {} {:?}", self.mode, self.def_id);
836 let mut seen_blocks = BitSet::new_empty(mir.basic_blocks().len());
837 let mut bb = START_BLOCK;
839 seen_blocks.insert(bb.index());
841 self.visit_basic_block_data(bb, &mir[bb]);
843 let target = match mir[bb].terminator().kind {
844 TerminatorKind::Goto { target } |
845 TerminatorKind::Drop { target, .. } |
846 TerminatorKind::Assert { target, .. } |
847 TerminatorKind::Call { destination: Some((_, target)), .. } => {
851 // Non-terminating calls cannot produce any value.
852 TerminatorKind::Call { destination: None, .. } => {
856 TerminatorKind::SwitchInt {..} |
857 TerminatorKind::DropAndReplace { .. } |
858 TerminatorKind::Resume |
859 TerminatorKind::Abort |
860 TerminatorKind::GeneratorDrop |
861 TerminatorKind::Yield { .. } |
862 TerminatorKind::Unreachable |
863 TerminatorKind::FalseEdges { .. } |
864 TerminatorKind::FalseUnwind { .. } => None,
866 TerminatorKind::Return => {
873 Some(target) if !seen_blocks.contains(target.index()) => {
884 // Collect all the temps we need to promote.
885 let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
887 debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
888 for candidate in &self.promotion_candidates {
890 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
891 match self.mir[bb].statements[stmt_idx].kind {
892 StatementKind::Assign(
894 box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
896 promoted_temps.insert(index);
901 Candidate::Argument { .. } => {}
905 let promoted_temps = Lrc::new(promoted_temps);
907 let mut qualifs = self.qualifs_in_local(RETURN_PLACE);
909 // Account for errors in consts by using the
910 // conservative type qualification instead.
911 if qualifs[IsNotConst] {
912 qualifs = self.qualifs_in_any_value_of_ty(mir.return_ty());
915 (qualifs.encode_to_bits(), promoted_temps)
919 /// Checks MIR for const-correctness, using `ConstCx`
920 /// for value qualifications, and accumulates writes of
921 /// rvalue/call results to locals, in `local_qualif`.
922 /// For functions (constant or not), it also records
923 /// candidates for promotion in `promotion_candidates`.
924 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
925 fn visit_place(&mut self,
927 context: PlaceContext<'tcx>,
928 location: Location) {
929 debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
930 self.super_place(place, context, location);
932 Place::Base(PlaceBase::Local(_)) => {}
933 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) => {
936 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
940 .any(|attr| attr.check_name("thread_local")) {
941 if self.mode != Mode::Fn {
942 span_err!(self.tcx.sess, self.span, E0625,
943 "thread-local statics cannot be \
944 accessed at compile-time");
949 // Only allow statics (not consts) to refer to other statics.
950 if self.mode == Mode::Static || self.mode == Mode::StaticMut {
951 if self.mode == Mode::Static && context.is_mutating_use() {
952 // this is not strictly necessary as miri will also bail out
953 // For interior mutability we can't really catch this statically as that
954 // goes through raw pointers and intermediate temporaries, so miri has
955 // to catch this anyway
956 self.tcx.sess.span_err(
958 "cannot mutate statics in the initializer of another static",
965 if self.mode != Mode::Fn {
966 let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
967 "{}s cannot refer to statics, use \
968 a constant instead", self.mode);
969 if self.tcx.sess.teach(&err.get_code().unwrap()) {
971 "Static and const variables can refer to other const variables. But a \
972 const variable cannot refer to a static variable."
975 "To fix this, the value can be extracted as a const and then used."
981 Place::Projection(ref proj) => {
983 ProjectionElem::Deref => {
984 if context.is_mutating_use() {
985 // `not_const` errors out in const contexts
988 let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
992 if let ty::RawPtr(_) = base_ty.sty {
993 if !self.tcx.features().const_raw_ptr_deref {
995 &self.tcx.sess.parse_sess, "const_raw_ptr_deref",
996 self.span, GateIssue::Language,
998 "dereferencing raw pointers in {}s is unstable",
1008 ProjectionElem::ConstantIndex {..} |
1009 ProjectionElem::Subslice {..} |
1010 ProjectionElem::Field(..) |
1011 ProjectionElem::Index(_) => {
1012 let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
1013 if let Some(def) = base_ty.ty_adt_def() {
1017 if !self.tcx.features().const_fn_union {
1019 &self.tcx.sess.parse_sess, "const_fn_union",
1020 self.span, GateIssue::Language,
1021 "unions in const fn are unstable",
1036 ProjectionElem::Downcast(..) => {
1044 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
1045 debug!("visit_operand: operand={:?} location={:?}", operand, location);
1046 self.super_operand(operand, location);
1049 Operand::Move(ref place) => {
1050 // Mark the consumed locals to indicate later drops are noops.
1051 if let Place::Base(PlaceBase::Local(local)) = *place {
1052 self.cx.per_local[NeedsDrop].remove(local);
1056 Operand::Constant(_) => {}
1060 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
1061 debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
1063 // Check nested operands and places.
1064 if let Rvalue::Ref(region, kind, ref place) = *rvalue {
1065 // Special-case reborrows.
1066 let mut is_reborrow = false;
1067 if let Place::Projection(ref proj) = *place {
1068 if let ProjectionElem::Deref = proj.elem {
1069 let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
1070 if let ty::Ref(..) = base_ty.sty {
1077 let ctx = match kind {
1078 BorrowKind::Shared => PlaceContext::NonMutatingUse(
1079 NonMutatingUseContext::SharedBorrow(region),
1081 BorrowKind::Shallow => PlaceContext::NonMutatingUse(
1082 NonMutatingUseContext::ShallowBorrow(region),
1084 BorrowKind::Unique => PlaceContext::NonMutatingUse(
1085 NonMutatingUseContext::UniqueBorrow(region),
1087 BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
1088 MutatingUseContext::Borrow(region),
1091 self.super_place(place, ctx, location);
1093 self.super_rvalue(rvalue, location);
1096 self.super_rvalue(rvalue, location);
1101 Rvalue::Repeat(..) |
1102 Rvalue::UnaryOp(UnOp::Neg, _) |
1103 Rvalue::UnaryOp(UnOp::Not, _) |
1104 Rvalue::NullaryOp(NullOp::SizeOf, _) |
1105 Rvalue::CheckedBinaryOp(..) |
1106 Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
1107 Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
1108 Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
1109 Rvalue::Cast(CastKind::Unsize, ..) |
1110 Rvalue::Cast(CastKind::MutToConstPointer, ..) |
1111 Rvalue::Discriminant(..) |
1114 Rvalue::Aggregate(..) => {}
1116 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
1117 let operand_ty = operand.ty(self.mir, self.tcx);
1118 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
1119 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
1120 match (cast_in, cast_out) {
1121 (CastTy::Ptr(_), CastTy::Int(_)) |
1122 (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => {
1123 unleash_miri!(self);
1124 if !self.tcx.features().const_raw_ptr_to_usize_cast {
1125 // in const fn and constants require the feature gate
1126 // FIXME: make it unsafe inside const fn and constants
1128 &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast",
1129 self.span, GateIssue::Language,
1131 "casting pointers to integers in {}s is unstable",
1141 Rvalue::BinaryOp(op, ref lhs, _) => {
1142 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty {
1143 assert!(op == BinOp::Eq || op == BinOp::Ne ||
1144 op == BinOp::Le || op == BinOp::Lt ||
1145 op == BinOp::Ge || op == BinOp::Gt ||
1146 op == BinOp::Offset);
1148 unleash_miri!(self);
1149 if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers {
1150 // require the feature gate inside constants and const fn
1151 // FIXME: make it unsafe to use these operations
1153 &self.tcx.sess.parse_sess,
1154 "const_compare_raw_pointers",
1156 GateIssue::Language,
1157 &format!("comparing raw pointers inside {}", self.mode),
1163 Rvalue::NullaryOp(NullOp::Box, _) => {
1164 unleash_miri!(self);
1165 if self.mode != Mode::Fn {
1166 let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
1167 "allocations are not allowed in {}s", self.mode);
1168 err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
1169 if self.tcx.sess.teach(&err.get_code().unwrap()) {
1171 "The value of statics and constants must be known at compile time, \
1172 and they live for the entire lifetime of a program. Creating a boxed \
1173 value allocates memory on the heap at runtime, and therefore cannot \
1174 be done at compile time."
1183 fn visit_terminator_kind(&mut self,
1185 kind: &TerminatorKind<'tcx>,
1186 location: Location) {
1187 debug!("visit_terminator_kind: bb={:?} kind={:?} location={:?}", bb, kind, location);
1188 if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
1189 if let Some((ref dest, _)) = *destination {
1190 self.assign(dest, ValueSource::Call {
1193 return_ty: dest.ty(self.mir, self.tcx).to_ty(self.tcx),
1197 let fn_ty = func.ty(self.mir, self.tcx);
1198 let mut callee_def_id = None;
1199 let mut is_shuffle = false;
1201 ty::FnDef(def_id, _) => {
1202 callee_def_id = Some(def_id);
1203 match self.tcx.fn_sig(def_id).abi() {
1204 Abi::RustIntrinsic |
1205 Abi::PlatformIntrinsic => {
1206 assert!(!self.tcx.is_const_fn(def_id));
1207 match &self.tcx.item_name(def_id).as_str()[..] {
1208 // special intrinsic that can be called diretly without an intrinsic
1209 // feature gate needs a language feature gate
1211 // never promote transmute calls
1212 if self.mode != Mode::Fn {
1213 // const eval transmute calls only with the feature gate
1214 if !self.tcx.features().const_transmute {
1216 &self.tcx.sess.parse_sess, "const_transmute",
1217 self.span, GateIssue::Language,
1218 &format!("The use of std::mem::transmute() \
1219 is gated in {}s", self.mode));
1224 name if name.starts_with("simd_shuffle") => {
1228 // no need to check feature gates, intrinsics are only callable
1229 // from the libstd or with forever unstable feature gates
1234 // In normal functions no calls are feature-gated.
1235 if self.mode != Mode::Fn {
1236 let unleash_miri = self
1241 .unleash_the_miri_inside_of_you;
1242 if self.tcx.is_const_fn(def_id) || unleash_miri {
1243 // stable const fns or unstable const fns
1244 // with their feature gate active
1245 // FIXME(eddyb) move stability checks from `is_const_fn` here.
1246 } else if self.is_const_panic_fn(def_id) {
1247 // Check the const_panic feature gate.
1248 // FIXME: cannot allow this inside `allow_internal_unstable`
1249 // because that would make `panic!` insta stable in constants,
1250 // since the macro is marked with the attribute.
1251 if !self.tcx.features().const_panic {
1252 // Don't allow panics in constants without the feature gate.
1254 &self.tcx.sess.parse_sess,
1257 GateIssue::Language,
1258 &format!("panicking in {}s is unstable", self.mode),
1261 } else if let Some(feature)
1262 = self.tcx.is_unstable_const_fn(def_id) {
1263 // Check `#[unstable]` const fns or `#[rustc_const_unstable]`
1264 // functions without the feature gate active in this crate in
1265 // order to report a better error message than the one below.
1266 if !self.span.allows_unstable(&feature.as_str()) {
1267 let mut err = self.tcx.sess.struct_span_err(self.span,
1268 &format!("`{}` is not yet stable as a const fn",
1269 self.tcx.def_path_str(def_id)));
1270 if nightly_options::is_nightly_build() {
1272 "add `#![feature({})]` to the \
1273 crate attributes to enable",
1279 let mut err = struct_span_err!(
1283 "calls in {}s are limited to constant functions, \
1284 tuple structs and tuple variants",
1294 if self.mode != Mode::Fn {
1295 let mut err = self.tcx.sess.struct_span_err(
1297 &format!("function pointers are not allowed in const fn"));
1306 if self.mode == Mode::Fn {
1307 let constant_args = callee_def_id.and_then(|id| {
1308 args_required_const(self.tcx, id)
1309 }).unwrap_or_default();
1310 for (i, arg) in args.iter().enumerate() {
1311 if !(is_shuffle && i == 2 || constant_args.contains(&i)) {
1315 let candidate = Candidate::Argument { bb, index: i };
1316 // Since the argument is required to be constant,
1317 // we care about constness, not promotability.
1318 // If we checked for promotability, we'd miss out on
1319 // the results of function calls (which are never promoted
1320 // in runtime code).
1321 // This is not a problem, because the argument explicitly
1322 // requests constness, in contrast to regular promotion
1323 // which happens even without the user requesting it.
1324 // We can error out with a hard error if the argument is not
1326 if !IsNotConst::in_operand(self, arg) {
1327 debug!("visit_terminator_kind: candidate={:?}", candidate);
1328 self.promotion_candidates.push(candidate);
1331 span_err!(self.tcx.sess, self.span, E0526,
1332 "shuffle indices are not constant");
1334 self.tcx.sess.span_err(self.span,
1335 &format!("argument {} is required to be a constant",
1342 // Check callee and argument operands.
1343 self.visit_operand(func, location);
1345 self.visit_operand(arg, location);
1347 } else if let TerminatorKind::Drop { location: ref place, .. } = *kind {
1348 self.super_terminator_kind(bb, kind, location);
1350 // Deny *any* live drops anywhere other than functions.
1351 if self.mode != Mode::Fn {
1352 unleash_miri!(self);
1353 // HACK(eddyb): emulate a bit of dataflow analysis,
1354 // conservatively, that drop elaboration will do.
1355 let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place {
1356 if NeedsDrop::in_local(self, local) {
1357 Some(self.mir.local_decls[local].source_info.span)
1365 if let Some(span) = needs_drop {
1366 // Double-check the type being dropped, to minimize false positives.
1367 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
1368 if ty.needs_drop(self.tcx, self.param_env) {
1369 struct_span_err!(self.tcx.sess, span, E0493,
1370 "destructors cannot be evaluated at compile-time")
1371 .span_label(span, format!("{}s cannot evaluate destructors",
1378 // Qualify any operands inside other terminators.
1379 self.super_terminator_kind(bb, kind, location);
1383 fn visit_assign(&mut self,
1386 rvalue: &Rvalue<'tcx>,
1387 location: Location) {
1388 debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
1389 self.assign(dest, ValueSource::Rvalue(rvalue), location);
1391 self.visit_rvalue(rvalue, location);
1394 fn visit_source_info(&mut self, source_info: &SourceInfo) {
1395 debug!("visit_source_info: source_info={:?}", source_info);
1396 self.span = source_info.span;
1399 fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) {
1400 debug!("visit_statement: bb={:?} statement={:?} location={:?}", bb, statement, location);
1401 match statement.kind {
1402 StatementKind::Assign(..) => {
1403 self.super_statement(bb, statement, location);
1405 // FIXME(eddyb) should these really do nothing?
1406 StatementKind::FakeRead(..) |
1407 StatementKind::SetDiscriminant { .. } |
1408 StatementKind::StorageLive(_) |
1409 StatementKind::StorageDead(_) |
1410 StatementKind::InlineAsm {..} |
1411 StatementKind::Retag { .. } |
1412 StatementKind::AscribeUserType(..) |
1413 StatementKind::Nop => {}
1417 fn visit_terminator(&mut self,
1419 terminator: &Terminator<'tcx>,
1420 location: Location) {
1421 debug!("visit_terminator: bb={:?} terminator={:?} location={:?}", bb, terminator, location);
1422 self.super_terminator(bb, terminator, location);
1426 pub fn provide(providers: &mut Providers<'_>) {
1427 *providers = Providers {
1433 fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1435 -> (u8, Lrc<BitSet<Local>>) {
1436 // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
1437 // cannot yet be stolen), because `mir_validated()`, which steals
1438 // from `mir_const(), forces this query to execute before
1439 // performing the steal.
1440 let mir = &tcx.mir_const(def_id).borrow();
1442 if mir.return_ty().references_error() {
1443 tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors");
1444 return (1 << IsNotConst::IDX, Lrc::new(BitSet::new_empty(0)));
1447 Checker::new(tcx, def_id, mir, Mode::Const).check_const()
1450 pub struct QualifyAndPromoteConstants;
1452 impl MirPass for QualifyAndPromoteConstants {
1453 fn run_pass<'a, 'tcx>(&self,
1454 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1455 src: MirSource<'tcx>,
1456 mir: &mut Mir<'tcx>) {
1457 // There's not really any point in promoting errorful MIR.
1458 if mir.return_ty().references_error() {
1459 tcx.sess.delay_span_bug(mir.span, "QualifyAndPromoteConstants: Mir had errors");
1463 if src.promoted.is_some() {
1467 let def_id = src.def_id();
1468 let id = tcx.hir().as_local_hir_id(def_id).unwrap();
1469 let mut const_promoted_temps = None;
1470 let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
1471 hir::BodyOwnerKind::Closure => Mode::Fn,
1472 hir::BodyOwnerKind::Fn => {
1473 if tcx.is_const_fn(def_id) {
1479 hir::BodyOwnerKind::Const => {
1480 const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1483 hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
1484 hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
1487 debug!("run_pass: mode={:?}", mode);
1488 if mode == Mode::Fn || mode == Mode::ConstFn {
1489 // This is ugly because Checker holds onto mir,
1490 // which can't be mutated until its scope ends.
1491 let (temps, candidates) = {
1492 let mut checker = Checker::new(tcx, def_id, mir, mode);
1493 if mode == Mode::ConstFn {
1494 if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
1495 checker.check_const();
1496 } else if tcx.is_min_const_fn(def_id) {
1497 // enforce `min_const_fn` for stable const fns
1498 use super::qualify_min_const_fn::is_min_const_fn;
1499 if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
1500 let mut diag = struct_span_err!(
1504 "{} (see issue #57563)",
1508 "add #![feature(const_fn)] to the crate attributes to enable",
1512 // this should not produce any errors, but better safe than sorry
1514 checker.check_const();
1517 // Enforce a constant-like CFG for `const fn`.
1518 checker.check_const();
1521 while let Some((bb, data)) = checker.rpo.next() {
1522 checker.visit_basic_block_data(bb, data);
1526 (checker.temp_promotion_state, checker.promotion_candidates)
1529 // Do the actual promotion, now that we know what's viable.
1530 promote_consts::promote_candidates(mir, tcx, temps, candidates);
1532 if !mir.control_flow_destroyed.is_empty() {
1533 let mut locals = mir.vars_iter();
1534 if let Some(local) = locals.next() {
1535 let span = mir.local_decls[local].source_info.span;
1536 let mut error = tcx.sess.struct_span_err(
1539 "new features like let bindings are not permitted in {}s \
1540 which also use short circuiting operators",
1544 for (span, kind) in mir.control_flow_destroyed.iter() {
1547 &format!("use of {} here does not actually short circuit due to \
1548 the const evaluator presently not being able to do control flow. \
1549 See https://github.com/rust-lang/rust/issues/49146 for more \
1550 information.", kind),
1553 for local in locals {
1554 let span = mir.local_decls[local].source_info.span;
1557 "more locals defined here",
1563 let promoted_temps = if mode == Mode::Const {
1564 // Already computed by `mir_const_qualif`.
1565 const_promoted_temps.unwrap()
1567 Checker::new(tcx, def_id, mir, mode).check_const().1
1570 // In `const` and `static` everything without `StorageDead`
1571 // is `'static`, we don't have to create promoted MIR fragments,
1572 // just remove `Drop` and `StorageDead` on "promoted" locals.
1573 debug!("run_pass: promoted_temps={:?}", promoted_temps);
1574 for block in mir.basic_blocks_mut() {
1575 block.statements.retain(|statement| {
1576 match statement.kind {
1577 StatementKind::StorageDead(index) => {
1578 !promoted_temps.contains(index)
1583 let terminator = block.terminator_mut();
1584 match terminator.kind {
1585 TerminatorKind::Drop {
1586 location: Place::Base(PlaceBase::Local(index)),
1590 if promoted_temps.contains(index) {
1591 terminator.kind = TerminatorKind::Goto {
1601 // Statics must be Sync.
1602 if mode == Mode::Static {
1603 // `#[thread_local]` statics don't have to be `Sync`.
1604 for attr in &tcx.get_attrs(def_id)[..] {
1605 if attr.check_name("thread_local") {
1609 let ty = mir.return_ty();
1610 tcx.infer_ctxt().enter(|infcx| {
1611 let param_env = ty::ParamEnv::empty();
1612 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
1613 let mut fulfillment_cx = traits::FulfillmentContext::new();
1614 fulfillment_cx.register_bound(&infcx,
1617 tcx.require_lang_item(lang_items::SyncTraitLangItem),
1619 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
1620 infcx.report_fulfillment_errors(&err, None, false);
1627 fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
1628 let attrs = tcx.get_attrs(def_id);
1629 let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?;
1630 let mut ret = FxHashSet::default();
1631 for meta in attr.meta_item_list()? {
1632 match meta.literal()?.node {
1633 LitKind::Int(a, _) => { ret.insert(a as usize); }