]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/check_consts/validation.rs
Use unified dataflow framework in `check_consts`
[rust.git] / src / librustc_mir / transform / check_consts / validation.rs
1 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
2
3 use rustc::middle::lang_items;
4 use rustc::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
5 use rustc::mir::*;
6 use rustc::traits::{self, TraitEngine};
7 use rustc::ty::cast::CastTy;
8 use rustc::ty::{self, TyCtxt};
9 use rustc_error_codes::*;
10 use rustc_errors::struct_span_err;
11 use rustc_hir::{def_id::DefId, HirId};
12 use rustc_index::bit_set::BitSet;
13 use rustc_span::symbol::sym;
14 use rustc_span::Span;
15
16 use std::borrow::Cow;
17 use std::ops::Deref;
18
19 use self::old_dataflow::IndirectlyMutableLocals;
20 use super::ops::{self, NonConstOp};
21 use super::qualifs::{self, HasMutInterior, NeedsDrop};
22 use super::resolver::FlowSensitiveAnalysis;
23 use super::{is_lang_panic_fn, ConstKind, Item, Qualif};
24 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
25 use crate::dataflow::{self as old_dataflow, generic as dataflow};
26
27 pub type IndirectlyMutableResults<'mir, 'tcx> =
28     old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>;
29
30 struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> {
31     cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
32     in_any_value_of_ty: BitSet<Local>,
33 }
34
35 impl<Q: Qualif> QualifCursor<'a, 'mir, 'tcx, Q> {
36     pub fn new(q: Q, item: &'a Item<'mir, 'tcx>) -> Self {
37         let analysis = FlowSensitiveAnalysis::new(q, item);
38         let results = dataflow::Engine::new_generic(item.tcx, &item.body, item.def_id, analysis)
39             .iterate_to_fixpoint();
40         let cursor = dataflow::ResultsCursor::new(*item.body, results);
41
42         let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
43         for (local, decl) in item.body.local_decls.iter_enumerated() {
44             if Q::in_any_value_of_ty(item, decl.ty) {
45                 in_any_value_of_ty.insert(local);
46             }
47         }
48
49         QualifCursor { cursor, in_any_value_of_ty }
50     }
51 }
52
53 pub struct Qualifs<'a, 'mir, 'tcx> {
54     has_mut_interior: QualifCursor<'a, 'mir, 'tcx, HasMutInterior>,
55     needs_drop: QualifCursor<'a, 'mir, 'tcx, NeedsDrop>,
56     indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>,
57 }
58
59 impl Qualifs<'a, 'mir, 'tcx> {
60     fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool {
61         self.indirectly_mutable.seek(location);
62         self.indirectly_mutable.get().contains(local)
63     }
64
65     /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
66     ///
67     /// Only updates the cursor if absolutely necessary
68     fn needs_drop_lazy_seek(&mut self, local: Local, location: Location) -> bool {
69         if !self.needs_drop.in_any_value_of_ty.contains(local) {
70             return false;
71         }
72
73         self.needs_drop.cursor.seek_before(location);
74         self.needs_drop.cursor.get().contains(local) || self.indirectly_mutable(local, location)
75     }
76
77     /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
78     ///
79     /// Only updates the cursor if absolutely necessary.
80     fn has_mut_interior_lazy_seek(&mut self, local: Local, location: Location) -> bool {
81         if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
82             return false;
83         }
84
85         self.has_mut_interior.cursor.seek_before(location);
86         self.has_mut_interior.cursor.get().contains(local)
87             || self.indirectly_mutable(local, location)
88     }
89
90     /// Returns `true` if `local` is `HasMutInterior`, but requires the `has_mut_interior` and
91     /// `indirectly_mutable` cursors to be updated beforehand.
92     fn has_mut_interior_eager_seek(&self, local: Local) -> bool {
93         if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
94             return false;
95         }
96
97         self.has_mut_interior.cursor.get().contains(local)
98             || self.indirectly_mutable.get().contains(local)
99     }
100
101     fn in_return_place(&mut self, item: &Item<'_, 'tcx>) -> ConstQualifs {
102         // Find the `Return` terminator if one exists.
103         //
104         // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
105         // qualifs for the return type.
106         let return_block = item
107             .body
108             .basic_blocks()
109             .iter_enumerated()
110             .find(|(_, block)| match block.terminator().kind {
111                 TerminatorKind::Return => true,
112                 _ => false,
113             })
114             .map(|(bb, _)| bb);
115
116         let return_block = match return_block {
117             None => return qualifs::in_any_value_of_ty(item, item.body.return_ty()),
118             Some(bb) => bb,
119         };
120
121         let return_loc = item.body.terminator_loc(return_block);
122
123         ConstQualifs {
124             needs_drop: self.needs_drop_lazy_seek(RETURN_PLACE, return_loc),
125             has_mut_interior: self.has_mut_interior_lazy_seek(RETURN_PLACE, return_loc),
126         }
127     }
128 }
129
130 pub struct Validator<'a, 'mir, 'tcx> {
131     item: &'a Item<'mir, 'tcx>,
132     qualifs: Qualifs<'a, 'mir, 'tcx>,
133
134     /// The span of the current statement.
135     span: Span,
136 }
137
138 impl Deref for Validator<'_, 'mir, 'tcx> {
139     type Target = Item<'mir, 'tcx>;
140
141     fn deref(&self) -> &Self::Target {
142         &self.item
143     }
144 }
145
146 impl Validator<'a, 'mir, 'tcx> {
147     pub fn new(item: &'a Item<'mir, 'tcx>) -> Self {
148         let needs_drop = QualifCursor::new(NeedsDrop, item);
149         let has_mut_interior = QualifCursor::new(HasMutInterior, item);
150
151         let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len());
152         let indirectly_mutable = old_dataflow::do_dataflow(
153             item.tcx,
154             &*item.body,
155             item.def_id,
156             &item.tcx.get_attrs(item.def_id),
157             &dead_unwinds,
158             old_dataflow::IndirectlyMutableLocals::new(item.tcx, *item.body, item.param_env),
159             |_, local| old_dataflow::DebugFormatted::new(&local),
160         );
161
162         let indirectly_mutable =
163             old_dataflow::DataflowResultsCursor::new(indirectly_mutable, *item.body);
164
165         let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable };
166
167         Validator { span: item.body.span, item, qualifs }
168     }
169
170     pub fn check_body(&mut self) {
171         let Item { tcx, body, def_id, const_kind, .. } = *self.item;
172
173         let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn)
174             && crate::const_eval::is_min_const_fn(tcx, def_id))
175             && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you;
176
177         if use_min_const_fn_checks {
178             // Enforce `min_const_fn` for stable `const fn`s.
179             use crate::transform::qualify_min_const_fn::is_min_const_fn;
180             if let Err((span, err)) = is_min_const_fn(tcx, def_id, &body) {
181                 error_min_const_fn_violation(tcx, span, err);
182                 return;
183             }
184         }
185
186         check_short_circuiting_in_const_local(self.item);
187
188         if body.is_cfg_cyclic() {
189             // We can't provide a good span for the error here, but this should be caught by the
190             // HIR const-checker anyways.
191             self.check_op_spanned(ops::Loop, body.span);
192         }
193
194         self.visit_body(body);
195
196         // Ensure that the end result is `Sync` in a non-thread local `static`.
197         let should_check_for_sync =
198             const_kind == Some(ConstKind::Static) && !tcx.has_attr(def_id, sym::thread_local);
199
200         if should_check_for_sync {
201             let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
202             check_return_ty_is_sync(tcx, &body, hir_id);
203         }
204     }
205
206     pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
207         self.qualifs.in_return_place(self.item)
208     }
209
210     /// Emits an error at the given `span` if an expression cannot be evaluated in the current
211     /// context.
212     pub fn check_op_spanned<O>(&mut self, op: O, span: Span)
213     where
214         O: NonConstOp,
215     {
216         trace!("check_op: op={:?}", op);
217
218         if op.is_allowed_in_item(self) {
219             return;
220         }
221
222         // If an operation is supported in miri (and is not already controlled by a feature gate) it
223         // can be turned on with `-Zunleash-the-miri-inside-of-you`.
224         let is_unleashable = O::IS_SUPPORTED_IN_MIRI && O::feature_gate(self.tcx).is_none();
225
226         if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
227             self.tcx.sess.span_warn(span, "skipping const checks");
228             return;
229         }
230
231         op.emit_error(self, span);
232     }
233
234     /// Emits an error if an expression cannot be evaluated in the current context.
235     pub fn check_op(&mut self, op: impl NonConstOp) {
236         let span = self.span;
237         self.check_op_spanned(op, span)
238     }
239
240     fn check_static(&mut self, def_id: DefId, span: Span) {
241         let is_thread_local = self.tcx.has_attr(def_id, sym::thread_local);
242         if is_thread_local {
243             self.check_op_spanned(ops::ThreadLocalAccess, span)
244         } else {
245             self.check_op_spanned(ops::StaticAccess, span)
246         }
247     }
248
249     fn check_immutable_borrow_like(&mut self, location: Location, place: &Place<'tcx>) {
250         // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
251         // seek the cursors beforehand.
252         self.qualifs.has_mut_interior.cursor.seek_before(location);
253         self.qualifs.indirectly_mutable.seek(location);
254
255         let borrowed_place_has_mut_interior = HasMutInterior::in_place(
256             &self.item,
257             &|local| self.qualifs.has_mut_interior_eager_seek(local),
258             place.as_ref(),
259         );
260
261         if borrowed_place_has_mut_interior {
262             self.check_op(ops::CellBorrow);
263         }
264     }
265 }
266
267 impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
268     fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
269         trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
270
271         // Just as the old checker did, we skip const-checking basic blocks on the unwind path.
272         // These blocks often drop locals that would otherwise be returned from the function.
273         //
274         // FIXME: This shouldn't be unsound since a panic at compile time will cause a compiler
275         // error anyway, but maybe we should do more here?
276         if block.is_cleanup {
277             return;
278         }
279
280         self.super_basic_block_data(bb, block);
281     }
282
283     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
284         trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
285
286         // Special-case reborrows to be more like a copy of a reference.
287         match *rvalue {
288             Rvalue::Ref(_, kind, ref place) => {
289                 if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
290                     let ctx = match kind {
291                         BorrowKind::Shared => {
292                             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
293                         }
294                         BorrowKind::Shallow => {
295                             PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
296                         }
297                         BorrowKind::Unique => {
298                             PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
299                         }
300                         BorrowKind::Mut { .. } => {
301                             PlaceContext::MutatingUse(MutatingUseContext::Borrow)
302                         }
303                     };
304                     self.visit_place_base(&place.local, ctx, location);
305                     self.visit_projection(&place.local, reborrowed_proj, ctx, location);
306                     return;
307                 }
308             }
309             Rvalue::AddressOf(mutbl, ref place) => {
310                 if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
311                     let ctx = match mutbl {
312                         Mutability::Not => {
313                             PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
314                         }
315                         Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
316                     };
317                     self.visit_place_base(&place.local, ctx, location);
318                     self.visit_projection(&place.local, reborrowed_proj, ctx, location);
319                     return;
320                 }
321             }
322             _ => {}
323         }
324
325         self.super_rvalue(rvalue, location);
326
327         match *rvalue {
328             Rvalue::Use(_)
329             | Rvalue::Repeat(..)
330             | Rvalue::UnaryOp(UnOp::Neg, _)
331             | Rvalue::UnaryOp(UnOp::Not, _)
332             | Rvalue::NullaryOp(NullOp::SizeOf, _)
333             | Rvalue::CheckedBinaryOp(..)
334             | Rvalue::Cast(CastKind::Pointer(_), ..)
335             | Rvalue::Discriminant(..)
336             | Rvalue::Len(_)
337             | Rvalue::Aggregate(..) => {}
338
339             Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
340             | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
341                 let ty = place.ty(*self.body, self.tcx).ty;
342                 let is_allowed = match ty.kind {
343                     // Inside a `static mut`, `&mut [...]` is allowed.
344                     ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut => {
345                         true
346                     }
347
348                     // FIXME(ecstaticmorse): We could allow `&mut []` inside a const context given
349                     // that this is merely a ZST and it is already eligible for promotion.
350                     // This may require an RFC?
351                     /*
352                     ty::Array(_, len) if len.try_eval_usize(cx.tcx, cx.param_env) == Some(0)
353                         => true,
354                     */
355                     _ => false,
356                 };
357
358                 if !is_allowed {
359                     if let BorrowKind::Mut { .. } = kind {
360                         self.check_op(ops::MutBorrow);
361                     } else {
362                         self.check_op(ops::CellBorrow);
363                     }
364                 }
365             }
366
367             Rvalue::AddressOf(Mutability::Mut, _) => self.check_op(ops::MutAddressOf),
368
369             Rvalue::Ref(_, BorrowKind::Shared, ref place)
370             | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
371                 self.check_immutable_borrow_like(location, place)
372             }
373
374             Rvalue::AddressOf(Mutability::Not, ref place) => {
375                 self.check_immutable_borrow_like(location, place)
376             }
377
378             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
379                 let operand_ty = operand.ty(*self.body, self.tcx);
380                 let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
381                 let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
382
383                 if let (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) =
384                     (cast_in, cast_out)
385                 {
386                     self.check_op(ops::RawPtrToIntCast);
387                 }
388             }
389
390             Rvalue::BinaryOp(op, ref lhs, _) => {
391                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(*self.body, self.tcx).kind {
392                     assert!(
393                         op == BinOp::Eq
394                             || op == BinOp::Ne
395                             || op == BinOp::Le
396                             || op == BinOp::Lt
397                             || op == BinOp::Ge
398                             || op == BinOp::Gt
399                             || op == BinOp::Offset
400                     );
401
402                     self.check_op(ops::RawPtrComparison);
403                 }
404             }
405
406             Rvalue::NullaryOp(NullOp::Box, _) => {
407                 self.check_op(ops::HeapAllocation);
408             }
409         }
410     }
411
412     fn visit_place_base(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
413         trace!(
414             "visit_place_base: place_local={:?} context={:?} location={:?}",
415             place_local,
416             context,
417             location,
418         );
419         self.super_place_base(place_local, context, location);
420     }
421
422     fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
423         self.super_operand(op, location);
424         if let Operand::Constant(c) = op {
425             if let Some(def_id) = c.check_static_ptr(self.tcx) {
426                 self.check_static(def_id, self.span);
427             }
428         }
429     }
430     fn visit_projection_elem(
431         &mut self,
432         place_local: &Local,
433         proj_base: &[PlaceElem<'tcx>],
434         elem: &PlaceElem<'tcx>,
435         context: PlaceContext,
436         location: Location,
437     ) {
438         trace!(
439             "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
440             context={:?} location={:?}",
441             place_local,
442             proj_base,
443             elem,
444             context,
445             location,
446         );
447
448         self.super_projection_elem(place_local, proj_base, elem, context, location);
449
450         match elem {
451             ProjectionElem::Deref => {
452                 let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
453                 if let ty::RawPtr(_) = base_ty.kind {
454                     if proj_base.is_empty() {
455                         if let (local, []) = (place_local, proj_base) {
456                             let decl = &self.body.local_decls[*local];
457                             if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
458                                 let span = decl.source_info.span;
459                                 self.check_static(def_id, span);
460                                 return;
461                             }
462                         }
463                     }
464                     self.check_op(ops::RawPtrDeref);
465                 }
466
467                 if context.is_mutating_use() {
468                     self.check_op(ops::MutDeref);
469                 }
470             }
471
472             ProjectionElem::ConstantIndex { .. }
473             | ProjectionElem::Subslice { .. }
474             | ProjectionElem::Field(..)
475             | ProjectionElem::Index(_) => {
476                 let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty;
477                 match base_ty.ty_adt_def() {
478                     Some(def) if def.is_union() => {
479                         self.check_op(ops::UnionAccess);
480                     }
481
482                     _ => {}
483                 }
484             }
485
486             ProjectionElem::Downcast(..) => {
487                 self.check_op(ops::Downcast);
488             }
489         }
490     }
491
492     fn visit_source_info(&mut self, source_info: &SourceInfo) {
493         trace!("visit_source_info: source_info={:?}", source_info);
494         self.span = source_info.span;
495     }
496
497     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
498         trace!("visit_statement: statement={:?} location={:?}", statement, location);
499
500         match statement.kind {
501             StatementKind::Assign(..) | StatementKind::SetDiscriminant { .. } => {
502                 self.super_statement(statement, location);
503             }
504             StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _) => {
505                 self.check_op(ops::IfOrMatch);
506             }
507             // FIXME(eddyb) should these really do nothing?
508             StatementKind::FakeRead(..)
509             | StatementKind::StorageLive(_)
510             | StatementKind::StorageDead(_)
511             | StatementKind::InlineAsm { .. }
512             | StatementKind::Retag { .. }
513             | StatementKind::AscribeUserType(..)
514             | StatementKind::Nop => {}
515         }
516     }
517
518     fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) {
519         trace!("visit_terminator_kind: kind={:?} location={:?}", kind, location);
520         self.super_terminator_kind(kind, location);
521
522         match kind {
523             TerminatorKind::Call { func, .. } => {
524                 let fn_ty = func.ty(*self.body, self.tcx);
525
526                 let def_id = match fn_ty.kind {
527                     ty::FnDef(def_id, _) => def_id,
528
529                     ty::FnPtr(_) => {
530                         self.check_op(ops::FnCallIndirect);
531                         return;
532                     }
533                     _ => {
534                         self.check_op(ops::FnCallOther);
535                         return;
536                     }
537                 };
538
539                 // At this point, we are calling a function whose `DefId` is known...
540                 if is_const_fn(self.tcx, def_id) {
541                     return;
542                 }
543
544                 if is_lang_panic_fn(self.tcx, def_id) {
545                     self.check_op(ops::Panic);
546                 } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) {
547                     // Exempt unstable const fns inside of macros with
548                     // `#[allow_internal_unstable]`.
549                     if !self.span.allows_unstable(feature) {
550                         self.check_op(ops::FnCallUnstable(def_id, feature));
551                     }
552                 } else {
553                     self.check_op(ops::FnCallNonConst(def_id));
554                 }
555             }
556
557             // Forbid all `Drop` terminators unless the place being dropped is a local with no
558             // projections that cannot be `NeedsDrop`.
559             TerminatorKind::Drop { location: dropped_place, .. }
560             | TerminatorKind::DropAndReplace { location: dropped_place, .. } => {
561                 let mut err_span = self.span;
562
563                 // Check to see if the type of this place can ever have a drop impl. If not, this
564                 // `Drop` terminator is frivolous.
565                 let ty_needs_drop =
566                     dropped_place.ty(*self.body, self.tcx).ty.needs_drop(self.tcx, self.param_env);
567
568                 if !ty_needs_drop {
569                     return;
570                 }
571
572                 let needs_drop = if let Some(local) = dropped_place.as_local() {
573                     // Use the span where the local was declared as the span of the drop error.
574                     err_span = self.body.local_decls[local].source_info.span;
575                     self.qualifs.needs_drop_lazy_seek(local, location)
576                 } else {
577                     true
578                 };
579
580                 if needs_drop {
581                     self.check_op_spanned(ops::LiveDrop, err_span);
582                 }
583             }
584
585             _ => {}
586         }
587     }
588 }
589
590 fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) {
591     struct_span_err!(tcx.sess, span, E0723, "{}", msg)
592         .note("for more information, see issue https://github.com/rust-lang/rust/issues/57563")
593         .help("add `#![feature(const_fn)]` to the crate attributes to enable")
594         .emit();
595 }
596
597 fn check_short_circuiting_in_const_local(item: &Item<'_, 'tcx>) {
598     let body = item.body;
599
600     if body.control_flow_destroyed.is_empty() {
601         return;
602     }
603
604     let mut locals = body.vars_iter();
605     if let Some(local) = locals.next() {
606         let span = body.local_decls[local].source_info.span;
607         let mut error = item.tcx.sess.struct_span_err(
608             span,
609             &format!(
610                 "new features like let bindings are not permitted in {}s \
611                 which also use short circuiting operators",
612                 item.const_kind(),
613             ),
614         );
615         for (span, kind) in body.control_flow_destroyed.iter() {
616             error.span_note(
617                 *span,
618                 &format!(
619                     "use of {} here does not actually short circuit due to \
620                 the const evaluator presently not being able to do control flow. \
621                 See https://github.com/rust-lang/rust/issues/49146 for more \
622                 information.",
623                     kind
624                 ),
625             );
626         }
627         for local in locals {
628             let span = body.local_decls[local].source_info.span;
629             error.span_note(span, "more locals defined here");
630         }
631         error.emit();
632     }
633 }
634
635 fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
636     let ty = body.return_ty();
637     tcx.infer_ctxt().enter(|infcx| {
638         let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
639         let mut fulfillment_cx = traits::FulfillmentContext::new();
640         let sync_def_id = tcx.require_lang_item(lang_items::SyncTraitLangItem, Some(body.span));
641         fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
642         if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
643             infcx.report_fulfillment_errors(&err, None, false);
644         }
645     });
646 }
647
648 fn place_as_reborrow(
649     tcx: TyCtxt<'tcx>,
650     body: &Body<'tcx>,
651     place: &'a Place<'tcx>,
652 ) -> Option<&'a [PlaceElem<'tcx>]> {
653     place.projection.split_last().and_then(|(outermost, inner)| {
654         if outermost != &ProjectionElem::Deref {
655             return None;
656         }
657
658         // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
659         // that points to the allocation for the static. Don't treat these as reborrows.
660         if body.local_decls[place.local].is_ref_to_static() {
661             return None;
662         }
663
664         // Ensure the type being derefed is a reference and not a raw pointer.
665         //
666         // This is sufficient to prevent an access to a `static mut` from being marked as a
667         // reborrow, even if the check above were to disappear.
668         let inner_ty = Place::ty_from(&place.local, inner, body, tcx).ty;
669         match inner_ty.kind {
670             ty::Ref(..) => Some(inner),
671             _ => None,
672         }
673     })
674 }