1#![allow(internal_features)]
5#![doc(rust_logo)]
6#![feature(assert_matches)]
7#![feature(box_patterns)]
8#![feature(file_buffered)]
9#![feature(if_let_guard)]
10#![feature(negative_impls)]
11#![feature(never_type)]
12#![feature(rustc_attrs)]
13#![feature(rustdoc_internals)]
14#![feature(stmt_expr_attributes)]
15#![feature(try_blocks)]
16use std::borrow::Cow;
19use std::cell::{OnceCell, RefCell};
20use std::marker::PhantomData;
21use std::ops::{ControlFlow, Deref};
22
23use borrow_set::LocalsStateAtExit;
24use root_cx::BorrowCheckRootCtxt;
25use rustc_abi::FieldIdx;
26use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
27use rustc_data_structures::graph::dominators::Dominators;
28use rustc_errors::LintDiagnostic;
29use rustc_hir as hir;
30use rustc_hir::CRATE_HIR_ID;
31use rustc_hir::def_id::LocalDefId;
32use rustc_index::bit_set::MixedBitSet;
33use rustc_index::{IndexSlice, IndexVec};
34use rustc_infer::infer::{
35 InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
36};
37use rustc_middle::mir::*;
38use rustc_middle::query::Providers;
39use rustc_middle::ty::{
40 self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions,
41};
42use rustc_middle::{bug, span_bug};
43use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
44use rustc_mir_dataflow::move_paths::{
45 InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
46};
47use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
48use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
49use rustc_span::{ErrorGuaranteed, Span, Symbol};
50use smallvec::SmallVec;
51use tracing::{debug, instrument};
52
53use crate::borrow_set::{BorrowData, BorrowSet};
54use crate::consumers::BodyWithBorrowckFacts;
55use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
56use crate::diagnostics::{
57 AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
58};
59use crate::path_utils::*;
60use crate::place_ext::PlaceExt;
61use crate::places_conflict::{PlaceConflictBias, places_conflict};
62use crate::polonius::PoloniusDiagnosticsContext;
63use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
64use crate::prefixes::PrefixSet;
65use crate::region_infer::RegionInferenceContext;
66use crate::renumber::RegionCtxt;
67use crate::session_diagnostics::VarNeedNotMut;
68
69mod borrow_set;
70mod borrowck_errors;
71mod constraints;
72mod dataflow;
73mod def_use;
74mod diagnostics;
75mod handle_placeholders;
76mod member_constraints;
77mod nll;
78mod path_utils;
79mod place_ext;
80mod places_conflict;
81mod polonius;
82mod prefixes;
83mod region_infer;
84mod renumber;
85mod root_cx;
86mod session_diagnostics;
87mod type_check;
88mod universal_regions;
89mod used_muts;
90
91pub mod consumers;
93
94rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
95
96struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
98
99impl<'tcx> TyCtxtConsts<'tcx> {
100 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
101}
102
103pub fn provide(providers: &mut Providers) {
104 *providers = Providers { mir_borrowck, ..*providers };
105}
106
107fn mir_borrowck(
111 tcx: TyCtxt<'_>,
112 def: LocalDefId,
113) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
114 assert!(!tcx.is_typeck_child(def.to_def_id()));
115 let (input_body, _) = tcx.mir_promoted(def);
116 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
117
118 let input_body: &Body<'_> = &input_body.borrow();
119 if let Some(guar) = input_body.tainted_by_errors {
120 debug!("Skipping borrowck because of tainted body");
121 Err(guar)
122 } else if input_body.should_skip() {
123 debug!("Skipping borrowck because of injected body");
124 let opaque_types = ConcreteOpaqueTypes(Default::default());
125 Ok(tcx.arena.alloc(opaque_types))
126 } else {
127 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
128 let nested_bodies = tcx.nested_bodies_within(def);
132 for def_id in nested_bodies {
133 root_cx.get_or_insert_nested(def_id);
134 }
135
136 let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
137 do_mir_borrowck(&mut root_cx, def);
138 debug_assert!(closure_requirements.is_none());
139 debug_assert!(used_mut_upvars.is_empty());
140 root_cx.finalize()
141 }
142}
143
144#[derive(Debug)]
147struct PropagatedBorrowCheckResults<'tcx> {
148 closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
149 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
150}
151
152#[derive(Clone, Debug)]
195pub struct ClosureRegionRequirements<'tcx> {
196 pub num_external_vids: usize,
202
203 pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
206}
207
208#[derive(Copy, Clone, Debug)]
211pub struct ClosureOutlivesRequirement<'tcx> {
212 pub subject: ClosureOutlivesSubject<'tcx>,
214
215 pub outlived_free_region: ty::RegionVid,
217
218 pub blame_span: Span,
220
221 pub category: ConstraintCategory<'tcx>,
223}
224
225#[cfg(target_pointer_width = "64")]
227rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
228
229#[derive(Copy, Clone, Debug)]
232pub enum ClosureOutlivesSubject<'tcx> {
233 Ty(ClosureOutlivesSubjectTy<'tcx>),
237
238 Region(ty::RegionVid),
241}
242
243#[derive(Copy, Clone, Debug)]
249pub struct ClosureOutlivesSubjectTy<'tcx> {
250 inner: Ty<'tcx>,
251}
252impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
255impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
256
257impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
258 pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
261 let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
262 ty::ReVar(vid) => {
263 let br = ty::BoundRegion {
264 var: ty::BoundVar::from_usize(vid.index()),
265 kind: ty::BoundRegionKind::Anon,
266 };
267 ty::Region::new_bound(tcx, depth, br)
268 }
269 _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
270 });
271
272 Self { inner }
273 }
274
275 pub fn instantiate(
276 self,
277 tcx: TyCtxt<'tcx>,
278 mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
279 ) -> Ty<'tcx> {
280 fold_regions(tcx, self.inner, |r, depth| match r.kind() {
281 ty::ReBound(debruijn, br) => {
282 debug_assert_eq!(debruijn, depth);
283 map(ty::RegionVid::from_usize(br.var.index()))
284 }
285 _ => bug!("unexpected region {r:?}"),
286 })
287 }
288}
289
290#[instrument(skip(root_cx), level = "debug")]
294fn do_mir_borrowck<'tcx>(
295 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
296 def: LocalDefId,
297) -> PropagatedBorrowCheckResults<'tcx> {
298 let tcx = root_cx.tcx;
299 let infcx = BorrowckInferCtxt::new(tcx, def);
300 let (input_body, promoted) = tcx.mir_promoted(def);
301 let input_body: &Body<'_> = &input_body.borrow();
302 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
303 if let Some(e) = input_body.tainted_by_errors {
304 infcx.set_tainted_by_errors(e);
305 root_cx.set_tainted_by_errors(e);
306 }
307
308 let mut body_owned = input_body.clone();
313 let mut promoted = input_promoted.to_owned();
314 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
315 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
318
319 let move_data = MoveData::gather_moves(body, tcx, |_| true);
320
321 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
322 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
323
324 let nll::NllOutput {
326 regioncx,
327 polonius_input,
328 polonius_output,
329 opt_closure_req,
330 nll_errors,
331 polonius_diagnostics,
332 } = nll::compute_regions(
333 root_cx,
334 &infcx,
335 universal_regions,
336 body,
337 &promoted,
338 &location_table,
339 &move_data,
340 &borrow_set,
341 );
342
343 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
346 polonius::dump_polonius_mir(
347 &infcx,
348 body,
349 ®ioncx,
350 &opt_closure_req,
351 &borrow_set,
352 polonius_diagnostics.as_ref(),
353 );
354
355 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
358
359 let movable_coroutine = body.coroutine.is_some()
360 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
361
362 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
363 for promoted_body in &promoted {
366 use rustc_middle::mir::visit::Visitor;
367 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
371 let mut promoted_mbcx = MirBorrowckCtxt {
372 root_cx,
373 infcx: &infcx,
374 body: promoted_body,
375 move_data: &move_data,
376 location_table: &location_table,
378 movable_coroutine,
379 fn_self_span_reported: Default::default(),
380 access_place_error_reported: Default::default(),
381 reservation_error_reported: Default::default(),
382 uninitialized_error_reported: Default::default(),
383 regioncx: ®ioncx,
384 used_mut: Default::default(),
385 used_mut_upvars: SmallVec::new(),
386 borrow_set: &borrow_set,
387 upvars: &[],
388 local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
389 region_names: RefCell::default(),
390 next_region_name: RefCell::new(1),
391 polonius_output: None,
392 move_errors: Vec::new(),
393 diags_buffer,
394 polonius_diagnostics: polonius_diagnostics.as_ref(),
395 };
396 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
397 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
398 }
399
400 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
401 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
402 if let Operand::Move(place) = operand {
403 self.ctxt.check_movable_place(location, *place);
404 }
405 }
406 }
407 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
408 promoted_mbcx.report_move_errors();
409 }
410
411 let mut mbcx = MirBorrowckCtxt {
412 root_cx,
413 infcx: &infcx,
414 body,
415 move_data: &move_data,
416 location_table: &location_table,
417 movable_coroutine,
418 fn_self_span_reported: Default::default(),
419 access_place_error_reported: Default::default(),
420 reservation_error_reported: Default::default(),
421 uninitialized_error_reported: Default::default(),
422 regioncx: ®ioncx,
423 used_mut: Default::default(),
424 used_mut_upvars: SmallVec::new(),
425 borrow_set: &borrow_set,
426 upvars: tcx.closure_captures(def),
427 local_names: OnceCell::new(),
428 region_names: RefCell::default(),
429 next_region_name: RefCell::new(1),
430 move_errors: Vec::new(),
431 diags_buffer,
432 polonius_output: polonius_output.as_deref(),
433 polonius_diagnostics: polonius_diagnostics.as_ref(),
434 };
435
436 mbcx.report_region_errors(nll_errors);
438
439 let (mut flow_analysis, flow_entry_states) =
440 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
441 visit_results(
442 body,
443 traversal::reverse_postorder(body).map(|(bb, _)| bb),
444 &mut flow_analysis,
445 &flow_entry_states,
446 &mut mbcx,
447 );
448
449 mbcx.report_move_errors();
450
451 let temporary_used_locals: FxIndexSet<Local> = mbcx
457 .used_mut
458 .iter()
459 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
460 .cloned()
461 .collect();
462 let unused_mut_locals =
466 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
467 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
468
469 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
470 mbcx.lint_unused_mut();
471 if let Some(guar) = mbcx.emit_errors() {
472 mbcx.root_cx.set_tainted_by_errors(guar);
473 }
474
475 let result = PropagatedBorrowCheckResults {
476 closure_requirements: opt_closure_req,
477 used_mut_upvars: mbcx.used_mut_upvars,
478 };
479
480 if let Some(consumer) = &mut root_cx.consumer {
481 consumer.insert_body(
482 def,
483 BodyWithBorrowckFacts {
484 body: body_owned,
485 promoted,
486 borrow_set,
487 region_inference_context: regioncx,
488 location_table: polonius_input.as_ref().map(|_| location_table),
489 input_facts: polonius_input,
490 output_facts: polonius_output,
491 },
492 );
493 }
494
495 debug!("do_mir_borrowck: result = {:#?}", result);
496
497 result
498}
499
500fn get_flow_results<'a, 'tcx>(
501 tcx: TyCtxt<'tcx>,
502 body: &'a Body<'tcx>,
503 move_data: &'a MoveData<'tcx>,
504 borrow_set: &'a BorrowSet<'tcx>,
505 regioncx: &RegionInferenceContext<'tcx>,
506) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
507 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
510 tcx,
511 body,
512 Some("borrowck"),
513 );
514 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
515 tcx,
516 body,
517 Some("borrowck"),
518 );
519 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
520 tcx,
521 body,
522 Some("borrowck"),
523 );
524
525 let analysis = Borrowck {
526 borrows: borrows.analysis,
527 uninits: uninits.analysis,
528 ever_inits: ever_inits.analysis,
529 };
530
531 assert_eq!(borrows.results.len(), uninits.results.len());
532 assert_eq!(borrows.results.len(), ever_inits.results.len());
533 let results: Results<_> =
534 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
535 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
536 .collect();
537
538 (analysis, results)
539}
540
541pub(crate) struct BorrowckInferCtxt<'tcx> {
542 pub(crate) infcx: InferCtxt<'tcx>,
543 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
544 pub(crate) param_env: ParamEnv<'tcx>,
545}
546
547impl<'tcx> BorrowckInferCtxt<'tcx> {
548 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
549 let typing_mode = if tcx.use_typing_mode_borrowck() {
550 TypingMode::borrowck(tcx, def_id)
551 } else {
552 TypingMode::analysis_in_body(tcx, def_id)
553 };
554 let infcx = tcx.infer_ctxt().build(typing_mode);
555 let param_env = tcx.param_env(def_id);
556 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
557 }
558
559 pub(crate) fn next_region_var<F>(
560 &self,
561 origin: RegionVariableOrigin,
562 get_ctxt_fn: F,
563 ) -> ty::Region<'tcx>
564 where
565 F: Fn() -> RegionCtxt,
566 {
567 let next_region = self.infcx.next_region_var(origin);
568 let vid = next_region.as_var();
569
570 if cfg!(debug_assertions) {
571 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
572 let ctxt = get_ctxt_fn();
573 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
574 assert_eq!(var_to_origin.insert(vid, ctxt), None);
575 }
576
577 next_region
578 }
579
580 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
581 pub(crate) fn next_nll_region_var<F>(
582 &self,
583 origin: NllRegionVariableOrigin,
584 get_ctxt_fn: F,
585 ) -> ty::Region<'tcx>
586 where
587 F: Fn() -> RegionCtxt,
588 {
589 let next_region = self.infcx.next_nll_region_var(origin);
590 let vid = next_region.as_var();
591
592 if cfg!(debug_assertions) {
593 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
594 let ctxt = get_ctxt_fn();
595 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
596 assert_eq!(var_to_origin.insert(vid, ctxt), None);
597 }
598
599 next_region
600 }
601}
602
603impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
604 type Target = InferCtxt<'tcx>;
605
606 fn deref(&self) -> &Self::Target {
607 &self.infcx
608 }
609}
610
611struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
612 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
613 infcx: &'infcx BorrowckInferCtxt<'tcx>,
614 body: &'a Body<'tcx>,
615 move_data: &'a MoveData<'tcx>,
616
617 location_table: &'a PoloniusLocationTable,
620
621 movable_coroutine: bool,
622 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
628 reservation_error_reported: FxIndexSet<Place<'tcx>>,
636 fn_self_span_reported: FxIndexSet<Span>,
640 uninitialized_error_reported: FxIndexSet<Local>,
643 used_mut: FxIndexSet<Local>,
646 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
649 regioncx: &'a RegionInferenceContext<'tcx>,
652
653 borrow_set: &'a BorrowSet<'tcx>,
655
656 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
658
659 local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
661
662 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
665
666 next_region_name: RefCell<usize>,
668
669 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
670 move_errors: Vec<MoveError<'tcx>>,
671
672 polonius_output: Option<&'a PoloniusOutput>,
674 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
676}
677
678impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
684 fn visit_after_early_statement_effect(
685 &mut self,
686 _analysis: &mut Borrowck<'a, 'tcx>,
687 state: &BorrowckDomain,
688 stmt: &Statement<'tcx>,
689 location: Location,
690 ) {
691 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
692 let span = stmt.source_info.span;
693
694 self.check_activations(location, span, state);
695
696 match &stmt.kind {
697 StatementKind::Assign(box (lhs, rhs)) => {
698 self.consume_rvalue(location, (rhs, span), state);
699
700 self.mutate_place(location, (*lhs, span), Shallow(None), state);
701 }
702 StatementKind::FakeRead(box (_, place)) => {
703 self.check_if_path_or_subpath_is_moved(
714 location,
715 InitializationRequiringAction::Use,
716 (place.as_ref(), span),
717 state,
718 );
719 }
720 StatementKind::Intrinsic(box kind) => match kind {
721 NonDivergingIntrinsic::Assume(op) => {
722 self.consume_operand(location, (op, span), state);
723 }
724 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
725 span,
726 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
727 )
728 }
729 StatementKind::AscribeUserType(..)
731 | StatementKind::PlaceMention(..)
733 | StatementKind::Coverage(..)
735 | StatementKind::ConstEvalCounter
737 | StatementKind::StorageLive(..) => {}
738 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
740 self.check_backward_incompatible_drop(location, **place, state);
741 }
742 StatementKind::StorageDead(local) => {
743 self.access_place(
744 location,
745 (Place::from(*local), span),
746 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
747 LocalMutationIsAllowed::Yes,
748 state,
749 );
750 }
751 StatementKind::Nop
752 | StatementKind::Retag { .. }
753 | StatementKind::Deinit(..)
754 | StatementKind::SetDiscriminant { .. } => {
755 bug!("Statement not allowed in this MIR phase")
756 }
757 }
758 }
759
760 fn visit_after_early_terminator_effect(
761 &mut self,
762 _analysis: &mut Borrowck<'a, 'tcx>,
763 state: &BorrowckDomain,
764 term: &Terminator<'tcx>,
765 loc: Location,
766 ) {
767 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
768 let span = term.source_info.span;
769
770 self.check_activations(loc, span, state);
771
772 match &term.kind {
773 TerminatorKind::SwitchInt { discr, targets: _ } => {
774 self.consume_operand(loc, (discr, span), state);
775 }
776 TerminatorKind::Drop {
777 place,
778 target: _,
779 unwind: _,
780 replace,
781 drop: _,
782 async_fut: _,
783 } => {
784 debug!(
785 "visit_terminator_drop \
786 loc: {:?} term: {:?} place: {:?} span: {:?}",
787 loc, term, place, span
788 );
789
790 let write_kind =
791 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
792 self.access_place(
793 loc,
794 (*place, span),
795 (AccessDepth::Drop, Write(write_kind)),
796 LocalMutationIsAllowed::Yes,
797 state,
798 );
799 }
800 TerminatorKind::Call {
801 func,
802 args,
803 destination,
804 target: _,
805 unwind: _,
806 call_source: _,
807 fn_span: _,
808 } => {
809 self.consume_operand(loc, (func, span), state);
810 for arg in args {
811 self.consume_operand(loc, (&arg.node, arg.span), state);
812 }
813 self.mutate_place(loc, (*destination, span), Deep, state);
814 }
815 TerminatorKind::TailCall { func, args, fn_span: _ } => {
816 self.consume_operand(loc, (func, span), state);
817 for arg in args {
818 self.consume_operand(loc, (&arg.node, arg.span), state);
819 }
820 }
821 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
822 self.consume_operand(loc, (cond, span), state);
823 if let AssertKind::BoundsCheck { len, index } = &**msg {
824 self.consume_operand(loc, (len, span), state);
825 self.consume_operand(loc, (index, span), state);
826 }
827 }
828
829 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
830 self.consume_operand(loc, (value, span), state);
831 self.mutate_place(loc, (*resume_arg, span), Deep, state);
832 }
833
834 TerminatorKind::InlineAsm {
835 asm_macro: _,
836 template: _,
837 operands,
838 options: _,
839 line_spans: _,
840 targets: _,
841 unwind: _,
842 } => {
843 for op in operands {
844 match op {
845 InlineAsmOperand::In { reg: _, value } => {
846 self.consume_operand(loc, (value, span), state);
847 }
848 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
849 if let Some(place) = place {
850 self.mutate_place(loc, (*place, span), Shallow(None), state);
851 }
852 }
853 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
854 self.consume_operand(loc, (in_value, span), state);
855 if let &Some(out_place) = out_place {
856 self.mutate_place(loc, (out_place, span), Shallow(None), state);
857 }
858 }
859 InlineAsmOperand::Const { value: _ }
860 | InlineAsmOperand::SymFn { value: _ }
861 | InlineAsmOperand::SymStatic { def_id: _ }
862 | InlineAsmOperand::Label { target_index: _ } => {}
863 }
864 }
865 }
866
867 TerminatorKind::Goto { target: _ }
868 | TerminatorKind::UnwindTerminate(_)
869 | TerminatorKind::Unreachable
870 | TerminatorKind::UnwindResume
871 | TerminatorKind::Return
872 | TerminatorKind::CoroutineDrop
873 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
874 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
875 }
877 }
878 }
879
880 fn visit_after_primary_terminator_effect(
881 &mut self,
882 _analysis: &mut Borrowck<'a, 'tcx>,
883 state: &BorrowckDomain,
884 term: &Terminator<'tcx>,
885 loc: Location,
886 ) {
887 let span = term.source_info.span;
888
889 match term.kind {
890 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
891 if self.movable_coroutine {
892 for i in state.borrows.iter() {
894 let borrow = &self.borrow_set[i];
895 self.check_for_local_borrow(borrow, span);
896 }
897 }
898 }
899
900 TerminatorKind::UnwindResume
901 | TerminatorKind::Return
902 | TerminatorKind::TailCall { .. }
903 | TerminatorKind::CoroutineDrop => {
904 match self.borrow_set.locals_state_at_exit() {
905 LocalsStateAtExit::AllAreInvalidated => {
906 for i in state.borrows.iter() {
911 let borrow = &self.borrow_set[i];
912 self.check_for_invalidation_at_exit(loc, borrow, span);
913 }
914 }
915 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
918 }
919 }
920
921 TerminatorKind::UnwindTerminate(_)
922 | TerminatorKind::Assert { .. }
923 | TerminatorKind::Call { .. }
924 | TerminatorKind::Drop { .. }
925 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
926 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
927 | TerminatorKind::Goto { .. }
928 | TerminatorKind::SwitchInt { .. }
929 | TerminatorKind::Unreachable
930 | TerminatorKind::InlineAsm { .. } => {}
931 }
932 }
933}
934
935use self::AccessDepth::{Deep, Shallow};
936use self::ReadOrWrite::{Activation, Read, Reservation, Write};
937
938#[derive(Copy, Clone, PartialEq, Eq, Debug)]
939enum ArtificialField {
940 ArrayLength,
941 FakeBorrow,
942}
943
944#[derive(Copy, Clone, PartialEq, Eq, Debug)]
945enum AccessDepth {
946 Shallow(Option<ArtificialField>),
952
953 Deep,
957
958 Drop,
961}
962
963#[derive(Copy, Clone, PartialEq, Eq, Debug)]
966enum ReadOrWrite {
967 Read(ReadKind),
970
971 Write(WriteKind),
975
976 Reservation(WriteKind),
980 Activation(WriteKind, BorrowIndex),
981}
982
983#[derive(Copy, Clone, PartialEq, Eq, Debug)]
986enum ReadKind {
987 Borrow(BorrowKind),
988 Copy,
989}
990
991#[derive(Copy, Clone, PartialEq, Eq, Debug)]
994enum WriteKind {
995 StorageDeadOrDrop,
996 Replace,
997 MutableBorrow(BorrowKind),
998 Mutate,
999 Move,
1000}
1001
1002#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1010enum LocalMutationIsAllowed {
1011 Yes,
1012 ExceptUpvars,
1015 No,
1016}
1017
1018#[derive(Copy, Clone, Debug)]
1019enum InitializationRequiringAction {
1020 Borrow,
1021 MatchOn,
1022 Use,
1023 Assignment,
1024 PartialAssignment,
1025}
1026
1027#[derive(Debug)]
1028struct RootPlace<'tcx> {
1029 place_local: Local,
1030 place_projection: &'tcx [PlaceElem<'tcx>],
1031 is_local_mutation_allowed: LocalMutationIsAllowed,
1032}
1033
1034impl InitializationRequiringAction {
1035 fn as_noun(self) -> &'static str {
1036 match self {
1037 InitializationRequiringAction::Borrow => "borrow",
1038 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1040 InitializationRequiringAction::Assignment => "assign",
1041 InitializationRequiringAction::PartialAssignment => "assign to part",
1042 }
1043 }
1044
1045 fn as_verb_in_past_tense(self) -> &'static str {
1046 match self {
1047 InitializationRequiringAction::Borrow => "borrowed",
1048 InitializationRequiringAction::MatchOn => "matched on",
1049 InitializationRequiringAction::Use => "used",
1050 InitializationRequiringAction::Assignment => "assigned",
1051 InitializationRequiringAction::PartialAssignment => "partially assigned",
1052 }
1053 }
1054
1055 fn as_general_verb_in_past_tense(self) -> &'static str {
1056 match self {
1057 InitializationRequiringAction::Borrow
1058 | InitializationRequiringAction::MatchOn
1059 | InitializationRequiringAction::Use => "used",
1060 InitializationRequiringAction::Assignment => "assigned",
1061 InitializationRequiringAction::PartialAssignment => "partially assigned",
1062 }
1063 }
1064}
1065
1066impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1067 fn body(&self) -> &'a Body<'tcx> {
1068 self.body
1069 }
1070
1071 fn access_place(
1078 &mut self,
1079 location: Location,
1080 place_span: (Place<'tcx>, Span),
1081 kind: (AccessDepth, ReadOrWrite),
1082 is_local_mutation_allowed: LocalMutationIsAllowed,
1083 state: &BorrowckDomain,
1084 ) {
1085 let (sd, rw) = kind;
1086
1087 if let Activation(_, borrow_index) = rw {
1088 if self.reservation_error_reported.contains(&place_span.0) {
1089 debug!(
1090 "skipping access_place for activation of invalid reservation \
1091 place: {:?} borrow_index: {:?}",
1092 place_span.0, borrow_index
1093 );
1094 return;
1095 }
1096 }
1097
1098 if !self.access_place_error_reported.is_empty()
1101 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1102 {
1103 debug!(
1104 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1105 place_span, kind
1106 );
1107 return;
1108 }
1109
1110 let mutability_error = self.check_access_permissions(
1111 place_span,
1112 rw,
1113 is_local_mutation_allowed,
1114 state,
1115 location,
1116 );
1117 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1118
1119 if conflict_error || mutability_error {
1120 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1121 self.access_place_error_reported.insert((place_span.0, place_span.1));
1122 }
1123 }
1124
1125 fn borrows_in_scope<'s>(
1126 &self,
1127 location: Location,
1128 state: &'s BorrowckDomain,
1129 ) -> Cow<'s, MixedBitSet<BorrowIndex>> {
1130 if let Some(polonius) = &self.polonius_output {
1131 let location = self.location_table.start_index(location);
1133 let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
1134 for &idx in polonius.errors_at(location) {
1135 polonius_output.insert(idx);
1136 }
1137 Cow::Owned(polonius_output)
1138 } else {
1139 Cow::Borrowed(&state.borrows)
1140 }
1141 }
1142
1143 #[instrument(level = "debug", skip(self, state))]
1144 fn check_access_for_conflict(
1145 &mut self,
1146 location: Location,
1147 place_span: (Place<'tcx>, Span),
1148 sd: AccessDepth,
1149 rw: ReadOrWrite,
1150 state: &BorrowckDomain,
1151 ) -> bool {
1152 let mut error_reported = false;
1153
1154 let borrows_in_scope = self.borrows_in_scope(location, state);
1155
1156 each_borrow_involving_path(
1157 self,
1158 self.infcx.tcx,
1159 self.body,
1160 (sd, place_span.0),
1161 self.borrow_set,
1162 |borrow_index| borrows_in_scope.contains(borrow_index),
1163 |this, borrow_index, borrow| match (rw, borrow.kind) {
1164 (Activation(_, activating), _) if activating == borrow_index => {
1171 debug!(
1172 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1173 skipping {:?} b/c activation of same borrow_index",
1174 place_span,
1175 sd,
1176 rw,
1177 (borrow_index, borrow),
1178 );
1179 ControlFlow::Continue(())
1180 }
1181
1182 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1183 | (
1184 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1185 BorrowKind::Mut { .. },
1186 ) => ControlFlow::Continue(()),
1187
1188 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1189 ControlFlow::Continue(())
1192 }
1193
1194 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1195 ControlFlow::Continue(())
1197 }
1198
1199 (Read(kind), BorrowKind::Mut { .. }) => {
1200 if !is_active(this.dominators(), borrow, location) {
1202 assert!(borrow.kind.allows_two_phase_borrow());
1203 return ControlFlow::Continue(());
1204 }
1205
1206 error_reported = true;
1207 match kind {
1208 ReadKind::Copy => {
1209 let err = this
1210 .report_use_while_mutably_borrowed(location, place_span, borrow);
1211 this.buffer_error(err);
1212 }
1213 ReadKind::Borrow(bk) => {
1214 let err =
1215 this.report_conflicting_borrow(location, place_span, bk, borrow);
1216 this.buffer_error(err);
1217 }
1218 }
1219 ControlFlow::Break(())
1220 }
1221
1222 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1223 match rw {
1224 Reservation(..) => {
1225 debug!(
1226 "recording invalid reservation of \
1227 place: {:?}",
1228 place_span.0
1229 );
1230 this.reservation_error_reported.insert(place_span.0);
1231 }
1232 Activation(_, activating) => {
1233 debug!(
1234 "observing check_place for activation of \
1235 borrow_index: {:?}",
1236 activating
1237 );
1238 }
1239 Read(..) | Write(..) => {}
1240 }
1241
1242 error_reported = true;
1243 match kind {
1244 WriteKind::MutableBorrow(bk) => {
1245 let err =
1246 this.report_conflicting_borrow(location, place_span, bk, borrow);
1247 this.buffer_error(err);
1248 }
1249 WriteKind::StorageDeadOrDrop => this
1250 .report_borrowed_value_does_not_live_long_enough(
1251 location,
1252 borrow,
1253 place_span,
1254 Some(WriteKind::StorageDeadOrDrop),
1255 ),
1256 WriteKind::Mutate => {
1257 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1258 }
1259 WriteKind::Move => {
1260 this.report_move_out_while_borrowed(location, place_span, borrow)
1261 }
1262 WriteKind::Replace => {
1263 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1264 }
1265 }
1266 ControlFlow::Break(())
1267 }
1268 },
1269 );
1270
1271 error_reported
1272 }
1273
1274 #[instrument(level = "debug", skip(self, state))]
1277 fn check_backward_incompatible_drop(
1278 &mut self,
1279 location: Location,
1280 place: Place<'tcx>,
1281 state: &BorrowckDomain,
1282 ) {
1283 let tcx = self.infcx.tcx;
1284 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1288 AccessDepth::Drop
1289 } else {
1290 AccessDepth::Shallow(None)
1291 };
1292
1293 let borrows_in_scope = self.borrows_in_scope(location, state);
1294
1295 each_borrow_involving_path(
1298 self,
1299 self.infcx.tcx,
1300 self.body,
1301 (sd, place),
1302 self.borrow_set,
1303 |borrow_index| borrows_in_scope.contains(borrow_index),
1304 |this, _borrow_index, borrow| {
1305 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1306 return ControlFlow::Continue(());
1307 }
1308 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1309 let explain = this.explain_why_borrow_contains_point(
1310 location,
1311 borrow,
1312 Some((WriteKind::StorageDeadOrDrop, place)),
1313 );
1314 this.infcx.tcx.node_span_lint(
1315 TAIL_EXPR_DROP_ORDER,
1316 CRATE_HIR_ID,
1317 borrowed,
1318 |diag| {
1319 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1320 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1321 },
1322 );
1323 ControlFlow::Break(())
1325 },
1326 );
1327 }
1328
1329 fn mutate_place(
1330 &mut self,
1331 location: Location,
1332 place_span: (Place<'tcx>, Span),
1333 kind: AccessDepth,
1334 state: &BorrowckDomain,
1335 ) {
1336 self.check_if_assigned_path_is_moved(location, place_span, state);
1338
1339 self.access_place(
1340 location,
1341 place_span,
1342 (kind, Write(WriteKind::Mutate)),
1343 LocalMutationIsAllowed::No,
1344 state,
1345 );
1346 }
1347
1348 fn consume_rvalue(
1349 &mut self,
1350 location: Location,
1351 (rvalue, span): (&Rvalue<'tcx>, Span),
1352 state: &BorrowckDomain,
1353 ) {
1354 match rvalue {
1355 &Rvalue::Ref(_ , bk, place) => {
1356 let access_kind = match bk {
1357 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1358 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1359 }
1360 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1361 (Deep, Read(ReadKind::Borrow(bk)))
1362 }
1363 BorrowKind::Mut { .. } => {
1364 let wk = WriteKind::MutableBorrow(bk);
1365 if bk.allows_two_phase_borrow() {
1366 (Deep, Reservation(wk))
1367 } else {
1368 (Deep, Write(wk))
1369 }
1370 }
1371 };
1372
1373 self.access_place(
1374 location,
1375 (place, span),
1376 access_kind,
1377 LocalMutationIsAllowed::No,
1378 state,
1379 );
1380
1381 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1382 InitializationRequiringAction::MatchOn
1383 } else {
1384 InitializationRequiringAction::Borrow
1385 };
1386
1387 self.check_if_path_or_subpath_is_moved(
1388 location,
1389 action,
1390 (place.as_ref(), span),
1391 state,
1392 );
1393 }
1394
1395 &Rvalue::RawPtr(kind, place) => {
1396 let access_kind = match kind {
1397 RawPtrKind::Mut => (
1398 Deep,
1399 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1400 kind: MutBorrowKind::Default,
1401 })),
1402 ),
1403 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1404 RawPtrKind::FakeForPtrMetadata => {
1405 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1406 }
1407 };
1408
1409 self.access_place(
1410 location,
1411 (place, span),
1412 access_kind,
1413 LocalMutationIsAllowed::No,
1414 state,
1415 );
1416
1417 self.check_if_path_or_subpath_is_moved(
1418 location,
1419 InitializationRequiringAction::Borrow,
1420 (place.as_ref(), span),
1421 state,
1422 );
1423 }
1424
1425 Rvalue::ThreadLocalRef(_) => {}
1426
1427 Rvalue::Use(operand)
1428 | Rvalue::Repeat(operand, _)
1429 | Rvalue::UnaryOp(_ , operand)
1430 | Rvalue::Cast(_ , operand, _ )
1431 | Rvalue::ShallowInitBox(operand, _ ) => {
1432 self.consume_operand(location, (operand, span), state)
1433 }
1434
1435 &Rvalue::CopyForDeref(place) => {
1436 self.access_place(
1437 location,
1438 (place, span),
1439 (Deep, Read(ReadKind::Copy)),
1440 LocalMutationIsAllowed::No,
1441 state,
1442 );
1443
1444 self.check_if_path_or_subpath_is_moved(
1446 location,
1447 InitializationRequiringAction::Use,
1448 (place.as_ref(), span),
1449 state,
1450 );
1451 }
1452
1453 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1454 let af = match *rvalue {
1455 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1456 Rvalue::Discriminant(..) => None,
1457 _ => unreachable!(),
1458 };
1459 self.access_place(
1460 location,
1461 (place, span),
1462 (Shallow(af), Read(ReadKind::Copy)),
1463 LocalMutationIsAllowed::No,
1464 state,
1465 );
1466 self.check_if_path_or_subpath_is_moved(
1467 location,
1468 InitializationRequiringAction::Use,
1469 (place.as_ref(), span),
1470 state,
1471 );
1472 }
1473
1474 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1475 self.consume_operand(location, (operand1, span), state);
1476 self.consume_operand(location, (operand2, span), state);
1477 }
1478
1479 Rvalue::NullaryOp(_op, _ty) => {
1480 }
1482
1483 Rvalue::Aggregate(aggregate_kind, operands) => {
1484 match **aggregate_kind {
1488 AggregateKind::Closure(def_id, _)
1489 | AggregateKind::CoroutineClosure(def_id, _)
1490 | AggregateKind::Coroutine(def_id, _) => {
1491 let def_id = def_id.expect_local();
1492 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1493 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1494 for field in used_mut_upvars.clone() {
1498 self.propagate_closure_used_mut_upvar(&operands[field]);
1499 }
1500 }
1501 AggregateKind::Adt(..)
1502 | AggregateKind::Array(..)
1503 | AggregateKind::Tuple { .. }
1504 | AggregateKind::RawPtr(..) => (),
1505 }
1506
1507 for operand in operands {
1508 self.consume_operand(location, (operand, span), state);
1509 }
1510 }
1511
1512 Rvalue::WrapUnsafeBinder(op, _) => {
1513 self.consume_operand(location, (op, span), state);
1514 }
1515 }
1516 }
1517
1518 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1519 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1520 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1528 this.used_mut_upvars.push(field);
1529 return;
1530 }
1531
1532 for (place_ref, proj) in place.iter_projections().rev() {
1533 if proj == ProjectionElem::Deref {
1535 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1536 ty::Ref(_, _, hir::Mutability::Mut) => return,
1538
1539 _ => {}
1540 }
1541 }
1542
1543 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1545 this.used_mut_upvars.push(field);
1546 return;
1547 }
1548 }
1549
1550 this.used_mut.insert(place.local);
1552 };
1553
1554 match *operand {
1558 Operand::Move(place) | Operand::Copy(place) => {
1559 match place.as_local() {
1560 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1561 if self.body.local_decls[local].ty.is_mutable_ptr() {
1562 return;
1564 }
1565 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1581 bug!("temporary should be tracked");
1582 };
1583 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1584 &self.move_data.inits[init_index]
1585 } else {
1586 bug!("temporary should be initialized exactly once")
1587 };
1588
1589 let InitLocation::Statement(loc) = init.location else {
1590 bug!("temporary initialized in arguments")
1591 };
1592
1593 let body = self.body;
1594 let bbd = &body[loc.block];
1595 let stmt = &bbd.statements[loc.statement_index];
1596 debug!("temporary assigned in: stmt={:?}", stmt);
1597
1598 match stmt.kind {
1599 StatementKind::Assign(box (
1600 _,
1601 Rvalue::Ref(_, _, source)
1602 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1603 )) => {
1604 propagate_closure_used_mut_place(self, source);
1605 }
1606 _ => {
1607 bug!(
1608 "closures should only capture user variables \
1609 or references to user variables"
1610 );
1611 }
1612 }
1613 }
1614 _ => propagate_closure_used_mut_place(self, place),
1615 }
1616 }
1617 Operand::Constant(..) => {}
1618 }
1619 }
1620
1621 fn consume_operand(
1622 &mut self,
1623 location: Location,
1624 (operand, span): (&Operand<'tcx>, Span),
1625 state: &BorrowckDomain,
1626 ) {
1627 match *operand {
1628 Operand::Copy(place) => {
1629 self.access_place(
1632 location,
1633 (place, span),
1634 (Deep, Read(ReadKind::Copy)),
1635 LocalMutationIsAllowed::No,
1636 state,
1637 );
1638
1639 self.check_if_path_or_subpath_is_moved(
1641 location,
1642 InitializationRequiringAction::Use,
1643 (place.as_ref(), span),
1644 state,
1645 );
1646 }
1647 Operand::Move(place) => {
1648 self.check_movable_place(location, place);
1650
1651 self.access_place(
1653 location,
1654 (place, span),
1655 (Deep, Write(WriteKind::Move)),
1656 LocalMutationIsAllowed::Yes,
1657 state,
1658 );
1659
1660 self.check_if_path_or_subpath_is_moved(
1662 location,
1663 InitializationRequiringAction::Use,
1664 (place.as_ref(), span),
1665 state,
1666 );
1667 }
1668 Operand::Constant(_) => {}
1669 }
1670 }
1671
1672 #[instrument(level = "debug", skip(self))]
1675 fn check_for_invalidation_at_exit(
1676 &mut self,
1677 location: Location,
1678 borrow: &BorrowData<'tcx>,
1679 span: Span,
1680 ) {
1681 let place = borrow.borrowed_place;
1682 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1683
1684 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1690 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1694 true
1695 } else {
1696 false
1697 };
1698
1699 let sd = if might_be_alive { Deep } else { Shallow(None) };
1700
1701 if places_conflict::borrow_conflicts_with_place(
1702 self.infcx.tcx,
1703 self.body,
1704 place,
1705 borrow.kind,
1706 root_place,
1707 sd,
1708 places_conflict::PlaceConflictBias::Overlap,
1709 ) {
1710 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1711 let span = self.infcx.tcx.sess.source_map().end_point(span);
1714 self.report_borrowed_value_does_not_live_long_enough(
1715 location,
1716 borrow,
1717 (place, span),
1718 None,
1719 )
1720 }
1721 }
1722
1723 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1726 debug!("check_for_local_borrow({:?})", borrow);
1727
1728 if borrow_of_local_data(borrow.borrowed_place) {
1729 let err = self.cannot_borrow_across_coroutine_yield(
1730 self.retrieve_borrow_spans(borrow).var_or_use(),
1731 yield_span,
1732 );
1733
1734 self.buffer_error(err);
1735 }
1736 }
1737
1738 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1739 for &borrow_index in self.borrow_set.activations_at_location(location) {
1743 let borrow = &self.borrow_set[borrow_index];
1744
1745 assert!(match borrow.kind {
1747 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1748 BorrowKind::Mut { .. } => true,
1749 });
1750
1751 self.access_place(
1752 location,
1753 (borrow.borrowed_place, span),
1754 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1755 LocalMutationIsAllowed::No,
1756 state,
1757 );
1758 }
1762 }
1763
1764 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1765 use IllegalMoveOriginKind::*;
1766
1767 let body = self.body;
1768 let tcx = self.infcx.tcx;
1769 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1770 for (place_ref, elem) in place.iter_projections() {
1771 match elem {
1772 ProjectionElem::Deref => match place_ty.ty.kind() {
1773 ty::Ref(..) | ty::RawPtr(..) => {
1774 self.move_errors.push(MoveError::new(
1775 place,
1776 location,
1777 BorrowedContent {
1778 target_place: place_ref.project_deeper(&[elem], tcx),
1779 },
1780 ));
1781 return;
1782 }
1783 ty::Adt(adt, _) => {
1784 if !adt.is_box() {
1785 bug!("Adt should be a box type when Place is deref");
1786 }
1787 }
1788 ty::Bool
1789 | ty::Char
1790 | ty::Int(_)
1791 | ty::Uint(_)
1792 | ty::Float(_)
1793 | ty::Foreign(_)
1794 | ty::Str
1795 | ty::Array(_, _)
1796 | ty::Pat(_, _)
1797 | ty::Slice(_)
1798 | ty::FnDef(_, _)
1799 | ty::FnPtr(..)
1800 | ty::Dynamic(_, _, _)
1801 | ty::Closure(_, _)
1802 | ty::CoroutineClosure(_, _)
1803 | ty::Coroutine(_, _)
1804 | ty::CoroutineWitness(..)
1805 | ty::Never
1806 | ty::Tuple(_)
1807 | ty::UnsafeBinder(_)
1808 | ty::Alias(_, _)
1809 | ty::Param(_)
1810 | ty::Bound(_, _)
1811 | ty::Infer(_)
1812 | ty::Error(_)
1813 | ty::Placeholder(_) => {
1814 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1815 }
1816 },
1817 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1818 ty::Adt(adt, _) => {
1819 if adt.has_dtor(tcx) {
1820 self.move_errors.push(MoveError::new(
1821 place,
1822 location,
1823 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1824 ));
1825 return;
1826 }
1827 }
1828 ty::Closure(..)
1829 | ty::CoroutineClosure(..)
1830 | ty::Coroutine(_, _)
1831 | ty::Tuple(_) => (),
1832 ty::Bool
1833 | ty::Char
1834 | ty::Int(_)
1835 | ty::Uint(_)
1836 | ty::Float(_)
1837 | ty::Foreign(_)
1838 | ty::Str
1839 | ty::Array(_, _)
1840 | ty::Pat(_, _)
1841 | ty::Slice(_)
1842 | ty::RawPtr(_, _)
1843 | ty::Ref(_, _, _)
1844 | ty::FnDef(_, _)
1845 | ty::FnPtr(..)
1846 | ty::Dynamic(_, _, _)
1847 | ty::CoroutineWitness(..)
1848 | ty::Never
1849 | ty::UnsafeBinder(_)
1850 | ty::Alias(_, _)
1851 | ty::Param(_)
1852 | ty::Bound(_, _)
1853 | ty::Infer(_)
1854 | ty::Error(_)
1855 | ty::Placeholder(_) => bug!(
1856 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1857 ),
1858 },
1859 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1860 match place_ty.ty.kind() {
1861 ty::Slice(_) => {
1862 self.move_errors.push(MoveError::new(
1863 place,
1864 location,
1865 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1866 ));
1867 return;
1868 }
1869 ty::Array(_, _) => (),
1870 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1871 }
1872 }
1873 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1874 ty::Array(..) | ty::Slice(..) => {
1875 self.move_errors.push(MoveError::new(
1876 place,
1877 location,
1878 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1879 ));
1880 return;
1881 }
1882 _ => bug!("Unexpected type {place_ty:#?}"),
1883 },
1884 ProjectionElem::OpaqueCast(_)
1889 | ProjectionElem::Subtype(_)
1890 | ProjectionElem::Downcast(_, _)
1891 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1892 }
1893
1894 place_ty = place_ty.projection_ty(tcx, elem);
1895 }
1896 }
1897
1898 fn check_if_full_path_is_moved(
1899 &mut self,
1900 location: Location,
1901 desired_action: InitializationRequiringAction,
1902 place_span: (PlaceRef<'tcx>, Span),
1903 state: &BorrowckDomain,
1904 ) {
1905 let maybe_uninits = &state.uninits;
1906
1907 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1943 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1944 if maybe_uninits.contains(mpi) {
1945 self.report_use_of_moved_or_uninitialized(
1946 location,
1947 desired_action,
1948 (prefix, place_span.0, place_span.1),
1949 mpi,
1950 );
1951 } }
1958
1959 fn check_if_subslice_element_is_moved(
1965 &mut self,
1966 location: Location,
1967 desired_action: InitializationRequiringAction,
1968 place_span: (PlaceRef<'tcx>, Span),
1969 maybe_uninits: &MixedBitSet<MovePathIndex>,
1970 from: u64,
1971 to: u64,
1972 ) {
1973 if let Some(mpi) = self.move_path_for_place(place_span.0) {
1974 let move_paths = &self.move_data.move_paths;
1975
1976 let root_path = &move_paths[mpi];
1977 for (child_mpi, child_move_path) in root_path.children(move_paths) {
1978 let last_proj = child_move_path.place.projection.last().unwrap();
1979 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
1980 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
1981
1982 if (from..to).contains(offset) {
1983 let uninit_child =
1984 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
1985 maybe_uninits.contains(mpi)
1986 });
1987
1988 if let Some(uninit_child) = uninit_child {
1989 self.report_use_of_moved_or_uninitialized(
1990 location,
1991 desired_action,
1992 (place_span.0, place_span.0, place_span.1),
1993 uninit_child,
1994 );
1995 return; }
1997 }
1998 }
1999 }
2000 }
2001 }
2002
2003 fn check_if_path_or_subpath_is_moved(
2004 &mut self,
2005 location: Location,
2006 desired_action: InitializationRequiringAction,
2007 place_span: (PlaceRef<'tcx>, Span),
2008 state: &BorrowckDomain,
2009 ) {
2010 let maybe_uninits = &state.uninits;
2011
2012 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2028
2029 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2030 place_span.0.last_projection()
2031 {
2032 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2033 if let ty::Array(..) = place_ty.ty.kind() {
2034 self.check_if_subslice_element_is_moved(
2035 location,
2036 desired_action,
2037 (place_base, place_span.1),
2038 maybe_uninits,
2039 from,
2040 to,
2041 );
2042 return;
2043 }
2044 }
2045
2046 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2056 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2057 let uninit_mpi = self
2058 .move_data
2059 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2060
2061 if let Some(uninit_mpi) = uninit_mpi {
2062 self.report_use_of_moved_or_uninitialized(
2063 location,
2064 desired_action,
2065 (place_span.0, place_span.0, place_span.1),
2066 uninit_mpi,
2067 );
2068 return; }
2070 }
2071 }
2072
2073 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2084 match self.move_data.rev_lookup.find(place) {
2085 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2086 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2087 }
2088 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2089 }
2090 }
2091
2092 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2093 match self.move_data.rev_lookup.find(place) {
2098 LookupResult::Parent(_) => None,
2099 LookupResult::Exact(mpi) => Some(mpi),
2100 }
2101 }
2102
2103 fn check_if_assigned_path_is_moved(
2104 &mut self,
2105 location: Location,
2106 (place, span): (Place<'tcx>, Span),
2107 state: &BorrowckDomain,
2108 ) {
2109 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2110
2111 for (place_base, elem) in place.iter_projections().rev() {
2113 match elem {
2114 ProjectionElem::Index(_) |
2115 ProjectionElem::Subtype(_) |
2116 ProjectionElem::OpaqueCast(_) |
2117 ProjectionElem::ConstantIndex { .. } |
2118 ProjectionElem::Downcast(_, _) =>
2120 { }
2124
2125 ProjectionElem::UnwrapUnsafeBinder(_) => {
2126 check_parent_of_field(self, location, place_base, span, state);
2127 }
2128
2129 ProjectionElem::Deref => {
2131 self.check_if_full_path_is_moved(
2132 location, InitializationRequiringAction::Use,
2133 (place_base, span), state);
2134 break;
2137 }
2138
2139 ProjectionElem::Subslice { .. } => {
2140 panic!("we don't allow assignments to subslices, location: {location:?}");
2141 }
2142
2143 ProjectionElem::Field(..) => {
2144 let tcx = self.infcx.tcx;
2148 let base_ty = place_base.ty(self.body(), tcx).ty;
2149 match base_ty.kind() {
2150 ty::Adt(def, _) if def.has_dtor(tcx) => {
2151 self.check_if_path_or_subpath_is_moved(
2152 location, InitializationRequiringAction::Assignment,
2153 (place_base, span), state);
2154
2155 break;
2158 }
2159
2160 ty::Adt(..) | ty::Tuple(..) => {
2163 check_parent_of_field(self, location, place_base, span, state);
2164 }
2165
2166 _ => {}
2167 }
2168 }
2169 }
2170 }
2171
2172 fn check_parent_of_field<'a, 'tcx>(
2173 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2174 location: Location,
2175 base: PlaceRef<'tcx>,
2176 span: Span,
2177 state: &BorrowckDomain,
2178 ) {
2179 let maybe_uninits = &state.uninits;
2211
2212 let mut shortest_uninit_seen = None;
2215 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2216 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2217
2218 if maybe_uninits.contains(mpi) {
2219 debug!(
2220 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2221 shortest_uninit_seen,
2222 Some((prefix, mpi))
2223 );
2224 shortest_uninit_seen = Some((prefix, mpi));
2225 } else {
2226 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2227 }
2228 }
2229
2230 if let Some((prefix, mpi)) = shortest_uninit_seen {
2231 let tcx = this.infcx.tcx;
2237 if base.ty(this.body(), tcx).ty.is_union()
2238 && this.move_data.path_map[mpi].iter().any(|moi| {
2239 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2240 })
2241 {
2242 return;
2243 }
2244
2245 this.report_use_of_moved_or_uninitialized(
2246 location,
2247 InitializationRequiringAction::PartialAssignment,
2248 (prefix, base, span),
2249 mpi,
2250 );
2251
2252 this.used_mut.insert(base.local);
2256 }
2257 }
2258 }
2259
2260 fn check_access_permissions(
2264 &mut self,
2265 (place, span): (Place<'tcx>, Span),
2266 kind: ReadOrWrite,
2267 is_local_mutation_allowed: LocalMutationIsAllowed,
2268 state: &BorrowckDomain,
2269 location: Location,
2270 ) -> bool {
2271 debug!(
2272 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2273 place, kind, is_local_mutation_allowed
2274 );
2275
2276 let error_access;
2277 let the_place_err;
2278
2279 match kind {
2280 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2281 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2282 let is_local_mutation_allowed = match mut_borrow_kind {
2283 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2287 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2288 is_local_mutation_allowed
2289 }
2290 };
2291 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2292 Ok(root_place) => {
2293 self.add_used_mut(root_place, state);
2294 return false;
2295 }
2296 Err(place_err) => {
2297 error_access = AccessKind::MutableBorrow;
2298 the_place_err = place_err;
2299 }
2300 }
2301 }
2302 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2303 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2304 Ok(root_place) => {
2305 self.add_used_mut(root_place, state);
2306 return false;
2307 }
2308 Err(place_err) => {
2309 error_access = AccessKind::Mutate;
2310 the_place_err = place_err;
2311 }
2312 }
2313 }
2314
2315 Reservation(
2316 WriteKind::Move
2317 | WriteKind::Replace
2318 | WriteKind::StorageDeadOrDrop
2319 | WriteKind::MutableBorrow(BorrowKind::Shared)
2320 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2321 )
2322 | Write(
2323 WriteKind::Move
2324 | WriteKind::Replace
2325 | WriteKind::StorageDeadOrDrop
2326 | WriteKind::MutableBorrow(BorrowKind::Shared)
2327 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2328 ) => {
2329 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2330 && !self.has_buffered_diags()
2331 {
2332 self.dcx().span_delayed_bug(
2338 span,
2339 format!(
2340 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2341 ),
2342 );
2343 }
2344 return false;
2345 }
2346 Activation(..) => {
2347 return false;
2349 }
2350 Read(
2351 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2352 | ReadKind::Copy,
2353 ) => {
2354 return false;
2356 }
2357 }
2358
2359 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2364
2365 if let Some(init_index) = previously_initialized {
2367 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2368 let init = &self.move_data.inits[init_index];
2371 let assigned_span = init.span(self.body);
2372 self.report_illegal_reassignment((place, span), assigned_span, place);
2373 } else {
2374 self.report_mutability_error(place, span, the_place_err, error_access, location)
2375 }
2376 true
2377 } else {
2378 false
2379 }
2380 }
2381
2382 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2383 let mpi = self.move_data.rev_lookup.find_local(local)?;
2384 let ii = &self.move_data.init_path_map[mpi];
2385 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2386 }
2387
2388 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2390 match root_place {
2391 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2392 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2396 && self.is_local_ever_initialized(local, state).is_some()
2397 {
2398 self.used_mut.insert(local);
2399 }
2400 }
2401 RootPlace {
2402 place_local: _,
2403 place_projection: _,
2404 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2405 } => {}
2406 RootPlace {
2407 place_local,
2408 place_projection: place_projection @ [.., _],
2409 is_local_mutation_allowed: _,
2410 } => {
2411 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2412 local: place_local,
2413 projection: place_projection,
2414 }) {
2415 self.used_mut_upvars.push(field);
2416 }
2417 }
2418 }
2419 }
2420
2421 fn is_mutable(
2424 &self,
2425 place: PlaceRef<'tcx>,
2426 is_local_mutation_allowed: LocalMutationIsAllowed,
2427 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2428 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2429 match place.last_projection() {
2430 None => {
2431 let local = &self.body.local_decls[place.local];
2432 match local.mutability {
2433 Mutability::Not => match is_local_mutation_allowed {
2434 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2435 place_local: place.local,
2436 place_projection: place.projection,
2437 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2438 }),
2439 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2440 place_local: place.local,
2441 place_projection: place.projection,
2442 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2443 }),
2444 LocalMutationIsAllowed::No => Err(place),
2445 },
2446 Mutability::Mut => Ok(RootPlace {
2447 place_local: place.local,
2448 place_projection: place.projection,
2449 is_local_mutation_allowed,
2450 }),
2451 }
2452 }
2453 Some((place_base, elem)) => {
2454 match elem {
2455 ProjectionElem::Deref => {
2456 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2457
2458 match base_ty.kind() {
2460 ty::Ref(_, _, mutbl) => {
2461 match mutbl {
2462 hir::Mutability::Not => Err(place),
2464 hir::Mutability::Mut => {
2467 let mode = match self.is_upvar_field_projection(place) {
2468 Some(field)
2469 if self.upvars[field.index()].is_by_ref() =>
2470 {
2471 is_local_mutation_allowed
2472 }
2473 _ => LocalMutationIsAllowed::Yes,
2474 };
2475
2476 self.is_mutable(place_base, mode)
2477 }
2478 }
2479 }
2480 ty::RawPtr(_, mutbl) => {
2481 match mutbl {
2482 hir::Mutability::Not => Err(place),
2484 hir::Mutability::Mut => Ok(RootPlace {
2487 place_local: place.local,
2488 place_projection: place.projection,
2489 is_local_mutation_allowed,
2490 }),
2491 }
2492 }
2493 _ if base_ty.is_box() => {
2495 self.is_mutable(place_base, is_local_mutation_allowed)
2496 }
2497 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2499 }
2500 }
2501 ProjectionElem::Field(..)
2504 | ProjectionElem::Index(..)
2505 | ProjectionElem::ConstantIndex { .. }
2506 | ProjectionElem::Subslice { .. }
2507 | ProjectionElem::Subtype(..)
2508 | ProjectionElem::OpaqueCast { .. }
2509 | ProjectionElem::Downcast(..)
2510 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2511 let upvar_field_projection = self.is_upvar_field_projection(place);
2512 if let Some(field) = upvar_field_projection {
2513 let upvar = &self.upvars[field.index()];
2514 debug!(
2515 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2516 place={:?}, place_base={:?}",
2517 upvar, is_local_mutation_allowed, place, place_base
2518 );
2519 match (upvar.mutability, is_local_mutation_allowed) {
2520 (
2521 Mutability::Not,
2522 LocalMutationIsAllowed::No
2523 | LocalMutationIsAllowed::ExceptUpvars,
2524 ) => Err(place),
2525 (Mutability::Not, LocalMutationIsAllowed::Yes)
2526 | (Mutability::Mut, _) => {
2527 let _ =
2546 self.is_mutable(place_base, is_local_mutation_allowed)?;
2547 Ok(RootPlace {
2548 place_local: place.local,
2549 place_projection: place.projection,
2550 is_local_mutation_allowed,
2551 })
2552 }
2553 }
2554 } else {
2555 self.is_mutable(place_base, is_local_mutation_allowed)
2556 }
2557 }
2558 }
2559 }
2560 }
2561 }
2562
2563 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2568 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2569 }
2570
2571 fn dominators(&self) -> &Dominators<BasicBlock> {
2572 self.body.basic_blocks.dominators()
2574 }
2575
2576 fn lint_unused_mut(&self) {
2577 let tcx = self.infcx.tcx;
2578 let body = self.body;
2579 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2580 let local_decl = &body.local_decls[local];
2581 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2582 body.source_scopes[local_decl.source_info.scope].local_data
2583 else {
2584 continue;
2585 };
2586
2587 if self.local_excluded_from_unused_mut_lint(local) {
2589 continue;
2590 }
2591
2592 let span = local_decl.source_info.span;
2593 if span.desugaring_kind().is_some() {
2594 continue;
2596 }
2597
2598 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2599
2600 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2601 }
2602 }
2603}
2604
2605enum Overlap {
2607 Arbitrary,
2613 EqualOrDisjoint,
2618 Disjoint,
2621}