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, ConsumerOptions};
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);
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, None).0;
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")]
298fn do_mir_borrowck<'tcx>(
299 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
300 def: LocalDefId,
301 consumer_options: Option<ConsumerOptions>,
302) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
303 let tcx = root_cx.tcx;
304 let infcx = BorrowckInferCtxt::new(tcx, def);
305 let (input_body, promoted) = tcx.mir_promoted(def);
306 let input_body: &Body<'_> = &input_body.borrow();
307 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
308 if let Some(e) = input_body.tainted_by_errors {
309 infcx.set_tainted_by_errors(e);
310 root_cx.set_tainted_by_errors(e);
311 }
312
313 let mut body_owned = input_body.clone();
318 let mut promoted = input_promoted.to_owned();
319 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
320 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
323
324 let move_data = MoveData::gather_moves(body, tcx, |_| true);
325
326 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
327 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
328
329 let nll::NllOutput {
331 regioncx,
332 polonius_input,
333 polonius_output,
334 opt_closure_req,
335 nll_errors,
336 polonius_diagnostics,
337 } = nll::compute_regions(
338 root_cx,
339 &infcx,
340 universal_regions,
341 body,
342 &promoted,
343 &location_table,
344 &move_data,
345 &borrow_set,
346 consumer_options,
347 );
348
349 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
352 polonius::dump_polonius_mir(
353 &infcx,
354 body,
355 ®ioncx,
356 &opt_closure_req,
357 &borrow_set,
358 polonius_diagnostics.as_ref(),
359 );
360
361 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
364
365 let movable_coroutine = body.coroutine.is_some()
366 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
367
368 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
369 for promoted_body in &promoted {
372 use rustc_middle::mir::visit::Visitor;
373 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
377 let mut promoted_mbcx = MirBorrowckCtxt {
378 root_cx,
379 infcx: &infcx,
380 body: promoted_body,
381 move_data: &move_data,
382 location_table: &location_table,
384 movable_coroutine,
385 fn_self_span_reported: Default::default(),
386 access_place_error_reported: Default::default(),
387 reservation_error_reported: Default::default(),
388 uninitialized_error_reported: Default::default(),
389 regioncx: ®ioncx,
390 used_mut: Default::default(),
391 used_mut_upvars: SmallVec::new(),
392 borrow_set: &borrow_set,
393 upvars: &[],
394 local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
395 region_names: RefCell::default(),
396 next_region_name: RefCell::new(1),
397 polonius_output: None,
398 move_errors: Vec::new(),
399 diags_buffer,
400 polonius_diagnostics: polonius_diagnostics.as_ref(),
401 };
402 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
403 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
404 }
405
406 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
407 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
408 if let Operand::Move(place) = operand {
409 self.ctxt.check_movable_place(location, *place);
410 }
411 }
412 }
413 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
414 promoted_mbcx.report_move_errors();
415 }
416
417 let mut mbcx = MirBorrowckCtxt {
418 root_cx,
419 infcx: &infcx,
420 body,
421 move_data: &move_data,
422 location_table: &location_table,
423 movable_coroutine,
424 fn_self_span_reported: Default::default(),
425 access_place_error_reported: Default::default(),
426 reservation_error_reported: Default::default(),
427 uninitialized_error_reported: Default::default(),
428 regioncx: ®ioncx,
429 used_mut: Default::default(),
430 used_mut_upvars: SmallVec::new(),
431 borrow_set: &borrow_set,
432 upvars: tcx.closure_captures(def),
433 local_names: OnceCell::new(),
434 region_names: RefCell::default(),
435 next_region_name: RefCell::new(1),
436 move_errors: Vec::new(),
437 diags_buffer,
438 polonius_output: polonius_output.as_deref(),
439 polonius_diagnostics: polonius_diagnostics.as_ref(),
440 };
441
442 mbcx.report_region_errors(nll_errors);
444
445 let (mut flow_analysis, flow_entry_states) =
446 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
447 visit_results(
448 body,
449 traversal::reverse_postorder(body).map(|(bb, _)| bb),
450 &mut flow_analysis,
451 &flow_entry_states,
452 &mut mbcx,
453 );
454
455 mbcx.report_move_errors();
456
457 let temporary_used_locals: FxIndexSet<Local> = mbcx
463 .used_mut
464 .iter()
465 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
466 .cloned()
467 .collect();
468 let unused_mut_locals =
472 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
473 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
474
475 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
476 mbcx.lint_unused_mut();
477 if let Some(guar) = mbcx.emit_errors() {
478 mbcx.root_cx.set_tainted_by_errors(guar);
479 }
480
481 let result = PropagatedBorrowCheckResults {
482 closure_requirements: opt_closure_req,
483 used_mut_upvars: mbcx.used_mut_upvars,
484 };
485
486 let body_with_facts = if consumer_options.is_some() {
487 Some(Box::new(BodyWithBorrowckFacts {
488 body: body_owned,
489 promoted,
490 borrow_set,
491 region_inference_context: regioncx,
492 location_table: polonius_input.as_ref().map(|_| location_table),
493 input_facts: polonius_input,
494 output_facts: polonius_output,
495 }))
496 } else {
497 None
498 };
499
500 debug!("do_mir_borrowck: result = {:#?}", result);
501
502 (result, body_with_facts)
503}
504
505fn get_flow_results<'a, 'tcx>(
506 tcx: TyCtxt<'tcx>,
507 body: &'a Body<'tcx>,
508 move_data: &'a MoveData<'tcx>,
509 borrow_set: &'a BorrowSet<'tcx>,
510 regioncx: &RegionInferenceContext<'tcx>,
511) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
512 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
515 tcx,
516 body,
517 Some("borrowck"),
518 );
519 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
520 tcx,
521 body,
522 Some("borrowck"),
523 );
524 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
525 tcx,
526 body,
527 Some("borrowck"),
528 );
529
530 let analysis = Borrowck {
531 borrows: borrows.analysis,
532 uninits: uninits.analysis,
533 ever_inits: ever_inits.analysis,
534 };
535
536 assert_eq!(borrows.results.len(), uninits.results.len());
537 assert_eq!(borrows.results.len(), ever_inits.results.len());
538 let results: Results<_> =
539 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
540 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
541 .collect();
542
543 (analysis, results)
544}
545
546pub(crate) struct BorrowckInferCtxt<'tcx> {
547 pub(crate) infcx: InferCtxt<'tcx>,
548 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
549 pub(crate) param_env: ParamEnv<'tcx>,
550}
551
552impl<'tcx> BorrowckInferCtxt<'tcx> {
553 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
554 let typing_mode = if tcx.use_typing_mode_borrowck() {
555 TypingMode::borrowck(tcx, def_id)
556 } else {
557 TypingMode::analysis_in_body(tcx, def_id)
558 };
559 let infcx = tcx.infer_ctxt().build(typing_mode);
560 let param_env = tcx.param_env(def_id);
561 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
562 }
563
564 pub(crate) fn next_region_var<F>(
565 &self,
566 origin: RegionVariableOrigin,
567 get_ctxt_fn: F,
568 ) -> ty::Region<'tcx>
569 where
570 F: Fn() -> RegionCtxt,
571 {
572 let next_region = self.infcx.next_region_var(origin);
573 let vid = next_region.as_var();
574
575 if cfg!(debug_assertions) {
576 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
577 let ctxt = get_ctxt_fn();
578 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
579 assert_eq!(var_to_origin.insert(vid, ctxt), None);
580 }
581
582 next_region
583 }
584
585 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
586 pub(crate) fn next_nll_region_var<F>(
587 &self,
588 origin: NllRegionVariableOrigin,
589 get_ctxt_fn: F,
590 ) -> ty::Region<'tcx>
591 where
592 F: Fn() -> RegionCtxt,
593 {
594 let next_region = self.infcx.next_nll_region_var(origin);
595 let vid = next_region.as_var();
596
597 if cfg!(debug_assertions) {
598 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
599 let ctxt = get_ctxt_fn();
600 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
601 assert_eq!(var_to_origin.insert(vid, ctxt), None);
602 }
603
604 next_region
605 }
606}
607
608impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
609 type Target = InferCtxt<'tcx>;
610
611 fn deref(&self) -> &Self::Target {
612 &self.infcx
613 }
614}
615
616struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
617 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
618 infcx: &'infcx BorrowckInferCtxt<'tcx>,
619 body: &'a Body<'tcx>,
620 move_data: &'a MoveData<'tcx>,
621
622 location_table: &'a PoloniusLocationTable,
625
626 movable_coroutine: bool,
627 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
633 reservation_error_reported: FxIndexSet<Place<'tcx>>,
641 fn_self_span_reported: FxIndexSet<Span>,
645 uninitialized_error_reported: FxIndexSet<Local>,
648 used_mut: FxIndexSet<Local>,
651 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
654 regioncx: &'a RegionInferenceContext<'tcx>,
657
658 borrow_set: &'a BorrowSet<'tcx>,
660
661 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
663
664 local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
666
667 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
670
671 next_region_name: RefCell<usize>,
673
674 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
675 move_errors: Vec<MoveError<'tcx>>,
676
677 polonius_output: Option<&'a PoloniusOutput>,
679 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
681}
682
683impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
689 fn visit_after_early_statement_effect(
690 &mut self,
691 _analysis: &mut Borrowck<'a, 'tcx>,
692 state: &BorrowckDomain,
693 stmt: &Statement<'tcx>,
694 location: Location,
695 ) {
696 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
697 let span = stmt.source_info.span;
698
699 self.check_activations(location, span, state);
700
701 match &stmt.kind {
702 StatementKind::Assign(box (lhs, rhs)) => {
703 self.consume_rvalue(location, (rhs, span), state);
704
705 self.mutate_place(location, (*lhs, span), Shallow(None), state);
706 }
707 StatementKind::FakeRead(box (_, place)) => {
708 self.check_if_path_or_subpath_is_moved(
719 location,
720 InitializationRequiringAction::Use,
721 (place.as_ref(), span),
722 state,
723 );
724 }
725 StatementKind::Intrinsic(box kind) => match kind {
726 NonDivergingIntrinsic::Assume(op) => {
727 self.consume_operand(location, (op, span), state);
728 }
729 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
730 span,
731 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
732 )
733 }
734 StatementKind::AscribeUserType(..)
736 | StatementKind::PlaceMention(..)
738 | StatementKind::Coverage(..)
740 | StatementKind::ConstEvalCounter
742 | StatementKind::StorageLive(..) => {}
743 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
745 self.check_backward_incompatible_drop(location, **place, state);
746 }
747 StatementKind::StorageDead(local) => {
748 self.access_place(
749 location,
750 (Place::from(*local), span),
751 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
752 LocalMutationIsAllowed::Yes,
753 state,
754 );
755 }
756 StatementKind::Nop
757 | StatementKind::Retag { .. }
758 | StatementKind::Deinit(..)
759 | StatementKind::SetDiscriminant { .. } => {
760 bug!("Statement not allowed in this MIR phase")
761 }
762 }
763 }
764
765 fn visit_after_early_terminator_effect(
766 &mut self,
767 _analysis: &mut Borrowck<'a, 'tcx>,
768 state: &BorrowckDomain,
769 term: &Terminator<'tcx>,
770 loc: Location,
771 ) {
772 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
773 let span = term.source_info.span;
774
775 self.check_activations(loc, span, state);
776
777 match &term.kind {
778 TerminatorKind::SwitchInt { discr, targets: _ } => {
779 self.consume_operand(loc, (discr, span), state);
780 }
781 TerminatorKind::Drop {
782 place,
783 target: _,
784 unwind: _,
785 replace,
786 drop: _,
787 async_fut: _,
788 } => {
789 debug!(
790 "visit_terminator_drop \
791 loc: {:?} term: {:?} place: {:?} span: {:?}",
792 loc, term, place, span
793 );
794
795 let write_kind =
796 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
797 self.access_place(
798 loc,
799 (*place, span),
800 (AccessDepth::Drop, Write(write_kind)),
801 LocalMutationIsAllowed::Yes,
802 state,
803 );
804 }
805 TerminatorKind::Call {
806 func,
807 args,
808 destination,
809 target: _,
810 unwind: _,
811 call_source: _,
812 fn_span: _,
813 } => {
814 self.consume_operand(loc, (func, span), state);
815 for arg in args {
816 self.consume_operand(loc, (&arg.node, arg.span), state);
817 }
818 self.mutate_place(loc, (*destination, span), Deep, state);
819 }
820 TerminatorKind::TailCall { func, args, fn_span: _ } => {
821 self.consume_operand(loc, (func, span), state);
822 for arg in args {
823 self.consume_operand(loc, (&arg.node, arg.span), state);
824 }
825 }
826 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
827 self.consume_operand(loc, (cond, span), state);
828 if let AssertKind::BoundsCheck { len, index } = &**msg {
829 self.consume_operand(loc, (len, span), state);
830 self.consume_operand(loc, (index, span), state);
831 }
832 }
833
834 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
835 self.consume_operand(loc, (value, span), state);
836 self.mutate_place(loc, (*resume_arg, span), Deep, state);
837 }
838
839 TerminatorKind::InlineAsm {
840 asm_macro: _,
841 template: _,
842 operands,
843 options: _,
844 line_spans: _,
845 targets: _,
846 unwind: _,
847 } => {
848 for op in operands {
849 match op {
850 InlineAsmOperand::In { reg: _, value } => {
851 self.consume_operand(loc, (value, span), state);
852 }
853 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
854 if let Some(place) = place {
855 self.mutate_place(loc, (*place, span), Shallow(None), state);
856 }
857 }
858 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
859 self.consume_operand(loc, (in_value, span), state);
860 if let &Some(out_place) = out_place {
861 self.mutate_place(loc, (out_place, span), Shallow(None), state);
862 }
863 }
864 InlineAsmOperand::Const { value: _ }
865 | InlineAsmOperand::SymFn { value: _ }
866 | InlineAsmOperand::SymStatic { def_id: _ }
867 | InlineAsmOperand::Label { target_index: _ } => {}
868 }
869 }
870 }
871
872 TerminatorKind::Goto { target: _ }
873 | TerminatorKind::UnwindTerminate(_)
874 | TerminatorKind::Unreachable
875 | TerminatorKind::UnwindResume
876 | TerminatorKind::Return
877 | TerminatorKind::CoroutineDrop
878 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
879 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
880 }
882 }
883 }
884
885 fn visit_after_primary_terminator_effect(
886 &mut self,
887 _analysis: &mut Borrowck<'a, 'tcx>,
888 state: &BorrowckDomain,
889 term: &Terminator<'tcx>,
890 loc: Location,
891 ) {
892 let span = term.source_info.span;
893
894 match term.kind {
895 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
896 if self.movable_coroutine {
897 for i in state.borrows.iter() {
899 let borrow = &self.borrow_set[i];
900 self.check_for_local_borrow(borrow, span);
901 }
902 }
903 }
904
905 TerminatorKind::UnwindResume
906 | TerminatorKind::Return
907 | TerminatorKind::TailCall { .. }
908 | TerminatorKind::CoroutineDrop => {
909 match self.borrow_set.locals_state_at_exit() {
910 LocalsStateAtExit::AllAreInvalidated => {
911 for i in state.borrows.iter() {
916 let borrow = &self.borrow_set[i];
917 self.check_for_invalidation_at_exit(loc, borrow, span);
918 }
919 }
920 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
923 }
924 }
925
926 TerminatorKind::UnwindTerminate(_)
927 | TerminatorKind::Assert { .. }
928 | TerminatorKind::Call { .. }
929 | TerminatorKind::Drop { .. }
930 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
931 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
932 | TerminatorKind::Goto { .. }
933 | TerminatorKind::SwitchInt { .. }
934 | TerminatorKind::Unreachable
935 | TerminatorKind::InlineAsm { .. } => {}
936 }
937 }
938}
939
940use self::AccessDepth::{Deep, Shallow};
941use self::ReadOrWrite::{Activation, Read, Reservation, Write};
942
943#[derive(Copy, Clone, PartialEq, Eq, Debug)]
944enum ArtificialField {
945 ArrayLength,
946 FakeBorrow,
947}
948
949#[derive(Copy, Clone, PartialEq, Eq, Debug)]
950enum AccessDepth {
951 Shallow(Option<ArtificialField>),
957
958 Deep,
962
963 Drop,
966}
967
968#[derive(Copy, Clone, PartialEq, Eq, Debug)]
971enum ReadOrWrite {
972 Read(ReadKind),
975
976 Write(WriteKind),
980
981 Reservation(WriteKind),
985 Activation(WriteKind, BorrowIndex),
986}
987
988#[derive(Copy, Clone, PartialEq, Eq, Debug)]
991enum ReadKind {
992 Borrow(BorrowKind),
993 Copy,
994}
995
996#[derive(Copy, Clone, PartialEq, Eq, Debug)]
999enum WriteKind {
1000 StorageDeadOrDrop,
1001 Replace,
1002 MutableBorrow(BorrowKind),
1003 Mutate,
1004 Move,
1005}
1006
1007#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1015enum LocalMutationIsAllowed {
1016 Yes,
1017 ExceptUpvars,
1020 No,
1021}
1022
1023#[derive(Copy, Clone, Debug)]
1024enum InitializationRequiringAction {
1025 Borrow,
1026 MatchOn,
1027 Use,
1028 Assignment,
1029 PartialAssignment,
1030}
1031
1032#[derive(Debug)]
1033struct RootPlace<'tcx> {
1034 place_local: Local,
1035 place_projection: &'tcx [PlaceElem<'tcx>],
1036 is_local_mutation_allowed: LocalMutationIsAllowed,
1037}
1038
1039impl InitializationRequiringAction {
1040 fn as_noun(self) -> &'static str {
1041 match self {
1042 InitializationRequiringAction::Borrow => "borrow",
1043 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1045 InitializationRequiringAction::Assignment => "assign",
1046 InitializationRequiringAction::PartialAssignment => "assign to part",
1047 }
1048 }
1049
1050 fn as_verb_in_past_tense(self) -> &'static str {
1051 match self {
1052 InitializationRequiringAction::Borrow => "borrowed",
1053 InitializationRequiringAction::MatchOn => "matched on",
1054 InitializationRequiringAction::Use => "used",
1055 InitializationRequiringAction::Assignment => "assigned",
1056 InitializationRequiringAction::PartialAssignment => "partially assigned",
1057 }
1058 }
1059
1060 fn as_general_verb_in_past_tense(self) -> &'static str {
1061 match self {
1062 InitializationRequiringAction::Borrow
1063 | InitializationRequiringAction::MatchOn
1064 | InitializationRequiringAction::Use => "used",
1065 InitializationRequiringAction::Assignment => "assigned",
1066 InitializationRequiringAction::PartialAssignment => "partially assigned",
1067 }
1068 }
1069}
1070
1071impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1072 fn body(&self) -> &'a Body<'tcx> {
1073 self.body
1074 }
1075
1076 fn access_place(
1083 &mut self,
1084 location: Location,
1085 place_span: (Place<'tcx>, Span),
1086 kind: (AccessDepth, ReadOrWrite),
1087 is_local_mutation_allowed: LocalMutationIsAllowed,
1088 state: &BorrowckDomain,
1089 ) {
1090 let (sd, rw) = kind;
1091
1092 if let Activation(_, borrow_index) = rw {
1093 if self.reservation_error_reported.contains(&place_span.0) {
1094 debug!(
1095 "skipping access_place for activation of invalid reservation \
1096 place: {:?} borrow_index: {:?}",
1097 place_span.0, borrow_index
1098 );
1099 return;
1100 }
1101 }
1102
1103 if !self.access_place_error_reported.is_empty()
1106 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1107 {
1108 debug!(
1109 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1110 place_span, kind
1111 );
1112 return;
1113 }
1114
1115 let mutability_error = self.check_access_permissions(
1116 place_span,
1117 rw,
1118 is_local_mutation_allowed,
1119 state,
1120 location,
1121 );
1122 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1123
1124 if conflict_error || mutability_error {
1125 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1126 self.access_place_error_reported.insert((place_span.0, place_span.1));
1127 }
1128 }
1129
1130 fn borrows_in_scope<'s>(
1131 &self,
1132 location: Location,
1133 state: &'s BorrowckDomain,
1134 ) -> Cow<'s, MixedBitSet<BorrowIndex>> {
1135 if let Some(polonius) = &self.polonius_output {
1136 let location = self.location_table.start_index(location);
1138 let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
1139 for &idx in polonius.errors_at(location) {
1140 polonius_output.insert(idx);
1141 }
1142 Cow::Owned(polonius_output)
1143 } else {
1144 Cow::Borrowed(&state.borrows)
1145 }
1146 }
1147
1148 #[instrument(level = "debug", skip(self, state))]
1149 fn check_access_for_conflict(
1150 &mut self,
1151 location: Location,
1152 place_span: (Place<'tcx>, Span),
1153 sd: AccessDepth,
1154 rw: ReadOrWrite,
1155 state: &BorrowckDomain,
1156 ) -> bool {
1157 let mut error_reported = false;
1158
1159 let borrows_in_scope = self.borrows_in_scope(location, state);
1160
1161 each_borrow_involving_path(
1162 self,
1163 self.infcx.tcx,
1164 self.body,
1165 (sd, place_span.0),
1166 self.borrow_set,
1167 |borrow_index| borrows_in_scope.contains(borrow_index),
1168 |this, borrow_index, borrow| match (rw, borrow.kind) {
1169 (Activation(_, activating), _) if activating == borrow_index => {
1176 debug!(
1177 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1178 skipping {:?} b/c activation of same borrow_index",
1179 place_span,
1180 sd,
1181 rw,
1182 (borrow_index, borrow),
1183 );
1184 ControlFlow::Continue(())
1185 }
1186
1187 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1188 | (
1189 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1190 BorrowKind::Mut { .. },
1191 ) => ControlFlow::Continue(()),
1192
1193 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1194 ControlFlow::Continue(())
1197 }
1198
1199 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1200 ControlFlow::Continue(())
1202 }
1203
1204 (Read(kind), BorrowKind::Mut { .. }) => {
1205 if !is_active(this.dominators(), borrow, location) {
1207 assert!(borrow.kind.allows_two_phase_borrow());
1208 return ControlFlow::Continue(());
1209 }
1210
1211 error_reported = true;
1212 match kind {
1213 ReadKind::Copy => {
1214 let err = this
1215 .report_use_while_mutably_borrowed(location, place_span, borrow);
1216 this.buffer_error(err);
1217 }
1218 ReadKind::Borrow(bk) => {
1219 let err =
1220 this.report_conflicting_borrow(location, place_span, bk, borrow);
1221 this.buffer_error(err);
1222 }
1223 }
1224 ControlFlow::Break(())
1225 }
1226
1227 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1228 match rw {
1229 Reservation(..) => {
1230 debug!(
1231 "recording invalid reservation of \
1232 place: {:?}",
1233 place_span.0
1234 );
1235 this.reservation_error_reported.insert(place_span.0);
1236 }
1237 Activation(_, activating) => {
1238 debug!(
1239 "observing check_place for activation of \
1240 borrow_index: {:?}",
1241 activating
1242 );
1243 }
1244 Read(..) | Write(..) => {}
1245 }
1246
1247 error_reported = true;
1248 match kind {
1249 WriteKind::MutableBorrow(bk) => {
1250 let err =
1251 this.report_conflicting_borrow(location, place_span, bk, borrow);
1252 this.buffer_error(err);
1253 }
1254 WriteKind::StorageDeadOrDrop => this
1255 .report_borrowed_value_does_not_live_long_enough(
1256 location,
1257 borrow,
1258 place_span,
1259 Some(WriteKind::StorageDeadOrDrop),
1260 ),
1261 WriteKind::Mutate => {
1262 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1263 }
1264 WriteKind::Move => {
1265 this.report_move_out_while_borrowed(location, place_span, borrow)
1266 }
1267 WriteKind::Replace => {
1268 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1269 }
1270 }
1271 ControlFlow::Break(())
1272 }
1273 },
1274 );
1275
1276 error_reported
1277 }
1278
1279 #[instrument(level = "debug", skip(self, state))]
1282 fn check_backward_incompatible_drop(
1283 &mut self,
1284 location: Location,
1285 place: Place<'tcx>,
1286 state: &BorrowckDomain,
1287 ) {
1288 let tcx = self.infcx.tcx;
1289 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1293 AccessDepth::Drop
1294 } else {
1295 AccessDepth::Shallow(None)
1296 };
1297
1298 let borrows_in_scope = self.borrows_in_scope(location, state);
1299
1300 each_borrow_involving_path(
1303 self,
1304 self.infcx.tcx,
1305 self.body,
1306 (sd, place),
1307 self.borrow_set,
1308 |borrow_index| borrows_in_scope.contains(borrow_index),
1309 |this, _borrow_index, borrow| {
1310 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1311 return ControlFlow::Continue(());
1312 }
1313 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1314 let explain = this.explain_why_borrow_contains_point(
1315 location,
1316 borrow,
1317 Some((WriteKind::StorageDeadOrDrop, place)),
1318 );
1319 this.infcx.tcx.node_span_lint(
1320 TAIL_EXPR_DROP_ORDER,
1321 CRATE_HIR_ID,
1322 borrowed,
1323 |diag| {
1324 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1325 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1326 },
1327 );
1328 ControlFlow::Break(())
1330 },
1331 );
1332 }
1333
1334 fn mutate_place(
1335 &mut self,
1336 location: Location,
1337 place_span: (Place<'tcx>, Span),
1338 kind: AccessDepth,
1339 state: &BorrowckDomain,
1340 ) {
1341 self.check_if_assigned_path_is_moved(location, place_span, state);
1343
1344 self.access_place(
1345 location,
1346 place_span,
1347 (kind, Write(WriteKind::Mutate)),
1348 LocalMutationIsAllowed::No,
1349 state,
1350 );
1351 }
1352
1353 fn consume_rvalue(
1354 &mut self,
1355 location: Location,
1356 (rvalue, span): (&Rvalue<'tcx>, Span),
1357 state: &BorrowckDomain,
1358 ) {
1359 match rvalue {
1360 &Rvalue::Ref(_ , bk, place) => {
1361 let access_kind = match bk {
1362 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1363 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1364 }
1365 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1366 (Deep, Read(ReadKind::Borrow(bk)))
1367 }
1368 BorrowKind::Mut { .. } => {
1369 let wk = WriteKind::MutableBorrow(bk);
1370 if bk.allows_two_phase_borrow() {
1371 (Deep, Reservation(wk))
1372 } else {
1373 (Deep, Write(wk))
1374 }
1375 }
1376 };
1377
1378 self.access_place(
1379 location,
1380 (place, span),
1381 access_kind,
1382 LocalMutationIsAllowed::No,
1383 state,
1384 );
1385
1386 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1387 InitializationRequiringAction::MatchOn
1388 } else {
1389 InitializationRequiringAction::Borrow
1390 };
1391
1392 self.check_if_path_or_subpath_is_moved(
1393 location,
1394 action,
1395 (place.as_ref(), span),
1396 state,
1397 );
1398 }
1399
1400 &Rvalue::RawPtr(kind, place) => {
1401 let access_kind = match kind {
1402 RawPtrKind::Mut => (
1403 Deep,
1404 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1405 kind: MutBorrowKind::Default,
1406 })),
1407 ),
1408 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1409 RawPtrKind::FakeForPtrMetadata => {
1410 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1411 }
1412 };
1413
1414 self.access_place(
1415 location,
1416 (place, span),
1417 access_kind,
1418 LocalMutationIsAllowed::No,
1419 state,
1420 );
1421
1422 self.check_if_path_or_subpath_is_moved(
1423 location,
1424 InitializationRequiringAction::Borrow,
1425 (place.as_ref(), span),
1426 state,
1427 );
1428 }
1429
1430 Rvalue::ThreadLocalRef(_) => {}
1431
1432 Rvalue::Use(operand)
1433 | Rvalue::Repeat(operand, _)
1434 | Rvalue::UnaryOp(_ , operand)
1435 | Rvalue::Cast(_ , operand, _ )
1436 | Rvalue::ShallowInitBox(operand, _ ) => {
1437 self.consume_operand(location, (operand, span), state)
1438 }
1439
1440 &Rvalue::CopyForDeref(place) => {
1441 self.access_place(
1442 location,
1443 (place, span),
1444 (Deep, Read(ReadKind::Copy)),
1445 LocalMutationIsAllowed::No,
1446 state,
1447 );
1448
1449 self.check_if_path_or_subpath_is_moved(
1451 location,
1452 InitializationRequiringAction::Use,
1453 (place.as_ref(), span),
1454 state,
1455 );
1456 }
1457
1458 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1459 let af = match *rvalue {
1460 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1461 Rvalue::Discriminant(..) => None,
1462 _ => unreachable!(),
1463 };
1464 self.access_place(
1465 location,
1466 (place, span),
1467 (Shallow(af), Read(ReadKind::Copy)),
1468 LocalMutationIsAllowed::No,
1469 state,
1470 );
1471 self.check_if_path_or_subpath_is_moved(
1472 location,
1473 InitializationRequiringAction::Use,
1474 (place.as_ref(), span),
1475 state,
1476 );
1477 }
1478
1479 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1480 self.consume_operand(location, (operand1, span), state);
1481 self.consume_operand(location, (operand2, span), state);
1482 }
1483
1484 Rvalue::NullaryOp(_op, _ty) => {
1485 }
1487
1488 Rvalue::Aggregate(aggregate_kind, operands) => {
1489 match **aggregate_kind {
1493 AggregateKind::Closure(def_id, _)
1494 | AggregateKind::CoroutineClosure(def_id, _)
1495 | AggregateKind::Coroutine(def_id, _) => {
1496 let def_id = def_id.expect_local();
1497 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1498 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1499 for field in used_mut_upvars.clone() {
1503 self.propagate_closure_used_mut_upvar(&operands[field]);
1504 }
1505 }
1506 AggregateKind::Adt(..)
1507 | AggregateKind::Array(..)
1508 | AggregateKind::Tuple { .. }
1509 | AggregateKind::RawPtr(..) => (),
1510 }
1511
1512 for operand in operands {
1513 self.consume_operand(location, (operand, span), state);
1514 }
1515 }
1516
1517 Rvalue::WrapUnsafeBinder(op, _) => {
1518 self.consume_operand(location, (op, span), state);
1519 }
1520 }
1521 }
1522
1523 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1524 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1525 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1533 this.used_mut_upvars.push(field);
1534 return;
1535 }
1536
1537 for (place_ref, proj) in place.iter_projections().rev() {
1538 if proj == ProjectionElem::Deref {
1540 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1541 ty::Ref(_, _, hir::Mutability::Mut) => return,
1543
1544 _ => {}
1545 }
1546 }
1547
1548 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1550 this.used_mut_upvars.push(field);
1551 return;
1552 }
1553 }
1554
1555 this.used_mut.insert(place.local);
1557 };
1558
1559 match *operand {
1563 Operand::Move(place) | Operand::Copy(place) => {
1564 match place.as_local() {
1565 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1566 if self.body.local_decls[local].ty.is_mutable_ptr() {
1567 return;
1569 }
1570 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1586 bug!("temporary should be tracked");
1587 };
1588 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1589 &self.move_data.inits[init_index]
1590 } else {
1591 bug!("temporary should be initialized exactly once")
1592 };
1593
1594 let InitLocation::Statement(loc) = init.location else {
1595 bug!("temporary initialized in arguments")
1596 };
1597
1598 let body = self.body;
1599 let bbd = &body[loc.block];
1600 let stmt = &bbd.statements[loc.statement_index];
1601 debug!("temporary assigned in: stmt={:?}", stmt);
1602
1603 match stmt.kind {
1604 StatementKind::Assign(box (
1605 _,
1606 Rvalue::Ref(_, _, source)
1607 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1608 )) => {
1609 propagate_closure_used_mut_place(self, source);
1610 }
1611 _ => {
1612 bug!(
1613 "closures should only capture user variables \
1614 or references to user variables"
1615 );
1616 }
1617 }
1618 }
1619 _ => propagate_closure_used_mut_place(self, place),
1620 }
1621 }
1622 Operand::Constant(..) => {}
1623 }
1624 }
1625
1626 fn consume_operand(
1627 &mut self,
1628 location: Location,
1629 (operand, span): (&Operand<'tcx>, Span),
1630 state: &BorrowckDomain,
1631 ) {
1632 match *operand {
1633 Operand::Copy(place) => {
1634 self.access_place(
1637 location,
1638 (place, span),
1639 (Deep, Read(ReadKind::Copy)),
1640 LocalMutationIsAllowed::No,
1641 state,
1642 );
1643
1644 self.check_if_path_or_subpath_is_moved(
1646 location,
1647 InitializationRequiringAction::Use,
1648 (place.as_ref(), span),
1649 state,
1650 );
1651 }
1652 Operand::Move(place) => {
1653 self.check_movable_place(location, place);
1655
1656 self.access_place(
1658 location,
1659 (place, span),
1660 (Deep, Write(WriteKind::Move)),
1661 LocalMutationIsAllowed::Yes,
1662 state,
1663 );
1664
1665 self.check_if_path_or_subpath_is_moved(
1667 location,
1668 InitializationRequiringAction::Use,
1669 (place.as_ref(), span),
1670 state,
1671 );
1672 }
1673 Operand::Constant(_) => {}
1674 }
1675 }
1676
1677 #[instrument(level = "debug", skip(self))]
1680 fn check_for_invalidation_at_exit(
1681 &mut self,
1682 location: Location,
1683 borrow: &BorrowData<'tcx>,
1684 span: Span,
1685 ) {
1686 let place = borrow.borrowed_place;
1687 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1688
1689 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1695 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1699 true
1700 } else {
1701 false
1702 };
1703
1704 let sd = if might_be_alive { Deep } else { Shallow(None) };
1705
1706 if places_conflict::borrow_conflicts_with_place(
1707 self.infcx.tcx,
1708 self.body,
1709 place,
1710 borrow.kind,
1711 root_place,
1712 sd,
1713 places_conflict::PlaceConflictBias::Overlap,
1714 ) {
1715 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1716 let span = self.infcx.tcx.sess.source_map().end_point(span);
1719 self.report_borrowed_value_does_not_live_long_enough(
1720 location,
1721 borrow,
1722 (place, span),
1723 None,
1724 )
1725 }
1726 }
1727
1728 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1731 debug!("check_for_local_borrow({:?})", borrow);
1732
1733 if borrow_of_local_data(borrow.borrowed_place) {
1734 let err = self.cannot_borrow_across_coroutine_yield(
1735 self.retrieve_borrow_spans(borrow).var_or_use(),
1736 yield_span,
1737 );
1738
1739 self.buffer_error(err);
1740 }
1741 }
1742
1743 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1744 for &borrow_index in self.borrow_set.activations_at_location(location) {
1748 let borrow = &self.borrow_set[borrow_index];
1749
1750 assert!(match borrow.kind {
1752 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1753 BorrowKind::Mut { .. } => true,
1754 });
1755
1756 self.access_place(
1757 location,
1758 (borrow.borrowed_place, span),
1759 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1760 LocalMutationIsAllowed::No,
1761 state,
1762 );
1763 }
1767 }
1768
1769 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1770 use IllegalMoveOriginKind::*;
1771
1772 let body = self.body;
1773 let tcx = self.infcx.tcx;
1774 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1775 for (place_ref, elem) in place.iter_projections() {
1776 match elem {
1777 ProjectionElem::Deref => match place_ty.ty.kind() {
1778 ty::Ref(..) | ty::RawPtr(..) => {
1779 self.move_errors.push(MoveError::new(
1780 place,
1781 location,
1782 BorrowedContent {
1783 target_place: place_ref.project_deeper(&[elem], tcx),
1784 },
1785 ));
1786 return;
1787 }
1788 ty::Adt(adt, _) => {
1789 if !adt.is_box() {
1790 bug!("Adt should be a box type when Place is deref");
1791 }
1792 }
1793 ty::Bool
1794 | ty::Char
1795 | ty::Int(_)
1796 | ty::Uint(_)
1797 | ty::Float(_)
1798 | ty::Foreign(_)
1799 | ty::Str
1800 | ty::Array(_, _)
1801 | ty::Pat(_, _)
1802 | ty::Slice(_)
1803 | ty::FnDef(_, _)
1804 | ty::FnPtr(..)
1805 | ty::Dynamic(_, _, _)
1806 | ty::Closure(_, _)
1807 | ty::CoroutineClosure(_, _)
1808 | ty::Coroutine(_, _)
1809 | ty::CoroutineWitness(..)
1810 | ty::Never
1811 | ty::Tuple(_)
1812 | ty::UnsafeBinder(_)
1813 | ty::Alias(_, _)
1814 | ty::Param(_)
1815 | ty::Bound(_, _)
1816 | ty::Infer(_)
1817 | ty::Error(_)
1818 | ty::Placeholder(_) => {
1819 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1820 }
1821 },
1822 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1823 ty::Adt(adt, _) => {
1824 if adt.has_dtor(tcx) {
1825 self.move_errors.push(MoveError::new(
1826 place,
1827 location,
1828 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1829 ));
1830 return;
1831 }
1832 }
1833 ty::Closure(..)
1834 | ty::CoroutineClosure(..)
1835 | ty::Coroutine(_, _)
1836 | ty::Tuple(_) => (),
1837 ty::Bool
1838 | ty::Char
1839 | ty::Int(_)
1840 | ty::Uint(_)
1841 | ty::Float(_)
1842 | ty::Foreign(_)
1843 | ty::Str
1844 | ty::Array(_, _)
1845 | ty::Pat(_, _)
1846 | ty::Slice(_)
1847 | ty::RawPtr(_, _)
1848 | ty::Ref(_, _, _)
1849 | ty::FnDef(_, _)
1850 | ty::FnPtr(..)
1851 | ty::Dynamic(_, _, _)
1852 | ty::CoroutineWitness(..)
1853 | ty::Never
1854 | ty::UnsafeBinder(_)
1855 | ty::Alias(_, _)
1856 | ty::Param(_)
1857 | ty::Bound(_, _)
1858 | ty::Infer(_)
1859 | ty::Error(_)
1860 | ty::Placeholder(_) => bug!(
1861 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1862 ),
1863 },
1864 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1865 match place_ty.ty.kind() {
1866 ty::Slice(_) => {
1867 self.move_errors.push(MoveError::new(
1868 place,
1869 location,
1870 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1871 ));
1872 return;
1873 }
1874 ty::Array(_, _) => (),
1875 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1876 }
1877 }
1878 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1879 ty::Array(..) | ty::Slice(..) => {
1880 self.move_errors.push(MoveError::new(
1881 place,
1882 location,
1883 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1884 ));
1885 return;
1886 }
1887 _ => bug!("Unexpected type {place_ty:#?}"),
1888 },
1889 ProjectionElem::OpaqueCast(_)
1894 | ProjectionElem::Subtype(_)
1895 | ProjectionElem::Downcast(_, _)
1896 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1897 }
1898
1899 place_ty = place_ty.projection_ty(tcx, elem);
1900 }
1901 }
1902
1903 fn check_if_full_path_is_moved(
1904 &mut self,
1905 location: Location,
1906 desired_action: InitializationRequiringAction,
1907 place_span: (PlaceRef<'tcx>, Span),
1908 state: &BorrowckDomain,
1909 ) {
1910 let maybe_uninits = &state.uninits;
1911
1912 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1948 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1949 if maybe_uninits.contains(mpi) {
1950 self.report_use_of_moved_or_uninitialized(
1951 location,
1952 desired_action,
1953 (prefix, place_span.0, place_span.1),
1954 mpi,
1955 );
1956 } }
1963
1964 fn check_if_subslice_element_is_moved(
1970 &mut self,
1971 location: Location,
1972 desired_action: InitializationRequiringAction,
1973 place_span: (PlaceRef<'tcx>, Span),
1974 maybe_uninits: &MixedBitSet<MovePathIndex>,
1975 from: u64,
1976 to: u64,
1977 ) {
1978 if let Some(mpi) = self.move_path_for_place(place_span.0) {
1979 let move_paths = &self.move_data.move_paths;
1980
1981 let root_path = &move_paths[mpi];
1982 for (child_mpi, child_move_path) in root_path.children(move_paths) {
1983 let last_proj = child_move_path.place.projection.last().unwrap();
1984 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
1985 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
1986
1987 if (from..to).contains(offset) {
1988 let uninit_child =
1989 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
1990 maybe_uninits.contains(mpi)
1991 });
1992
1993 if let Some(uninit_child) = uninit_child {
1994 self.report_use_of_moved_or_uninitialized(
1995 location,
1996 desired_action,
1997 (place_span.0, place_span.0, place_span.1),
1998 uninit_child,
1999 );
2000 return; }
2002 }
2003 }
2004 }
2005 }
2006 }
2007
2008 fn check_if_path_or_subpath_is_moved(
2009 &mut self,
2010 location: Location,
2011 desired_action: InitializationRequiringAction,
2012 place_span: (PlaceRef<'tcx>, Span),
2013 state: &BorrowckDomain,
2014 ) {
2015 let maybe_uninits = &state.uninits;
2016
2017 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2033
2034 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2035 place_span.0.last_projection()
2036 {
2037 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2038 if let ty::Array(..) = place_ty.ty.kind() {
2039 self.check_if_subslice_element_is_moved(
2040 location,
2041 desired_action,
2042 (place_base, place_span.1),
2043 maybe_uninits,
2044 from,
2045 to,
2046 );
2047 return;
2048 }
2049 }
2050
2051 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2061 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2062 let uninit_mpi = self
2063 .move_data
2064 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2065
2066 if let Some(uninit_mpi) = uninit_mpi {
2067 self.report_use_of_moved_or_uninitialized(
2068 location,
2069 desired_action,
2070 (place_span.0, place_span.0, place_span.1),
2071 uninit_mpi,
2072 );
2073 return; }
2075 }
2076 }
2077
2078 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2089 match self.move_data.rev_lookup.find(place) {
2090 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2091 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2092 }
2093 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2094 }
2095 }
2096
2097 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2098 match self.move_data.rev_lookup.find(place) {
2103 LookupResult::Parent(_) => None,
2104 LookupResult::Exact(mpi) => Some(mpi),
2105 }
2106 }
2107
2108 fn check_if_assigned_path_is_moved(
2109 &mut self,
2110 location: Location,
2111 (place, span): (Place<'tcx>, Span),
2112 state: &BorrowckDomain,
2113 ) {
2114 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2115
2116 for (place_base, elem) in place.iter_projections().rev() {
2118 match elem {
2119 ProjectionElem::Index(_) |
2120 ProjectionElem::Subtype(_) |
2121 ProjectionElem::OpaqueCast(_) |
2122 ProjectionElem::ConstantIndex { .. } |
2123 ProjectionElem::Downcast(_, _) =>
2125 { }
2129
2130 ProjectionElem::UnwrapUnsafeBinder(_) => {
2131 check_parent_of_field(self, location, place_base, span, state);
2132 }
2133
2134 ProjectionElem::Deref => {
2136 self.check_if_full_path_is_moved(
2137 location, InitializationRequiringAction::Use,
2138 (place_base, span), state);
2139 break;
2142 }
2143
2144 ProjectionElem::Subslice { .. } => {
2145 panic!("we don't allow assignments to subslices, location: {location:?}");
2146 }
2147
2148 ProjectionElem::Field(..) => {
2149 let tcx = self.infcx.tcx;
2153 let base_ty = place_base.ty(self.body(), tcx).ty;
2154 match base_ty.kind() {
2155 ty::Adt(def, _) if def.has_dtor(tcx) => {
2156 self.check_if_path_or_subpath_is_moved(
2157 location, InitializationRequiringAction::Assignment,
2158 (place_base, span), state);
2159
2160 break;
2163 }
2164
2165 ty::Adt(..) | ty::Tuple(..) => {
2168 check_parent_of_field(self, location, place_base, span, state);
2169 }
2170
2171 _ => {}
2172 }
2173 }
2174 }
2175 }
2176
2177 fn check_parent_of_field<'a, 'tcx>(
2178 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2179 location: Location,
2180 base: PlaceRef<'tcx>,
2181 span: Span,
2182 state: &BorrowckDomain,
2183 ) {
2184 let maybe_uninits = &state.uninits;
2216
2217 let mut shortest_uninit_seen = None;
2220 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2221 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2222
2223 if maybe_uninits.contains(mpi) {
2224 debug!(
2225 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2226 shortest_uninit_seen,
2227 Some((prefix, mpi))
2228 );
2229 shortest_uninit_seen = Some((prefix, mpi));
2230 } else {
2231 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2232 }
2233 }
2234
2235 if let Some((prefix, mpi)) = shortest_uninit_seen {
2236 let tcx = this.infcx.tcx;
2242 if base.ty(this.body(), tcx).ty.is_union()
2243 && this.move_data.path_map[mpi].iter().any(|moi| {
2244 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2245 })
2246 {
2247 return;
2248 }
2249
2250 this.report_use_of_moved_or_uninitialized(
2251 location,
2252 InitializationRequiringAction::PartialAssignment,
2253 (prefix, base, span),
2254 mpi,
2255 );
2256
2257 this.used_mut.insert(base.local);
2261 }
2262 }
2263 }
2264
2265 fn check_access_permissions(
2269 &mut self,
2270 (place, span): (Place<'tcx>, Span),
2271 kind: ReadOrWrite,
2272 is_local_mutation_allowed: LocalMutationIsAllowed,
2273 state: &BorrowckDomain,
2274 location: Location,
2275 ) -> bool {
2276 debug!(
2277 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2278 place, kind, is_local_mutation_allowed
2279 );
2280
2281 let error_access;
2282 let the_place_err;
2283
2284 match kind {
2285 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2286 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2287 let is_local_mutation_allowed = match mut_borrow_kind {
2288 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2292 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2293 is_local_mutation_allowed
2294 }
2295 };
2296 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2297 Ok(root_place) => {
2298 self.add_used_mut(root_place, state);
2299 return false;
2300 }
2301 Err(place_err) => {
2302 error_access = AccessKind::MutableBorrow;
2303 the_place_err = place_err;
2304 }
2305 }
2306 }
2307 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2308 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2309 Ok(root_place) => {
2310 self.add_used_mut(root_place, state);
2311 return false;
2312 }
2313 Err(place_err) => {
2314 error_access = AccessKind::Mutate;
2315 the_place_err = place_err;
2316 }
2317 }
2318 }
2319
2320 Reservation(
2321 WriteKind::Move
2322 | WriteKind::Replace
2323 | WriteKind::StorageDeadOrDrop
2324 | WriteKind::MutableBorrow(BorrowKind::Shared)
2325 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2326 )
2327 | Write(
2328 WriteKind::Move
2329 | WriteKind::Replace
2330 | WriteKind::StorageDeadOrDrop
2331 | WriteKind::MutableBorrow(BorrowKind::Shared)
2332 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2333 ) => {
2334 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2335 && !self.has_buffered_diags()
2336 {
2337 self.dcx().span_delayed_bug(
2343 span,
2344 format!(
2345 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2346 ),
2347 );
2348 }
2349 return false;
2350 }
2351 Activation(..) => {
2352 return false;
2354 }
2355 Read(
2356 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2357 | ReadKind::Copy,
2358 ) => {
2359 return false;
2361 }
2362 }
2363
2364 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2369
2370 if let Some(init_index) = previously_initialized {
2372 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2373 let init = &self.move_data.inits[init_index];
2376 let assigned_span = init.span(self.body);
2377 self.report_illegal_reassignment((place, span), assigned_span, place);
2378 } else {
2379 self.report_mutability_error(place, span, the_place_err, error_access, location)
2380 }
2381 true
2382 } else {
2383 false
2384 }
2385 }
2386
2387 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2388 let mpi = self.move_data.rev_lookup.find_local(local)?;
2389 let ii = &self.move_data.init_path_map[mpi];
2390 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2391 }
2392
2393 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2395 match root_place {
2396 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2397 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2401 && self.is_local_ever_initialized(local, state).is_some()
2402 {
2403 self.used_mut.insert(local);
2404 }
2405 }
2406 RootPlace {
2407 place_local: _,
2408 place_projection: _,
2409 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2410 } => {}
2411 RootPlace {
2412 place_local,
2413 place_projection: place_projection @ [.., _],
2414 is_local_mutation_allowed: _,
2415 } => {
2416 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2417 local: place_local,
2418 projection: place_projection,
2419 }) {
2420 self.used_mut_upvars.push(field);
2421 }
2422 }
2423 }
2424 }
2425
2426 fn is_mutable(
2429 &self,
2430 place: PlaceRef<'tcx>,
2431 is_local_mutation_allowed: LocalMutationIsAllowed,
2432 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2433 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2434 match place.last_projection() {
2435 None => {
2436 let local = &self.body.local_decls[place.local];
2437 match local.mutability {
2438 Mutability::Not => match is_local_mutation_allowed {
2439 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2440 place_local: place.local,
2441 place_projection: place.projection,
2442 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2443 }),
2444 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2445 place_local: place.local,
2446 place_projection: place.projection,
2447 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2448 }),
2449 LocalMutationIsAllowed::No => Err(place),
2450 },
2451 Mutability::Mut => Ok(RootPlace {
2452 place_local: place.local,
2453 place_projection: place.projection,
2454 is_local_mutation_allowed,
2455 }),
2456 }
2457 }
2458 Some((place_base, elem)) => {
2459 match elem {
2460 ProjectionElem::Deref => {
2461 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2462
2463 match base_ty.kind() {
2465 ty::Ref(_, _, mutbl) => {
2466 match mutbl {
2467 hir::Mutability::Not => Err(place),
2469 hir::Mutability::Mut => {
2472 let mode = match self.is_upvar_field_projection(place) {
2473 Some(field)
2474 if self.upvars[field.index()].is_by_ref() =>
2475 {
2476 is_local_mutation_allowed
2477 }
2478 _ => LocalMutationIsAllowed::Yes,
2479 };
2480
2481 self.is_mutable(place_base, mode)
2482 }
2483 }
2484 }
2485 ty::RawPtr(_, mutbl) => {
2486 match mutbl {
2487 hir::Mutability::Not => Err(place),
2489 hir::Mutability::Mut => Ok(RootPlace {
2492 place_local: place.local,
2493 place_projection: place.projection,
2494 is_local_mutation_allowed,
2495 }),
2496 }
2497 }
2498 _ if base_ty.is_box() => {
2500 self.is_mutable(place_base, is_local_mutation_allowed)
2501 }
2502 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2504 }
2505 }
2506 ProjectionElem::Field(..)
2509 | ProjectionElem::Index(..)
2510 | ProjectionElem::ConstantIndex { .. }
2511 | ProjectionElem::Subslice { .. }
2512 | ProjectionElem::Subtype(..)
2513 | ProjectionElem::OpaqueCast { .. }
2514 | ProjectionElem::Downcast(..)
2515 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2516 let upvar_field_projection = self.is_upvar_field_projection(place);
2517 if let Some(field) = upvar_field_projection {
2518 let upvar = &self.upvars[field.index()];
2519 debug!(
2520 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2521 place={:?}, place_base={:?}",
2522 upvar, is_local_mutation_allowed, place, place_base
2523 );
2524 match (upvar.mutability, is_local_mutation_allowed) {
2525 (
2526 Mutability::Not,
2527 LocalMutationIsAllowed::No
2528 | LocalMutationIsAllowed::ExceptUpvars,
2529 ) => Err(place),
2530 (Mutability::Not, LocalMutationIsAllowed::Yes)
2531 | (Mutability::Mut, _) => {
2532 let _ =
2551 self.is_mutable(place_base, is_local_mutation_allowed)?;
2552 Ok(RootPlace {
2553 place_local: place.local,
2554 place_projection: place.projection,
2555 is_local_mutation_allowed,
2556 })
2557 }
2558 }
2559 } else {
2560 self.is_mutable(place_base, is_local_mutation_allowed)
2561 }
2562 }
2563 }
2564 }
2565 }
2566 }
2567
2568 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2573 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2574 }
2575
2576 fn dominators(&self) -> &Dominators<BasicBlock> {
2577 self.body.basic_blocks.dominators()
2579 }
2580
2581 fn lint_unused_mut(&self) {
2582 let tcx = self.infcx.tcx;
2583 let body = self.body;
2584 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2585 let local_decl = &body.local_decls[local];
2586 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2587 body.source_scopes[local_decl.source_info.scope].local_data
2588 else {
2589 continue;
2590 };
2591
2592 if self.local_excluded_from_unused_mut_lint(local) {
2594 continue;
2595 }
2596
2597 let span = local_decl.source_info.span;
2598 if span.desugaring_kind().is_some() {
2599 continue;
2601 }
2602
2603 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2604
2605 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2606 }
2607 }
2608}
2609
2610enum Overlap {
2612 Arbitrary,
2618 EqualOrDisjoint,
2623 Disjoint,
2626}