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_target::spec::abi::Abi;
12 use rustc::hir::def_id::DefId;
13 use rustc::traits::{self, TraitEngine};
14 use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
15 use rustc::ty::cast::CastTy;
16 use rustc::ty::query::Providers;
18 use rustc::mir::interpret::ConstValue;
19 use rustc::mir::traversal::ReversePostorder;
20 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
21 use rustc::middle::lang_items;
22 use rustc::session::config::nightly_options;
23 use syntax::ast::LitKind;
24 use syntax::feature_gate::{emit_feature_err, GateIssue};
25 use syntax::symbol::sym;
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>,
116 body: &'a Body<'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: &Projection<'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.body, 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: &Projection<'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.body, cx.tcx).ty;
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.body, cx.tcx).ty;
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 match len.assert_usize(cx.tcx) {
320 Some(0) if cx.mode == Mode::Fn => {},
329 Rvalue::Aggregate(ref kind, _) => {
330 if let AggregateKind::Adt(def, ..) = **kind {
331 if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() {
332 let ty = rvalue.ty(cx.body, cx.tcx);
333 assert_eq!(Self::in_any_value_of_ty(cx, ty), Some(true));
342 Self::in_rvalue_structurally(cx, rvalue)
346 // Constant containing an ADT that implements Drop.
349 impl Qualif for NeedsDrop {
350 const IDX: usize = 1;
352 fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> Option<bool> {
353 Some(ty.needs_drop(cx.tcx, cx.param_env))
356 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
357 if let Rvalue::Aggregate(ref kind, _) = *rvalue {
358 if let AggregateKind::Adt(def, ..) = **kind {
359 if def.has_dtor(cx.tcx) {
365 Self::in_rvalue_structurally(cx, rvalue)
369 // Not promotable at all - non-`const fn` calls, asm!,
370 // pointer comparisons, ptr-to-int casts, etc.
371 struct IsNotPromotable;
373 impl Qualif for IsNotPromotable {
374 const IDX: usize = 2;
376 fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool {
378 StaticKind::Promoted(_) => unreachable!(),
379 StaticKind::Static(def_id) => {
380 // Only allow statics (not consts) to refer to other statics.
381 let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut;
384 cx.tcx.get_attrs(def_id).iter().any(
385 |attr| attr.check_name(sym::thread_local)
391 fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'tcx>) -> bool {
393 ProjectionElem::Deref |
394 ProjectionElem::Downcast(..) => return true,
396 ProjectionElem::ConstantIndex {..} |
397 ProjectionElem::Subslice {..} |
398 ProjectionElem::Index(_) => {}
400 ProjectionElem::Field(..) => {
401 if cx.mode == Mode::Fn {
402 let base_ty = proj.base.ty(cx.body, cx.tcx).ty;
403 if let Some(def) = base_ty.ty_adt_def() {
412 Self::in_projection_structurally(cx, proj)
415 fn in_rvalue(cx: &ConstCx<'_, 'tcx>, rvalue: &Rvalue<'tcx>) -> bool {
417 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if cx.mode == Mode::Fn => {
418 let operand_ty = operand.ty(cx.body, cx.tcx);
419 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
420 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
421 match (cast_in, cast_out) {
422 (CastTy::Ptr(_), CastTy::Int(_)) |
423 (CastTy::FnPtr, CastTy::Int(_)) => {
424 // in normal functions, mark such casts as not promotable
431 Rvalue::BinaryOp(op, ref lhs, _) if cx.mode == Mode::Fn => {
432 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(cx.body, cx.tcx).sty {
433 assert!(op == BinOp::Eq || op == BinOp::Ne ||
434 op == BinOp::Le || op == BinOp::Lt ||
435 op == BinOp::Ge || op == BinOp::Gt ||
436 op == BinOp::Offset);
438 // raw pointer operations are not allowed inside promoteds
443 Rvalue::NullaryOp(NullOp::Box, _) => return true,
448 Self::in_rvalue_structurally(cx, rvalue)
452 cx: &ConstCx<'_, 'tcx>,
453 callee: &Operand<'tcx>,
454 args: &[Operand<'tcx>],
455 _return_ty: Ty<'tcx>,
457 let fn_ty = callee.ty(cx.body, cx.tcx);
459 ty::FnDef(def_id, _) => {
460 match cx.tcx.fn_sig(def_id).abi() {
462 Abi::PlatformIntrinsic => {
463 assert!(!cx.tcx.is_const_fn(def_id));
464 match &cx.tcx.item_name(def_id).as_str()[..] {
483 | "add_with_overflow"
484 | "sub_with_overflow"
485 | "mul_with_overflow"
496 cx.tcx.is_const_fn(def_id) ||
497 cx.tcx.is_unstable_const_fn(def_id).is_some() ||
498 cx.is_const_panic_fn(def_id);
508 Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
512 /// Refers to temporaries which cannot be promoted *implicitly*.
513 /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`.
514 /// Inside a const context all constness rules
515 /// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior
516 /// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively).
517 /// Implicit promotion inside regular functions does not happen if `const fn` calls are involved,
518 /// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses
519 /// being compared inside the function.
520 struct IsNotImplicitlyPromotable;
522 impl Qualif for IsNotImplicitlyPromotable {
523 const IDX: usize = 3;
526 cx: &ConstCx<'_, 'tcx>,
527 callee: &Operand<'tcx>,
528 args: &[Operand<'tcx>],
529 _return_ty: Ty<'tcx>,
531 if cx.mode == Mode::Fn {
532 if let ty::FnDef(def_id, _) = callee.ty(cx.body, cx.tcx).sty {
533 // Never promote runtime `const fn` calls of
534 // functions without `#[rustc_promotable]`.
535 if !cx.tcx.is_promotable_const_fn(def_id) {
541 Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
545 // Ensure the `IDX` values are sequential (`0..QUALIF_COUNT`).
546 macro_rules! static_assert_seq_qualifs {
547 ($i:expr => $first:ident $(, $rest:ident)*) => {
549 static_assert_seq_qualifs!($i + 1 => $($rest),*);
555 static_assert!(QUALIF_COUNT == $i);
558 static_assert_seq_qualifs!(
559 0 => HasMutInterior, NeedsDrop, IsNotPromotable, IsNotImplicitlyPromotable
562 impl ConstCx<'_, 'tcx> {
563 fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif<bool> {
564 let mut qualifs = PerQualif::default();
565 qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false);
566 qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false);
567 qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
568 qualifs[IsNotImplicitlyPromotable] =
569 IsNotImplicitlyPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
573 fn qualifs_in_local(&self, local: Local) -> PerQualif<bool> {
574 let mut qualifs = PerQualif::default();
575 qualifs[HasMutInterior] = HasMutInterior::in_local(self, local);
576 qualifs[NeedsDrop] = NeedsDrop::in_local(self, local);
577 qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local);
578 qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_local(self, local);
582 fn qualifs_in_value(&self, source: ValueSource<'_, 'tcx>) -> PerQualif<bool> {
583 let mut qualifs = PerQualif::default();
584 qualifs[HasMutInterior] = HasMutInterior::in_value(self, source);
585 qualifs[NeedsDrop] = NeedsDrop::in_value(self, source);
586 qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source);
587 qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_value(self, source);
592 struct Checker<'a, 'tcx> {
593 cx: ConstCx<'a, 'tcx>,
597 rpo: ReversePostorder<'a, 'tcx>,
599 temp_promotion_state: IndexVec<Local, TempState>,
600 promotion_candidates: Vec<Candidate>,
603 macro_rules! unleash_miri {
605 if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
606 $this.tcx.sess.span_warn($this.span, "skipping const checks");
612 impl Deref for Checker<'a, 'tcx> {
613 type Target = ConstCx<'a, 'tcx>;
615 fn deref(&self) -> &Self::Target {
620 impl<'a, 'tcx> Checker<'a, 'tcx> {
621 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
623 body: &'a Body<'tcx>,
626 assert!(def_id.is_local());
627 let mut rpo = traversal::reverse_postorder(body);
628 let temps = promote_consts::collect_temps(body, &mut rpo);
631 let param_env = tcx.param_env(def_id);
633 let mut cx = ConstCx {
638 per_local: PerQualif::new(BitSet::new_empty(body.local_decls.len())),
641 for (local, decl) in body.local_decls.iter_enumerated() {
642 if let LocalKind::Arg = body.local_kind(local) {
643 let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty);
644 for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 {
646 per_local.insert(local);
650 if !temps[local].is_promotable() {
651 cx.per_local[IsNotPromotable].insert(local);
653 if let LocalKind::Var = body.local_kind(local) {
654 // Sanity check to prevent implicit and explicit promotion of
656 assert!(cx.per_local[IsNotPromotable].contains(local));
665 temp_promotion_state: temps,
666 promotion_candidates: vec![]
670 // FIXME(eddyb) we could split the errors into meaningful
671 // categories, but enabling full miri would make that
672 // slightly pointless (even with feature-gating).
673 fn not_const(&mut self) {
675 if self.mode != Mode::Fn {
676 let mut err = struct_span_err!(
680 "{} contains unimplemented expression type",
683 if self.tcx.sess.teach(&err.get_code().unwrap()) {
684 err.note("A function call isn't allowed in the const's initialization expression \
685 because the expression's value must be known at compile-time.");
686 err.note("Remember: you can't use a function call inside a const's initialization \
687 expression! However, you can use it anywhere else.");
693 /// Assigns an rvalue/call qualification to the given destination.
694 fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) {
695 trace!("assign: {:?} <- {:?}", dest, source);
697 let mut qualifs = self.qualifs_in_value(source);
699 if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
700 // Getting `true` from `HasMutInterior::in_rvalue` means
701 // the borrowed place is disallowed from being borrowed,
702 // due to either a mutable borrow (with some exceptions),
703 // or an shared borrow of a value with interior mutability.
704 // Then `HasMutInterior` is replaced with `IsNotPromotable`,
705 // to avoid duplicate errors (e.g. from reborrowing).
706 if qualifs[HasMutInterior] {
707 qualifs[HasMutInterior] = false;
708 qualifs[IsNotPromotable] = true;
710 if self.mode != Mode::Fn {
711 if let BorrowKind::Mut { .. } = kind {
712 let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
713 "references in {}s may only refer \
714 to immutable values", self.mode);
715 err.span_label(self.span, format!("{}s require immutable values",
717 if self.tcx.sess.teach(&err.get_code().unwrap()) {
718 err.note("References in statics and constants may only refer to \
719 immutable values.\n\n\
720 Statics are shared everywhere, and if they refer to \
721 mutable data one might violate memory safety since \
722 holding multiple mutable references to shared data is \
724 If you really want global mutable state, try using \
725 static mut or a global UnsafeCell.");
729 span_err!(self.tcx.sess, self.span, E0492,
730 "cannot borrow a constant which may contain \
731 interior mutability, create a static instead");
734 } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
735 // Don't promote BorrowKind::Shallow borrows, as they don't
738 // We might have a candidate for promotion.
739 let candidate = Candidate::Ref(location);
740 // We can only promote interior borrows of promotable temps.
741 let mut place = place;
742 while let Place::Projection(ref proj) = *place {
743 if proj.elem == ProjectionElem::Deref {
748 debug!("qualify_consts: promotion candidate: place={:?}", place);
749 if let Place::Base(PlaceBase::Local(local)) = *place {
750 if self.body.local_kind(local) == LocalKind::Temp {
751 debug!("qualify_consts: promotion candidate: local={:?}", local);
752 // The borrowed place doesn't have `HasMutInterior`
753 // (from `in_rvalue`), so we can safely ignore
754 // `HasMutInterior` from the local's qualifications.
755 // This allows borrowing fields which don't have
756 // `HasMutInterior`, from a type that does, e.g.:
757 // `let _: &'static _ = &(Cell::new(1), 2).1;`
758 let mut local_qualifs = self.qualifs_in_local(local);
759 local_qualifs[HasMutInterior] = false;
760 if !local_qualifs.0.iter().any(|&qualif| qualif) {
761 debug!("qualify_consts: promotion candidate: {:?}", candidate);
762 self.promotion_candidates.push(candidate);
772 // We treat all locals equal in constants
773 Place::Base(PlaceBase::Local(index)) => break *index,
774 // projections are transparent for assignments
775 // we qualify the entire destination at once, even if just a field would have
776 // stricter qualification
777 Place::Projection(proj) => {
778 // Catch more errors in the destination. `visit_place` also checks various
779 // projection rules like union field access and raw pointer deref
782 PlaceContext::MutatingUse(MutatingUseContext::Store),
787 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
788 bug!("promoteds don't exist yet during promotion"),
789 Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
790 // Catch more errors in the destination. `visit_place` also checks that we
791 // do not try to access statics from constants or try to mutate statics
794 PlaceContext::MutatingUse(MutatingUseContext::Store),
802 let kind = self.body.local_kind(index);
803 debug!("store to {:?} {:?}", kind, index);
805 // Only handle promotable temps in non-const functions.
806 if self.mode == Mode::Fn {
807 if kind != LocalKind::Temp ||
808 !self.temp_promotion_state[index].is_promotable() {
813 // this is overly restrictive, because even full assignments do not clear the qualif
814 // While we could special case full assignments, this would be inconsistent with
815 // aggregates where we overwrite all fields via assignments, which would not get
817 for (per_local, qualif) in &mut self.cx.per_local.as_mut().zip(qualifs).0 {
819 per_local.insert(index);
823 // Ensure the `IsNotPromotable` qualification is preserved.
824 // NOTE(eddyb) this is actually unnecessary right now, as
825 // we never replace the local's qualif, but we might in
826 // the future, and so it serves to catch changes that unset
827 // important bits (in which case, asserting `contains` could
828 // be replaced with calling `insert` to re-set the bit).
829 if kind == LocalKind::Temp {
830 if !self.temp_promotion_state[index].is_promotable() {
831 assert!(self.cx.per_local[IsNotPromotable].contains(index));
836 /// Check a whole const, static initializer or const fn.
837 fn check_const(&mut self) -> (u8, &'tcx BitSet<Local>) {
838 debug!("const-checking {} {:?}", self.mode, self.def_id);
840 let body = self.body;
842 let mut seen_blocks = BitSet::new_empty(body.basic_blocks().len());
843 let mut bb = START_BLOCK;
845 seen_blocks.insert(bb.index());
847 self.visit_basic_block_data(bb, &body[bb]);
849 let target = match body[bb].terminator().kind {
850 TerminatorKind::Goto { target } |
851 TerminatorKind::Drop { target, .. } |
852 TerminatorKind::Assert { target, .. } |
853 TerminatorKind::Call { destination: Some((_, target)), .. } => {
857 // Non-terminating calls cannot produce any value.
858 TerminatorKind::Call { destination: None, .. } => {
862 TerminatorKind::SwitchInt {..} |
863 TerminatorKind::DropAndReplace { .. } |
864 TerminatorKind::Resume |
865 TerminatorKind::Abort |
866 TerminatorKind::GeneratorDrop |
867 TerminatorKind::Yield { .. } |
868 TerminatorKind::Unreachable |
869 TerminatorKind::FalseEdges { .. } |
870 TerminatorKind::FalseUnwind { .. } => None,
872 TerminatorKind::Return => {
879 Some(target) if !seen_blocks.contains(target.index()) => {
890 // Collect all the temps we need to promote.
891 let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
893 debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
894 for candidate in &self.promotion_candidates {
896 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
897 match self.body[bb].statements[stmt_idx].kind {
898 StatementKind::Assign(
900 box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
902 promoted_temps.insert(index);
907 Candidate::Argument { .. } => {}
911 let mut qualifs = self.qualifs_in_local(RETURN_PLACE);
913 // Account for errors in consts by using the
914 // conservative type qualification instead.
915 if qualifs[IsNotPromotable] {
916 qualifs = self.qualifs_in_any_value_of_ty(body.return_ty());
919 (qualifs.encode_to_bits(), self.tcx.arena.alloc(promoted_temps))
923 /// Checks MIR for const-correctness, using `ConstCx`
924 /// for value qualifications, and accumulates writes of
925 /// rvalue/call results to locals, in `local_qualif`.
926 /// For functions (constant or not), it also records
927 /// candidates for promotion in `promotion_candidates`.
928 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
931 place_base: &PlaceBase<'tcx>,
932 context: PlaceContext,
935 self.super_place_base(place_base, context, location);
937 PlaceBase::Local(_) => {}
938 PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
941 PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
945 .any(|attr| attr.check_name(sym::thread_local)) {
946 if self.mode != Mode::Fn {
947 span_err!(self.tcx.sess, self.span, E0625,
948 "thread-local statics cannot be \
949 accessed at compile-time");
954 // Only allow statics (not consts) to refer to other statics.
955 if self.mode == Mode::Static || self.mode == Mode::StaticMut {
956 if self.mode == Mode::Static && context.is_mutating_use() {
957 // this is not strictly necessary as miri will also bail out
958 // For interior mutability we can't really catch this statically as that
959 // goes through raw pointers and intermediate temporaries, so miri has
960 // to catch this anyway
961 self.tcx.sess.span_err(
963 "cannot mutate statics in the initializer of another static",
970 if self.mode != Mode::Fn {
971 let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
972 "{}s cannot refer to statics, use \
973 a constant instead", self.mode);
974 if self.tcx.sess.teach(&err.get_code().unwrap()) {
976 "Static and const variables can refer to other const variables. \
977 But a const variable cannot refer to a static variable."
980 "To fix this, the value can be extracted as a const and then used."
991 proj: &Projection<'tcx>,
992 context: PlaceContext,
996 "visit_place_projection: proj={:?} context={:?} location={:?}",
997 proj, context, location,
999 self.super_projection(proj, context, location);
1001 ProjectionElem::Deref => {
1002 if context.is_mutating_use() {
1003 // `not_const` errors out in const contexts
1006 let base_ty = proj.base.ty(self.body, self.tcx).ty;
1010 if let ty::RawPtr(_) = base_ty.sty {
1011 if !self.tcx.features().const_raw_ptr_deref {
1013 &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
1014 self.span, GateIssue::Language,
1016 "dereferencing raw pointers in {}s is unstable",
1026 ProjectionElem::ConstantIndex {..} |
1027 ProjectionElem::Subslice {..} |
1028 ProjectionElem::Field(..) |
1029 ProjectionElem::Index(_) => {
1030 let base_ty = proj.base.ty(self.body, self.tcx).ty;
1031 if let Some(def) = base_ty.ty_adt_def() {
1035 if !self.tcx.features().const_fn_union {
1037 &self.tcx.sess.parse_sess, sym::const_fn_union,
1038 self.span, GateIssue::Language,
1039 "unions in const fn are unstable",
1054 ProjectionElem::Downcast(..) => {
1060 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
1061 debug!("visit_operand: operand={:?} location={:?}", operand, location);
1062 self.super_operand(operand, location);
1065 Operand::Move(ref place) => {
1066 // Mark the consumed locals to indicate later drops are noops.
1067 if let Place::Base(PlaceBase::Local(local)) = *place {
1068 self.cx.per_local[NeedsDrop].remove(local);
1072 Operand::Constant(_) => {}
1076 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
1077 debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
1079 // Check nested operands and places.
1080 if let Rvalue::Ref(_, kind, ref place) = *rvalue {
1081 // Special-case reborrows.
1082 let mut reborrow_place = None;
1083 if let Place::Projection(ref proj) = *place {
1084 if let ProjectionElem::Deref = proj.elem {
1085 let base_ty = proj.base.ty(self.body, self.tcx).ty;
1086 if let ty::Ref(..) = base_ty.sty {
1087 reborrow_place = Some(&proj.base);
1092 if let Some(place) = reborrow_place {
1093 let ctx = match kind {
1094 BorrowKind::Shared => PlaceContext::NonMutatingUse(
1095 NonMutatingUseContext::SharedBorrow,
1097 BorrowKind::Shallow => PlaceContext::NonMutatingUse(
1098 NonMutatingUseContext::ShallowBorrow,
1100 BorrowKind::Unique => PlaceContext::NonMutatingUse(
1101 NonMutatingUseContext::UniqueBorrow,
1103 BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
1104 MutatingUseContext::Borrow,
1107 self.visit_place(place, ctx, location);
1109 self.super_rvalue(rvalue, location);
1112 self.super_rvalue(rvalue, location);
1117 Rvalue::Repeat(..) |
1118 Rvalue::UnaryOp(UnOp::Neg, _) |
1119 Rvalue::UnaryOp(UnOp::Not, _) |
1120 Rvalue::NullaryOp(NullOp::SizeOf, _) |
1121 Rvalue::CheckedBinaryOp(..) |
1122 Rvalue::Cast(CastKind::Pointer(_), ..) |
1123 Rvalue::Discriminant(..) |
1126 Rvalue::Aggregate(..) => {}
1128 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
1129 let operand_ty = operand.ty(self.body, self.tcx);
1130 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
1131 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
1132 match (cast_in, cast_out) {
1133 (CastTy::Ptr(_), CastTy::Int(_)) |
1134 (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => {
1135 unleash_miri!(self);
1136 if !self.tcx.features().const_raw_ptr_to_usize_cast {
1137 // in const fn and constants require the feature gate
1138 // FIXME: make it unsafe inside const fn and constants
1140 &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
1141 self.span, GateIssue::Language,
1143 "casting pointers to integers in {}s is unstable",
1153 Rvalue::BinaryOp(op, ref lhs, _) => {
1154 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).sty {
1155 assert!(op == BinOp::Eq || op == BinOp::Ne ||
1156 op == BinOp::Le || op == BinOp::Lt ||
1157 op == BinOp::Ge || op == BinOp::Gt ||
1158 op == BinOp::Offset);
1160 unleash_miri!(self);
1161 if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers {
1162 // require the feature gate inside constants and const fn
1163 // FIXME: make it unsafe to use these operations
1165 &self.tcx.sess.parse_sess,
1166 sym::const_compare_raw_pointers,
1168 GateIssue::Language,
1169 &format!("comparing raw pointers inside {}", self.mode),
1175 Rvalue::NullaryOp(NullOp::Box, _) => {
1176 unleash_miri!(self);
1177 if self.mode != Mode::Fn {
1178 let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
1179 "allocations are not allowed in {}s", self.mode);
1180 err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
1181 if self.tcx.sess.teach(&err.get_code().unwrap()) {
1183 "The value of statics and constants must be known at compile time, \
1184 and they live for the entire lifetime of a program. Creating a boxed \
1185 value allocates memory on the heap at runtime, and therefore cannot \
1186 be done at compile time."
1195 fn visit_terminator_kind(&mut self,
1196 kind: &TerminatorKind<'tcx>,
1197 location: Location) {
1198 debug!("visit_terminator_kind: kind={:?} location={:?}", kind, location);
1199 if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
1200 if let Some((ref dest, _)) = *destination {
1201 self.assign(dest, ValueSource::Call {
1204 return_ty: dest.ty(self.body, self.tcx).ty,
1208 let fn_ty = func.ty(self.body, self.tcx);
1209 let mut callee_def_id = None;
1210 let mut is_shuffle = false;
1212 ty::FnDef(def_id, _) => {
1213 callee_def_id = Some(def_id);
1214 match self.tcx.fn_sig(def_id).abi() {
1215 Abi::RustIntrinsic |
1216 Abi::PlatformIntrinsic => {
1217 assert!(!self.tcx.is_const_fn(def_id));
1218 match &self.tcx.item_name(def_id).as_str()[..] {
1219 // special intrinsic that can be called diretly without an intrinsic
1220 // feature gate needs a language feature gate
1222 // never promote transmute calls
1223 if self.mode != Mode::Fn {
1224 // const eval transmute calls only with the feature gate
1225 if !self.tcx.features().const_transmute {
1227 &self.tcx.sess.parse_sess, sym::const_transmute,
1228 self.span, GateIssue::Language,
1229 &format!("The use of std::mem::transmute() \
1230 is gated in {}s", self.mode));
1235 name if name.starts_with("simd_shuffle") => {
1239 // no need to check feature gates, intrinsics are only callable
1240 // from the libstd or with forever unstable feature gates
1245 // In normal functions no calls are feature-gated.
1246 if self.mode != Mode::Fn {
1247 let unleash_miri = self
1252 .unleash_the_miri_inside_of_you;
1253 if self.tcx.is_const_fn(def_id) || unleash_miri {
1254 // stable const fns or unstable const fns
1255 // with their feature gate active
1256 // FIXME(eddyb) move stability checks from `is_const_fn` here.
1257 } else if self.is_const_panic_fn(def_id) {
1258 // Check the const_panic feature gate.
1259 // FIXME: cannot allow this inside `allow_internal_unstable`
1260 // because that would make `panic!` insta stable in constants,
1261 // since the macro is marked with the attribute.
1262 if !self.tcx.features().const_panic {
1263 // Don't allow panics in constants without the feature gate.
1265 &self.tcx.sess.parse_sess,
1268 GateIssue::Language,
1269 &format!("panicking in {}s is unstable", self.mode),
1272 } else if let Some(feature)
1273 = self.tcx.is_unstable_const_fn(def_id) {
1274 // Check `#[unstable]` const fns or `#[rustc_const_unstable]`
1275 // functions without the feature gate active in this crate in
1276 // order to report a better error message than the one below.
1277 if !self.span.allows_unstable(feature) {
1278 let mut err = self.tcx.sess.struct_span_err(self.span,
1279 &format!("`{}` is not yet stable as a const fn",
1280 self.tcx.def_path_str(def_id)));
1281 if nightly_options::is_nightly_build() {
1283 "add `#![feature({})]` to the \
1284 crate attributes to enable",
1290 let mut err = struct_span_err!(
1294 "calls in {}s are limited to constant functions, \
1295 tuple structs and tuple variants",
1305 if self.mode != Mode::Fn {
1306 let mut err = self.tcx.sess.struct_span_err(
1308 &format!("function pointers are not allowed in const fn"));
1317 // No need to do anything in constants and statics, as everything is "constant" anyway
1318 // so promotion would be useless.
1319 if self.mode != Mode::Static && self.mode != Mode::Const {
1320 let constant_args = callee_def_id.and_then(|id| {
1321 args_required_const(self.tcx, id)
1322 }).unwrap_or_default();
1323 for (i, arg) in args.iter().enumerate() {
1324 if !(is_shuffle && i == 2 || constant_args.contains(&i)) {
1328 let candidate = Candidate::Argument { bb: location.block, index: i };
1329 // Since the argument is required to be constant,
1330 // we care about constness, not promotability.
1331 // If we checked for promotability, we'd miss out on
1332 // the results of function calls (which are never promoted
1333 // in runtime code).
1334 // This is not a problem, because the argument explicitly
1335 // requests constness, in contrast to regular promotion
1336 // which happens even without the user requesting it.
1337 // We can error out with a hard error if the argument is not
1339 if !IsNotPromotable::in_operand(self, arg) {
1340 debug!("visit_terminator_kind: candidate={:?}", candidate);
1341 self.promotion_candidates.push(candidate);
1344 span_err!(self.tcx.sess, self.span, E0526,
1345 "shuffle indices are not constant");
1347 self.tcx.sess.span_err(self.span,
1348 &format!("argument {} is required to be a constant",
1355 // Check callee and argument operands.
1356 self.visit_operand(func, location);
1358 self.visit_operand(arg, location);
1360 } else if let TerminatorKind::Drop { location: ref place, .. } = *kind {
1361 self.super_terminator_kind(kind, location);
1363 // Deny *any* live drops anywhere other than functions.
1364 if self.mode != Mode::Fn {
1365 unleash_miri!(self);
1366 // HACK(eddyb): emulate a bit of dataflow analysis,
1367 // conservatively, that drop elaboration will do.
1368 let needs_drop = if let Place::Base(PlaceBase::Local(local)) = *place {
1369 if NeedsDrop::in_local(self, local) {
1370 Some(self.body.local_decls[local].source_info.span)
1378 if let Some(span) = needs_drop {
1379 // Double-check the type being dropped, to minimize false positives.
1380 let ty = place.ty(self.body, self.tcx).ty;
1381 if ty.needs_drop(self.tcx, self.param_env) {
1382 struct_span_err!(self.tcx.sess, span, E0493,
1383 "destructors cannot be evaluated at compile-time")
1384 .span_label(span, format!("{}s cannot evaluate destructors",
1391 // Qualify any operands inside other terminators.
1392 self.super_terminator_kind(kind, location);
1396 fn visit_assign(&mut self,
1398 rvalue: &Rvalue<'tcx>,
1399 location: Location) {
1400 debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
1401 self.assign(dest, ValueSource::Rvalue(rvalue), location);
1403 self.visit_rvalue(rvalue, location);
1406 fn visit_source_info(&mut self, source_info: &SourceInfo) {
1407 debug!("visit_source_info: source_info={:?}", source_info);
1408 self.span = source_info.span;
1411 fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
1412 debug!("visit_statement: statement={:?} location={:?}", statement, location);
1413 match statement.kind {
1414 StatementKind::Assign(..) => {
1415 self.super_statement(statement, location);
1417 // FIXME(eddyb) should these really do nothing?
1418 StatementKind::FakeRead(..) |
1419 StatementKind::SetDiscriminant { .. } |
1420 StatementKind::StorageLive(_) |
1421 StatementKind::StorageDead(_) |
1422 StatementKind::InlineAsm {..} |
1423 StatementKind::Retag { .. } |
1424 StatementKind::AscribeUserType(..) |
1425 StatementKind::Nop => {}
1430 pub fn provide(providers: &mut Providers<'_>) {
1431 *providers = Providers {
1437 fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1439 -> (u8, &'tcx BitSet<Local>) {
1440 // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
1441 // cannot yet be stolen), because `mir_validated()`, which steals
1442 // from `mir_const(), forces this query to execute before
1443 // performing the steal.
1444 let body = &tcx.mir_const(def_id).borrow();
1446 if body.return_ty().references_error() {
1447 tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
1448 return (1 << IsNotPromotable::IDX, tcx.arena.alloc(BitSet::new_empty(0)));
1451 Checker::new(tcx, def_id, body, Mode::Const).check_const()
1454 pub struct QualifyAndPromoteConstants;
1456 impl MirPass for QualifyAndPromoteConstants {
1457 fn run_pass<'a, 'tcx>(&self,
1458 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1459 src: MirSource<'tcx>,
1460 body: &mut Body<'tcx>) {
1461 // There's not really any point in promoting errorful MIR.
1462 if body.return_ty().references_error() {
1463 tcx.sess.delay_span_bug(body.span, "QualifyAndPromoteConstants: MIR had errors");
1467 if src.promoted.is_some() {
1471 let def_id = src.def_id();
1472 let id = tcx.hir().as_local_hir_id(def_id).unwrap();
1473 let mut const_promoted_temps = None;
1474 let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
1475 hir::BodyOwnerKind::Closure => Mode::Fn,
1476 hir::BodyOwnerKind::Fn => {
1477 if tcx.is_const_fn(def_id) {
1483 hir::BodyOwnerKind::Const => {
1484 const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1487 hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
1488 hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
1491 debug!("run_pass: mode={:?}", mode);
1492 if mode == Mode::Fn || mode == Mode::ConstFn {
1493 // This is ugly because Checker holds onto mir,
1494 // which can't be mutated until its scope ends.
1495 let (temps, candidates) = {
1496 let mut checker = Checker::new(tcx, def_id, body, mode);
1497 if mode == Mode::ConstFn {
1498 if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
1499 checker.check_const();
1500 } else if tcx.is_min_const_fn(def_id) {
1501 // enforce `min_const_fn` for stable const fns
1502 use super::qualify_min_const_fn::is_min_const_fn;
1503 if let Err((span, err)) = is_min_const_fn(tcx, def_id, body) {
1504 let mut diag = struct_span_err!(
1511 diag.note("for more information, see issue \
1512 https://github.com/rust-lang/rust/issues/57563");
1514 "add #![feature(const_fn)] to the crate attributes to enable",
1518 // this should not produce any errors, but better safe than sorry
1520 checker.check_const();
1523 // Enforce a constant-like CFG for `const fn`.
1524 checker.check_const();
1527 while let Some((bb, data)) = checker.rpo.next() {
1528 checker.visit_basic_block_data(bb, data);
1532 (checker.temp_promotion_state, checker.promotion_candidates)
1535 // Do the actual promotion, now that we know what's viable.
1536 promote_consts::promote_candidates(body, tcx, temps, candidates);
1538 if !body.control_flow_destroyed.is_empty() {
1539 let mut locals = body.vars_iter();
1540 if let Some(local) = locals.next() {
1541 let span = body.local_decls[local].source_info.span;
1542 let mut error = tcx.sess.struct_span_err(
1545 "new features like let bindings are not permitted in {}s \
1546 which also use short circuiting operators",
1550 for (span, kind) in body.control_flow_destroyed.iter() {
1553 &format!("use of {} here does not actually short circuit due to \
1554 the const evaluator presently not being able to do control flow. \
1555 See https://github.com/rust-lang/rust/issues/49146 for more \
1556 information.", kind),
1559 for local in locals {
1560 let span = body.local_decls[local].source_info.span;
1563 "more locals defined here",
1569 let promoted_temps = if mode == Mode::Const {
1570 // Already computed by `mir_const_qualif`.
1571 const_promoted_temps.unwrap()
1573 Checker::new(tcx, def_id, body, mode).check_const().1
1576 // In `const` and `static` everything without `StorageDead`
1577 // is `'static`, we don't have to create promoted MIR fragments,
1578 // just remove `Drop` and `StorageDead` on "promoted" locals.
1579 debug!("run_pass: promoted_temps={:?}", promoted_temps);
1580 for block in body.basic_blocks_mut() {
1581 block.statements.retain(|statement| {
1582 match statement.kind {
1583 StatementKind::StorageDead(index) => {
1584 !promoted_temps.contains(index)
1589 let terminator = block.terminator_mut();
1590 match terminator.kind {
1591 TerminatorKind::Drop {
1592 location: Place::Base(PlaceBase::Local(index)),
1596 if promoted_temps.contains(index) {
1597 terminator.kind = TerminatorKind::Goto {
1607 // Statics must be Sync.
1608 if mode == Mode::Static {
1609 // `#[thread_local]` statics don't have to be `Sync`.
1610 for attr in &tcx.get_attrs(def_id)[..] {
1611 if attr.check_name(sym::thread_local) {
1615 let ty = body.return_ty();
1616 tcx.infer_ctxt().enter(|infcx| {
1617 let param_env = ty::ParamEnv::empty();
1618 let cause = traits::ObligationCause::new(body.span, id, traits::SharedStatic);
1619 let mut fulfillment_cx = traits::FulfillmentContext::new();
1620 fulfillment_cx.register_bound(&infcx,
1623 tcx.require_lang_item(lang_items::SyncTraitLangItem),
1625 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
1626 infcx.report_fulfillment_errors(&err, None, false);
1633 fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
1634 let attrs = tcx.get_attrs(def_id);
1635 let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
1636 let mut ret = FxHashSet::default();
1637 for meta in attr.meta_item_list()? {
1638 match meta.literal()?.node {
1639 LitKind::Int(a, _) => { ret.insert(a as usize); }