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>,
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.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: &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.mir, 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.mir, 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 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 promotable at all - non-`const fn` calls, asm!,
369 // pointer comparisons, ptr-to-int casts, etc.
370 struct IsNotPromotable;
372 impl Qualif for IsNotPromotable {
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(sym::thread_local)
390 fn in_projection(cx: &ConstCx<'_, 'tcx>, proj: &Projection<'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).ty;
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 *implicitly*.
512 /// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`.
513 /// Inside a const context all constness rules
514 /// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior
515 /// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively).
516 /// Implicit promotion inside regular functions does not happen if `const fn` calls are involved,
517 /// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses
518 /// being compared inside the function.
519 struct IsNotImplicitlyPromotable;
521 impl Qualif for IsNotImplicitlyPromotable {
522 const IDX: usize = 3;
525 cx: &ConstCx<'_, 'tcx>,
526 callee: &Operand<'tcx>,
527 args: &[Operand<'tcx>],
528 _return_ty: Ty<'tcx>,
530 if cx.mode == Mode::Fn {
531 if let ty::FnDef(def_id, _) = callee.ty(cx.mir, cx.tcx).sty {
532 // Never promote runtime `const fn` calls of
533 // functions without `#[rustc_promotable]`.
534 if !cx.tcx.is_promotable_const_fn(def_id) {
540 Self::in_operand(cx, callee) || args.iter().any(|arg| Self::in_operand(cx, arg))
544 // Ensure the `IDX` values are sequential (`0..QUALIF_COUNT`).
545 macro_rules! static_assert_seq_qualifs {
546 ($i:expr => $first:ident $(, $rest:ident)*) => {
548 static_assert_seq_qualifs!($i + 1 => $($rest),*);
554 static_assert!(QUALIF_COUNT == $i);
557 static_assert_seq_qualifs!(
558 0 => HasMutInterior, NeedsDrop, IsNotPromotable, IsNotImplicitlyPromotable
561 impl ConstCx<'_, 'tcx> {
562 fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif<bool> {
563 let mut qualifs = PerQualif::default();
564 qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false);
565 qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false);
566 qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
567 qualifs[IsNotImplicitlyPromotable] =
568 IsNotImplicitlyPromotable::in_any_value_of_ty(self, ty).unwrap_or(false);
572 fn qualifs_in_local(&self, local: Local) -> PerQualif<bool> {
573 let mut qualifs = PerQualif::default();
574 qualifs[HasMutInterior] = HasMutInterior::in_local(self, local);
575 qualifs[NeedsDrop] = NeedsDrop::in_local(self, local);
576 qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local);
577 qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_local(self, local);
581 fn qualifs_in_value(&self, source: ValueSource<'_, 'tcx>) -> PerQualif<bool> {
582 let mut qualifs = PerQualif::default();
583 qualifs[HasMutInterior] = HasMutInterior::in_value(self, source);
584 qualifs[NeedsDrop] = NeedsDrop::in_value(self, source);
585 qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source);
586 qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_value(self, source);
591 struct Checker<'a, 'tcx> {
592 cx: ConstCx<'a, 'tcx>,
596 rpo: ReversePostorder<'a, 'tcx>,
598 temp_promotion_state: IndexVec<Local, TempState>,
599 promotion_candidates: Vec<Candidate>,
602 macro_rules! unleash_miri {
604 if $this.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
605 $this.tcx.sess.span_warn($this.span, "skipping const checks");
611 impl Deref for Checker<'a, 'tcx> {
612 type Target = ConstCx<'a, 'tcx>;
614 fn deref(&self) -> &Self::Target {
619 impl<'a, 'tcx> Checker<'a, 'tcx> {
620 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
625 assert!(def_id.is_local());
626 let mut rpo = traversal::reverse_postorder(mir);
627 let temps = promote_consts::collect_temps(mir, &mut rpo);
630 let param_env = tcx.param_env(def_id);
632 let mut cx = ConstCx {
637 per_local: PerQualif::new(BitSet::new_empty(mir.local_decls.len())),
640 for (local, decl) in mir.local_decls.iter_enumerated() {
641 if let LocalKind::Arg = mir.local_kind(local) {
642 let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty);
643 for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 {
645 per_local.insert(local);
649 if !temps[local].is_promotable() {
650 cx.per_local[IsNotPromotable].insert(local);
652 if let LocalKind::Var = mir.local_kind(local) {
653 // Sanity check to prevent implicit and explicit promotion of
655 assert!(cx.per_local[IsNotPromotable].contains(local));
664 temp_promotion_state: temps,
665 promotion_candidates: vec![]
669 // FIXME(eddyb) we could split the errors into meaningful
670 // categories, but enabling full miri would make that
671 // slightly pointless (even with feature-gating).
672 fn not_const(&mut self) {
674 if self.mode != Mode::Fn {
675 let mut err = struct_span_err!(
679 "{} contains unimplemented expression type",
682 if self.tcx.sess.teach(&err.get_code().unwrap()) {
683 err.note("A function call isn't allowed in the const's initialization expression \
684 because the expression's value must be known at compile-time.");
685 err.note("Remember: you can't use a function call inside a const's initialization \
686 expression! However, you can use it anywhere else.");
692 /// Assigns an rvalue/call qualification to the given destination.
693 fn assign(&mut self, dest: &Place<'tcx>, source: ValueSource<'_, 'tcx>, location: Location) {
694 trace!("assign: {:?} <- {:?}", dest, source);
696 let mut qualifs = self.qualifs_in_value(source);
698 if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
699 // Getting `true` from `HasMutInterior::in_rvalue` means
700 // the borrowed place is disallowed from being borrowed,
701 // due to either a mutable borrow (with some exceptions),
702 // or an shared borrow of a value with interior mutability.
703 // Then `HasMutInterior` is replaced with `IsNotPromotable`,
704 // to avoid duplicate errors (e.g. from reborrowing).
705 if qualifs[HasMutInterior] {
706 qualifs[HasMutInterior] = false;
707 qualifs[IsNotPromotable] = true;
709 if self.mode != Mode::Fn {
710 if let BorrowKind::Mut { .. } = kind {
711 let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
712 "references in {}s may only refer \
713 to immutable values", self.mode);
714 err.span_label(self.span, format!("{}s require immutable values",
716 if self.tcx.sess.teach(&err.get_code().unwrap()) {
717 err.note("References in statics and constants may only refer to \
718 immutable values.\n\n\
719 Statics are shared everywhere, and if they refer to \
720 mutable data one might violate memory safety since \
721 holding multiple mutable references to shared data is \
723 If you really want global mutable state, try using \
724 static mut or a global UnsafeCell.");
728 span_err!(self.tcx.sess, self.span, E0492,
729 "cannot borrow a constant which may contain \
730 interior mutability, create a static instead");
733 } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
734 // Don't promote BorrowKind::Shallow borrows, as they don't
737 // We might have a candidate for promotion.
738 let candidate = Candidate::Ref(location);
739 // We can only promote interior borrows of promotable temps.
740 let mut place = place;
741 while let Place::Projection(ref proj) = *place {
742 if proj.elem == ProjectionElem::Deref {
747 debug!("qualify_consts: promotion candidate: place={:?}", place);
748 if let Place::Base(PlaceBase::Local(local)) = *place {
749 if self.mir.local_kind(local) == LocalKind::Temp {
750 debug!("qualify_consts: promotion candidate: local={:?}", local);
751 // The borrowed place doesn't have `HasMutInterior`
752 // (from `in_rvalue`), so we can safely ignore
753 // `HasMutInterior` from the local's qualifications.
754 // This allows borrowing fields which don't have
755 // `HasMutInterior`, from a type that does, e.g.:
756 // `let _: &'static _ = &(Cell::new(1), 2).1;`
757 let mut local_qualifs = self.qualifs_in_local(local);
758 local_qualifs[HasMutInterior] = false;
759 if !local_qualifs.0.iter().any(|&qualif| qualif) {
760 debug!("qualify_consts: promotion candidate: {:?}", candidate);
761 self.promotion_candidates.push(candidate);
771 // We treat all locals equal in constants
772 Place::Base(PlaceBase::Local(index)) => break *index,
773 // projections are transparent for assignments
774 // we qualify the entire destination at once, even if just a field would have
775 // stricter qualification
776 Place::Projection(proj) => {
777 // Catch more errors in the destination. `visit_place` also checks various
778 // projection rules like union field access and raw pointer deref
781 PlaceContext::MutatingUse(MutatingUseContext::Store),
786 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
787 bug!("promoteds don't exist yet during promotion"),
788 Place::Base(PlaceBase::Static(box Static{ kind: _, .. })) => {
789 // Catch more errors in the destination. `visit_place` also checks that we
790 // do not try to access statics from constants or try to mutate statics
793 PlaceContext::MutatingUse(MutatingUseContext::Store),
801 let kind = self.mir.local_kind(index);
802 debug!("store to {:?} {:?}", kind, index);
804 // Only handle promotable temps in non-const functions.
805 if self.mode == Mode::Fn {
806 if kind != LocalKind::Temp ||
807 !self.temp_promotion_state[index].is_promotable() {
812 // this is overly restrictive, because even full assignments do not clear the qualif
813 // While we could special case full assignments, this would be inconsistent with
814 // aggregates where we overwrite all fields via assignments, which would not get
816 for (per_local, qualif) in &mut self.cx.per_local.as_mut().zip(qualifs).0 {
818 per_local.insert(index);
822 // Ensure the `IsNotPromotable` qualification is preserved.
823 // NOTE(eddyb) this is actually unnecessary right now, as
824 // we never replace the local's qualif, but we might in
825 // the future, and so it serves to catch changes that unset
826 // important bits (in which case, asserting `contains` could
827 // be replaced with calling `insert` to re-set the bit).
828 if kind == LocalKind::Temp {
829 if !self.temp_promotion_state[index].is_promotable() {
830 assert!(self.cx.per_local[IsNotPromotable].contains(index));
835 /// Check a whole const, static initializer or const fn.
836 fn check_const(&mut self) -> (u8, &'tcx BitSet<Local>) {
837 debug!("const-checking {} {:?}", self.mode, self.def_id);
841 let mut seen_blocks = BitSet::new_empty(mir.basic_blocks().len());
842 let mut bb = START_BLOCK;
844 seen_blocks.insert(bb.index());
846 self.visit_basic_block_data(bb, &mir[bb]);
848 let target = match mir[bb].terminator().kind {
849 TerminatorKind::Goto { target } |
850 TerminatorKind::Drop { target, .. } |
851 TerminatorKind::Assert { target, .. } |
852 TerminatorKind::Call { destination: Some((_, target)), .. } => {
856 // Non-terminating calls cannot produce any value.
857 TerminatorKind::Call { destination: None, .. } => {
861 TerminatorKind::SwitchInt {..} |
862 TerminatorKind::DropAndReplace { .. } |
863 TerminatorKind::Resume |
864 TerminatorKind::Abort |
865 TerminatorKind::GeneratorDrop |
866 TerminatorKind::Yield { .. } |
867 TerminatorKind::Unreachable |
868 TerminatorKind::FalseEdges { .. } |
869 TerminatorKind::FalseUnwind { .. } => None,
871 TerminatorKind::Return => {
878 Some(target) if !seen_blocks.contains(target.index()) => {
889 // Collect all the temps we need to promote.
890 let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
892 debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
893 for candidate in &self.promotion_candidates {
895 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
896 match self.mir[bb].statements[stmt_idx].kind {
897 StatementKind::Assign(
899 box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
901 promoted_temps.insert(index);
906 Candidate::Argument { .. } => {}
910 let mut qualifs = self.qualifs_in_local(RETURN_PLACE);
912 // Account for errors in consts by using the
913 // conservative type qualification instead.
914 if qualifs[IsNotPromotable] {
915 qualifs = self.qualifs_in_any_value_of_ty(mir.return_ty());
918 (qualifs.encode_to_bits(), self.tcx.arena.alloc(promoted_temps))
922 /// Checks MIR for const-correctness, using `ConstCx`
923 /// for value qualifications, and accumulates writes of
924 /// rvalue/call results to locals, in `local_qualif`.
925 /// For functions (constant or not), it also records
926 /// candidates for promotion in `promotion_candidates`.
927 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
928 fn visit_place(&mut self,
930 context: PlaceContext,
931 location: Location) {
932 debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
933 place.iterate(|place_base, place_projections| {
935 PlaceBase::Local(_) => {}
936 PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => {
939 PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => {
943 .any(|attr| attr.check_name(sym::thread_local)) {
944 if self.mode != Mode::Fn {
945 span_err!(self.tcx.sess, self.span, E0625,
946 "thread-local statics cannot be \
947 accessed at compile-time");
952 // Only allow statics (not consts) to refer to other statics.
953 if self.mode == Mode::Static || self.mode == Mode::StaticMut {
954 if self.mode == Mode::Static && context.is_mutating_use() {
955 // this is not strictly necessary as miri will also bail out
956 // For interior mutability we can't really catch this statically as that
957 // goes through raw pointers and intermediate temporaries, so miri has
958 // to catch this anyway
959 self.tcx.sess.span_err(
961 "cannot mutate statics in the initializer of another static",
968 if self.mode != Mode::Fn {
969 let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
970 "{}s cannot refer to statics, use \
971 a constant instead", self.mode);
972 if self.tcx.sess.teach(&err.get_code().unwrap()) {
974 "Static and const variables can refer to other const variables. \
975 But a const variable cannot refer to a static variable."
978 "To fix this, the value can be extracted as a const and then used."
986 for proj in place_projections {
988 ProjectionElem::Deref => {
989 if context.is_mutating_use() {
990 // `not_const` errors out in const contexts
993 let base_ty = proj.base.ty(self.mir, self.tcx).ty;
997 if let ty::RawPtr(_) = base_ty.sty {
998 if !self.tcx.features().const_raw_ptr_deref {
1000 &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
1001 self.span, GateIssue::Language,
1003 "dereferencing raw pointers in {}s is unstable",
1013 ProjectionElem::ConstantIndex {..} |
1014 ProjectionElem::Subslice {..} |
1015 ProjectionElem::Field(..) |
1016 ProjectionElem::Index(_) => {
1017 let base_ty = proj.base.ty(self.mir, self.tcx).ty;
1018 if let Some(def) = base_ty.ty_adt_def() {
1022 if !self.tcx.features().const_fn_union {
1024 &self.tcx.sess.parse_sess, sym::const_fn_union,
1025 self.span, GateIssue::Language,
1026 "unions in const fn are unstable",
1041 ProjectionElem::Downcast(..) => {
1049 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
1050 debug!("visit_operand: operand={:?} location={:?}", operand, location);
1051 self.super_operand(operand, location);
1054 Operand::Move(ref place) => {
1055 // Mark the consumed locals to indicate later drops are noops.
1056 if let Place::Base(PlaceBase::Local(local)) = *place {
1057 self.cx.per_local[NeedsDrop].remove(local);
1061 Operand::Constant(_) => {}
1065 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
1066 debug!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
1068 // Check nested operands and places.
1069 if let Rvalue::Ref(_, kind, ref place) = *rvalue {
1070 // Special-case reborrows.
1071 let mut is_reborrow = false;
1072 if let Place::Projection(ref proj) = *place {
1073 if let ProjectionElem::Deref = proj.elem {
1074 let base_ty = proj.base.ty(self.mir, self.tcx).ty;
1075 if let ty::Ref(..) = base_ty.sty {
1082 let ctx = match kind {
1083 BorrowKind::Shared => PlaceContext::NonMutatingUse(
1084 NonMutatingUseContext::SharedBorrow,
1086 BorrowKind::Shallow => PlaceContext::NonMutatingUse(
1087 NonMutatingUseContext::ShallowBorrow,
1089 BorrowKind::Unique => PlaceContext::NonMutatingUse(
1090 NonMutatingUseContext::UniqueBorrow,
1092 BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
1093 MutatingUseContext::Borrow,
1096 self.super_place(place, ctx, location);
1098 self.super_rvalue(rvalue, location);
1101 self.super_rvalue(rvalue, location);
1106 Rvalue::Repeat(..) |
1107 Rvalue::UnaryOp(UnOp::Neg, _) |
1108 Rvalue::UnaryOp(UnOp::Not, _) |
1109 Rvalue::NullaryOp(NullOp::SizeOf, _) |
1110 Rvalue::CheckedBinaryOp(..) |
1111 Rvalue::Cast(CastKind::Pointer(_), ..) |
1112 Rvalue::Discriminant(..) |
1115 Rvalue::Aggregate(..) => {}
1117 Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
1118 let operand_ty = operand.ty(self.mir, self.tcx);
1119 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
1120 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
1121 match (cast_in, cast_out) {
1122 (CastTy::Ptr(_), CastTy::Int(_)) |
1123 (CastTy::FnPtr, CastTy::Int(_)) if self.mode != Mode::Fn => {
1124 unleash_miri!(self);
1125 if !self.tcx.features().const_raw_ptr_to_usize_cast {
1126 // in const fn and constants require the feature gate
1127 // FIXME: make it unsafe inside const fn and constants
1129 &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
1130 self.span, GateIssue::Language,
1132 "casting pointers to integers in {}s is unstable",
1142 Rvalue::BinaryOp(op, ref lhs, _) => {
1143 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty {
1144 assert!(op == BinOp::Eq || op == BinOp::Ne ||
1145 op == BinOp::Le || op == BinOp::Lt ||
1146 op == BinOp::Ge || op == BinOp::Gt ||
1147 op == BinOp::Offset);
1149 unleash_miri!(self);
1150 if self.mode != Mode::Fn && !self.tcx.features().const_compare_raw_pointers {
1151 // require the feature gate inside constants and const fn
1152 // FIXME: make it unsafe to use these operations
1154 &self.tcx.sess.parse_sess,
1155 sym::const_compare_raw_pointers,
1157 GateIssue::Language,
1158 &format!("comparing raw pointers inside {}", self.mode),
1164 Rvalue::NullaryOp(NullOp::Box, _) => {
1165 unleash_miri!(self);
1166 if self.mode != Mode::Fn {
1167 let mut err = struct_span_err!(self.tcx.sess, self.span, E0010,
1168 "allocations are not allowed in {}s", self.mode);
1169 err.span_label(self.span, format!("allocation not allowed in {}s", self.mode));
1170 if self.tcx.sess.teach(&err.get_code().unwrap()) {
1172 "The value of statics and constants must be known at compile time, \
1173 and they live for the entire lifetime of a program. Creating a boxed \
1174 value allocates memory on the heap at runtime, and therefore cannot \
1175 be done at compile time."
1184 fn visit_terminator_kind(&mut self,
1185 kind: &TerminatorKind<'tcx>,
1186 location: Location) {
1187 debug!("visit_terminator_kind: kind={:?} location={:?}", 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).ty,
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, sym::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) {
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: location.block, 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 !IsNotPromotable::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(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).ty;
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(kind, location);
1383 fn visit_assign(&mut self,
1385 rvalue: &Rvalue<'tcx>,
1386 location: Location) {
1387 debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
1388 self.assign(dest, ValueSource::Rvalue(rvalue), location);
1390 self.visit_rvalue(rvalue, location);
1393 fn visit_source_info(&mut self, source_info: &SourceInfo) {
1394 debug!("visit_source_info: source_info={:?}", source_info);
1395 self.span = source_info.span;
1398 fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
1399 debug!("visit_statement: statement={:?} location={:?}", statement, location);
1400 match statement.kind {
1401 StatementKind::Assign(..) => {
1402 self.super_statement(statement, location);
1404 // FIXME(eddyb) should these really do nothing?
1405 StatementKind::FakeRead(..) |
1406 StatementKind::SetDiscriminant { .. } |
1407 StatementKind::StorageLive(_) |
1408 StatementKind::StorageDead(_) |
1409 StatementKind::InlineAsm {..} |
1410 StatementKind::Retag { .. } |
1411 StatementKind::AscribeUserType(..) |
1412 StatementKind::Nop => {}
1417 pub fn provide(providers: &mut Providers<'_>) {
1418 *providers = Providers {
1424 fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1426 -> (u8, &'tcx BitSet<Local>) {
1427 // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
1428 // cannot yet be stolen), because `mir_validated()`, which steals
1429 // from `mir_const(), forces this query to execute before
1430 // performing the steal.
1431 let mir = &tcx.mir_const(def_id).borrow();
1433 if mir.return_ty().references_error() {
1434 tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: MIR had errors");
1435 return (1 << IsNotPromotable::IDX, tcx.arena.alloc(BitSet::new_empty(0)));
1438 Checker::new(tcx, def_id, mir, Mode::Const).check_const()
1441 pub struct QualifyAndPromoteConstants;
1443 impl MirPass for QualifyAndPromoteConstants {
1444 fn run_pass<'a, 'tcx>(&self,
1445 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1446 src: MirSource<'tcx>,
1447 mir: &mut Body<'tcx>) {
1448 // There's not really any point in promoting errorful MIR.
1449 if mir.return_ty().references_error() {
1450 tcx.sess.delay_span_bug(mir.span, "QualifyAndPromoteConstants: MIR had errors");
1454 if src.promoted.is_some() {
1458 let def_id = src.def_id();
1459 let id = tcx.hir().as_local_hir_id(def_id).unwrap();
1460 let mut const_promoted_temps = None;
1461 let mode = match tcx.hir().body_owner_kind_by_hir_id(id) {
1462 hir::BodyOwnerKind::Closure => Mode::Fn,
1463 hir::BodyOwnerKind::Fn => {
1464 if tcx.is_const_fn(def_id) {
1470 hir::BodyOwnerKind::Const => {
1471 const_promoted_temps = Some(tcx.mir_const_qualif(def_id).1);
1474 hir::BodyOwnerKind::Static(hir::MutImmutable) => Mode::Static,
1475 hir::BodyOwnerKind::Static(hir::MutMutable) => Mode::StaticMut,
1478 debug!("run_pass: mode={:?}", mode);
1479 if mode == Mode::Fn || mode == Mode::ConstFn {
1480 // This is ugly because Checker holds onto mir,
1481 // which can't be mutated until its scope ends.
1482 let (temps, candidates) = {
1483 let mut checker = Checker::new(tcx, def_id, mir, mode);
1484 if mode == Mode::ConstFn {
1485 if tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
1486 checker.check_const();
1487 } else if tcx.is_min_const_fn(def_id) {
1488 // enforce `min_const_fn` for stable const fns
1489 use super::qualify_min_const_fn::is_min_const_fn;
1490 if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
1491 let mut diag = struct_span_err!(
1498 diag.note("for more information, see issue \
1499 https://github.com/rust-lang/rust/issues/57563");
1501 "add #![feature(const_fn)] to the crate attributes to enable",
1505 // this should not produce any errors, but better safe than sorry
1507 checker.check_const();
1510 // Enforce a constant-like CFG for `const fn`.
1511 checker.check_const();
1514 while let Some((bb, data)) = checker.rpo.next() {
1515 checker.visit_basic_block_data(bb, data);
1519 (checker.temp_promotion_state, checker.promotion_candidates)
1522 // Do the actual promotion, now that we know what's viable.
1523 promote_consts::promote_candidates(mir, tcx, temps, candidates);
1525 if !mir.control_flow_destroyed.is_empty() {
1526 let mut locals = mir.vars_iter();
1527 if let Some(local) = locals.next() {
1528 let span = mir.local_decls[local].source_info.span;
1529 let mut error = tcx.sess.struct_span_err(
1532 "new features like let bindings are not permitted in {}s \
1533 which also use short circuiting operators",
1537 for (span, kind) in mir.control_flow_destroyed.iter() {
1540 &format!("use of {} here does not actually short circuit due to \
1541 the const evaluator presently not being able to do control flow. \
1542 See https://github.com/rust-lang/rust/issues/49146 for more \
1543 information.", kind),
1546 for local in locals {
1547 let span = mir.local_decls[local].source_info.span;
1550 "more locals defined here",
1556 let promoted_temps = if mode == Mode::Const {
1557 // Already computed by `mir_const_qualif`.
1558 const_promoted_temps.unwrap()
1560 Checker::new(tcx, def_id, mir, mode).check_const().1
1563 // In `const` and `static` everything without `StorageDead`
1564 // is `'static`, we don't have to create promoted MIR fragments,
1565 // just remove `Drop` and `StorageDead` on "promoted" locals.
1566 debug!("run_pass: promoted_temps={:?}", promoted_temps);
1567 for block in mir.basic_blocks_mut() {
1568 block.statements.retain(|statement| {
1569 match statement.kind {
1570 StatementKind::StorageDead(index) => {
1571 !promoted_temps.contains(index)
1576 let terminator = block.terminator_mut();
1577 match terminator.kind {
1578 TerminatorKind::Drop {
1579 location: Place::Base(PlaceBase::Local(index)),
1583 if promoted_temps.contains(index) {
1584 terminator.kind = TerminatorKind::Goto {
1594 // Statics must be Sync.
1595 if mode == Mode::Static {
1596 // `#[thread_local]` statics don't have to be `Sync`.
1597 for attr in &tcx.get_attrs(def_id)[..] {
1598 if attr.check_name(sym::thread_local) {
1602 let ty = mir.return_ty();
1603 tcx.infer_ctxt().enter(|infcx| {
1604 let param_env = ty::ParamEnv::empty();
1605 let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
1606 let mut fulfillment_cx = traits::FulfillmentContext::new();
1607 fulfillment_cx.register_bound(&infcx,
1610 tcx.require_lang_item(lang_items::SyncTraitLangItem),
1612 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
1613 infcx.report_fulfillment_errors(&err, None, false);
1620 fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
1621 let attrs = tcx.get_attrs(def_id);
1622 let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
1623 let mut ret = FxHashSet::default();
1624 for meta in attr.meta_item_list()? {
1625 match meta.literal()?.node {
1626 LitKind::Int(a, _) => { ret.insert(a as usize); }