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::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::{DenseBitSet, 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: 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 local_names = IndexVec::from_elem(None, &body.local_decls);
418 for var_debug_info in &body.var_debug_info {
419 if let VarDebugInfoContents::Place(place) = var_debug_info.value {
420 if let Some(local) = place.as_local() {
421 if let Some(prev_name) = local_names[local]
422 && var_debug_info.name != prev_name
423 {
424 span_bug!(
425 var_debug_info.source_info.span,
426 "local {:?} has many names (`{}` vs `{}`)",
427 local,
428 prev_name,
429 var_debug_info.name
430 );
431 }
432 local_names[local] = Some(var_debug_info.name);
433 }
434 }
435 }
436
437 let mut mbcx = MirBorrowckCtxt {
438 root_cx,
439 infcx: &infcx,
440 body,
441 move_data: &move_data,
442 location_table: &location_table,
443 movable_coroutine,
444 fn_self_span_reported: Default::default(),
445 access_place_error_reported: Default::default(),
446 reservation_error_reported: Default::default(),
447 uninitialized_error_reported: Default::default(),
448 regioncx: ®ioncx,
449 used_mut: Default::default(),
450 used_mut_upvars: SmallVec::new(),
451 borrow_set: &borrow_set,
452 upvars: tcx.closure_captures(def),
453 local_names,
454 region_names: RefCell::default(),
455 next_region_name: RefCell::new(1),
456 move_errors: Vec::new(),
457 diags_buffer,
458 polonius_output: polonius_output.as_deref(),
459 polonius_diagnostics: polonius_diagnostics.as_ref(),
460 };
461
462 mbcx.report_region_errors(nll_errors);
464
465 let (mut flow_analysis, flow_entry_states) =
466 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
467 visit_results(
468 body,
469 traversal::reverse_postorder(body).map(|(bb, _)| bb),
470 &mut flow_analysis,
471 &flow_entry_states,
472 &mut mbcx,
473 );
474
475 mbcx.report_move_errors();
476
477 let temporary_used_locals: FxIndexSet<Local> = mbcx
483 .used_mut
484 .iter()
485 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
486 .cloned()
487 .collect();
488 let unused_mut_locals =
492 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
493 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
494
495 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
496 mbcx.lint_unused_mut();
497 if let Some(guar) = mbcx.emit_errors() {
498 mbcx.root_cx.set_tainted_by_errors(guar);
499 }
500
501 let result = PropagatedBorrowCheckResults {
502 closure_requirements: opt_closure_req,
503 used_mut_upvars: mbcx.used_mut_upvars,
504 };
505
506 let body_with_facts = if consumer_options.is_some() {
507 Some(Box::new(BodyWithBorrowckFacts {
508 body: body_owned,
509 promoted,
510 borrow_set,
511 region_inference_context: regioncx,
512 location_table: polonius_input.as_ref().map(|_| location_table),
513 input_facts: polonius_input,
514 output_facts: polonius_output,
515 }))
516 } else {
517 None
518 };
519
520 debug!("do_mir_borrowck: result = {:#?}", result);
521
522 (result, body_with_facts)
523}
524
525fn get_flow_results<'a, 'tcx>(
526 tcx: TyCtxt<'tcx>,
527 body: &'a Body<'tcx>,
528 move_data: &'a MoveData<'tcx>,
529 borrow_set: &'a BorrowSet<'tcx>,
530 regioncx: &RegionInferenceContext<'tcx>,
531) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
532 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
535 tcx,
536 body,
537 Some("borrowck"),
538 );
539 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
540 tcx,
541 body,
542 Some("borrowck"),
543 );
544 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
545 tcx,
546 body,
547 Some("borrowck"),
548 );
549
550 let analysis = Borrowck {
551 borrows: borrows.analysis,
552 uninits: uninits.analysis,
553 ever_inits: ever_inits.analysis,
554 };
555
556 assert_eq!(borrows.results.len(), uninits.results.len());
557 assert_eq!(borrows.results.len(), ever_inits.results.len());
558 let results: Results<_> =
559 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
560 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
561 .collect();
562
563 (analysis, results)
564}
565
566pub(crate) struct BorrowckInferCtxt<'tcx> {
567 pub(crate) infcx: InferCtxt<'tcx>,
568 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
569 pub(crate) param_env: ParamEnv<'tcx>,
570}
571
572impl<'tcx> BorrowckInferCtxt<'tcx> {
573 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
574 let typing_mode = if tcx.use_typing_mode_borrowck() {
575 TypingMode::borrowck(tcx, def_id)
576 } else {
577 TypingMode::analysis_in_body(tcx, def_id)
578 };
579 let infcx = tcx.infer_ctxt().build(typing_mode);
580 let param_env = tcx.param_env(def_id);
581 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
582 }
583
584 pub(crate) fn next_region_var<F>(
585 &self,
586 origin: RegionVariableOrigin,
587 get_ctxt_fn: F,
588 ) -> ty::Region<'tcx>
589 where
590 F: Fn() -> RegionCtxt,
591 {
592 let next_region = self.infcx.next_region_var(origin);
593 let vid = next_region.as_var();
594
595 if cfg!(debug_assertions) {
596 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
597 let ctxt = get_ctxt_fn();
598 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
599 assert_eq!(var_to_origin.insert(vid, ctxt), None);
600 }
601
602 next_region
603 }
604
605 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
606 pub(crate) fn next_nll_region_var<F>(
607 &self,
608 origin: NllRegionVariableOrigin,
609 get_ctxt_fn: F,
610 ) -> ty::Region<'tcx>
611 where
612 F: Fn() -> RegionCtxt,
613 {
614 let next_region = self.infcx.next_nll_region_var(origin);
615 let vid = next_region.as_var();
616
617 if cfg!(debug_assertions) {
618 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
619 let ctxt = get_ctxt_fn();
620 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
621 assert_eq!(var_to_origin.insert(vid, ctxt), None);
622 }
623
624 next_region
625 }
626}
627
628impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
629 type Target = InferCtxt<'tcx>;
630
631 fn deref(&self) -> &Self::Target {
632 &self.infcx
633 }
634}
635
636struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
637 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
638 infcx: &'infcx BorrowckInferCtxt<'tcx>,
639 body: &'a Body<'tcx>,
640 move_data: &'a MoveData<'tcx>,
641
642 location_table: &'a PoloniusLocationTable,
645
646 movable_coroutine: bool,
647 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
653 reservation_error_reported: FxIndexSet<Place<'tcx>>,
661 fn_self_span_reported: FxIndexSet<Span>,
665 uninitialized_error_reported: FxIndexSet<Local>,
668 used_mut: FxIndexSet<Local>,
671 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
674 regioncx: &'a RegionInferenceContext<'tcx>,
677
678 borrow_set: &'a BorrowSet<'tcx>,
680
681 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
683
684 local_names: IndexVec<Local, Option<Symbol>>,
686
687 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
690
691 next_region_name: RefCell<usize>,
693
694 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
695 move_errors: Vec<MoveError<'tcx>>,
696
697 polonius_output: Option<&'a PoloniusOutput>,
699 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
701}
702
703impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
709 fn visit_after_early_statement_effect(
710 &mut self,
711 _analysis: &mut Borrowck<'a, 'tcx>,
712 state: &BorrowckDomain,
713 stmt: &Statement<'tcx>,
714 location: Location,
715 ) {
716 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
717 let span = stmt.source_info.span;
718
719 self.check_activations(location, span, state);
720
721 match &stmt.kind {
722 StatementKind::Assign(box (lhs, rhs)) => {
723 self.consume_rvalue(location, (rhs, span), state);
724
725 self.mutate_place(location, (*lhs, span), Shallow(None), state);
726 }
727 StatementKind::FakeRead(box (_, place)) => {
728 self.check_if_path_or_subpath_is_moved(
739 location,
740 InitializationRequiringAction::Use,
741 (place.as_ref(), span),
742 state,
743 );
744 }
745 StatementKind::Intrinsic(box kind) => match kind {
746 NonDivergingIntrinsic::Assume(op) => {
747 self.consume_operand(location, (op, span), state);
748 }
749 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
750 span,
751 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
752 )
753 }
754 StatementKind::AscribeUserType(..)
756 | StatementKind::PlaceMention(..)
758 | StatementKind::Coverage(..)
760 | StatementKind::ConstEvalCounter
762 | StatementKind::StorageLive(..) => {}
763 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
765 self.check_backward_incompatible_drop(location, **place, state);
766 }
767 StatementKind::StorageDead(local) => {
768 self.access_place(
769 location,
770 (Place::from(*local), span),
771 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
772 LocalMutationIsAllowed::Yes,
773 state,
774 );
775 }
776 StatementKind::Nop
777 | StatementKind::Retag { .. }
778 | StatementKind::Deinit(..)
779 | StatementKind::SetDiscriminant { .. } => {
780 bug!("Statement not allowed in this MIR phase")
781 }
782 }
783 }
784
785 fn visit_after_early_terminator_effect(
786 &mut self,
787 _analysis: &mut Borrowck<'a, 'tcx>,
788 state: &BorrowckDomain,
789 term: &Terminator<'tcx>,
790 loc: Location,
791 ) {
792 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
793 let span = term.source_info.span;
794
795 self.check_activations(loc, span, state);
796
797 match &term.kind {
798 TerminatorKind::SwitchInt { discr, targets: _ } => {
799 self.consume_operand(loc, (discr, span), state);
800 }
801 TerminatorKind::Drop {
802 place,
803 target: _,
804 unwind: _,
805 replace,
806 drop: _,
807 async_fut: _,
808 } => {
809 debug!(
810 "visit_terminator_drop \
811 loc: {:?} term: {:?} place: {:?} span: {:?}",
812 loc, term, place, span
813 );
814
815 let write_kind =
816 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
817 self.access_place(
818 loc,
819 (*place, span),
820 (AccessDepth::Drop, Write(write_kind)),
821 LocalMutationIsAllowed::Yes,
822 state,
823 );
824 }
825 TerminatorKind::Call {
826 func,
827 args,
828 destination,
829 target: _,
830 unwind: _,
831 call_source: _,
832 fn_span: _,
833 } => {
834 self.consume_operand(loc, (func, span), state);
835 for arg in args {
836 self.consume_operand(loc, (&arg.node, arg.span), state);
837 }
838 self.mutate_place(loc, (*destination, span), Deep, state);
839 }
840 TerminatorKind::TailCall { func, args, fn_span: _ } => {
841 self.consume_operand(loc, (func, span), state);
842 for arg in args {
843 self.consume_operand(loc, (&arg.node, arg.span), state);
844 }
845 }
846 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
847 self.consume_operand(loc, (cond, span), state);
848 if let AssertKind::BoundsCheck { len, index } = &**msg {
849 self.consume_operand(loc, (len, span), state);
850 self.consume_operand(loc, (index, span), state);
851 }
852 }
853
854 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
855 self.consume_operand(loc, (value, span), state);
856 self.mutate_place(loc, (*resume_arg, span), Deep, state);
857 }
858
859 TerminatorKind::InlineAsm {
860 asm_macro: _,
861 template: _,
862 operands,
863 options: _,
864 line_spans: _,
865 targets: _,
866 unwind: _,
867 } => {
868 for op in operands {
869 match op {
870 InlineAsmOperand::In { reg: _, value } => {
871 self.consume_operand(loc, (value, span), state);
872 }
873 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
874 if let Some(place) = place {
875 self.mutate_place(loc, (*place, span), Shallow(None), state);
876 }
877 }
878 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
879 self.consume_operand(loc, (in_value, span), state);
880 if let &Some(out_place) = out_place {
881 self.mutate_place(loc, (out_place, span), Shallow(None), state);
882 }
883 }
884 InlineAsmOperand::Const { value: _ }
885 | InlineAsmOperand::SymFn { value: _ }
886 | InlineAsmOperand::SymStatic { def_id: _ }
887 | InlineAsmOperand::Label { target_index: _ } => {}
888 }
889 }
890 }
891
892 TerminatorKind::Goto { target: _ }
893 | TerminatorKind::UnwindTerminate(_)
894 | TerminatorKind::Unreachable
895 | TerminatorKind::UnwindResume
896 | TerminatorKind::Return
897 | TerminatorKind::CoroutineDrop
898 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
899 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
900 }
902 }
903 }
904
905 fn visit_after_primary_terminator_effect(
906 &mut self,
907 _analysis: &mut Borrowck<'a, 'tcx>,
908 state: &BorrowckDomain,
909 term: &Terminator<'tcx>,
910 loc: Location,
911 ) {
912 let span = term.source_info.span;
913
914 match term.kind {
915 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
916 if self.movable_coroutine {
917 for i in state.borrows.iter() {
919 let borrow = &self.borrow_set[i];
920 self.check_for_local_borrow(borrow, span);
921 }
922 }
923 }
924
925 TerminatorKind::UnwindResume
926 | TerminatorKind::Return
927 | TerminatorKind::TailCall { .. }
928 | TerminatorKind::CoroutineDrop => {
929 match self.borrow_set.locals_state_at_exit() {
930 LocalsStateAtExit::AllAreInvalidated => {
931 for i in state.borrows.iter() {
936 let borrow = &self.borrow_set[i];
937 self.check_for_invalidation_at_exit(loc, borrow, span);
938 }
939 }
940 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
943 }
944 }
945
946 TerminatorKind::UnwindTerminate(_)
947 | TerminatorKind::Assert { .. }
948 | TerminatorKind::Call { .. }
949 | TerminatorKind::Drop { .. }
950 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
951 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
952 | TerminatorKind::Goto { .. }
953 | TerminatorKind::SwitchInt { .. }
954 | TerminatorKind::Unreachable
955 | TerminatorKind::InlineAsm { .. } => {}
956 }
957 }
958}
959
960use self::AccessDepth::{Deep, Shallow};
961use self::ReadOrWrite::{Activation, Read, Reservation, Write};
962
963#[derive(Copy, Clone, PartialEq, Eq, Debug)]
964enum ArtificialField {
965 ArrayLength,
966 FakeBorrow,
967}
968
969#[derive(Copy, Clone, PartialEq, Eq, Debug)]
970enum AccessDepth {
971 Shallow(Option<ArtificialField>),
977
978 Deep,
982
983 Drop,
986}
987
988#[derive(Copy, Clone, PartialEq, Eq, Debug)]
991enum ReadOrWrite {
992 Read(ReadKind),
995
996 Write(WriteKind),
1000
1001 Reservation(WriteKind),
1005 Activation(WriteKind, BorrowIndex),
1006}
1007
1008#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1011enum ReadKind {
1012 Borrow(BorrowKind),
1013 Copy,
1014}
1015
1016#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1019enum WriteKind {
1020 StorageDeadOrDrop,
1021 Replace,
1022 MutableBorrow(BorrowKind),
1023 Mutate,
1024 Move,
1025}
1026
1027#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1035enum LocalMutationIsAllowed {
1036 Yes,
1037 ExceptUpvars,
1040 No,
1041}
1042
1043#[derive(Copy, Clone, Debug)]
1044enum InitializationRequiringAction {
1045 Borrow,
1046 MatchOn,
1047 Use,
1048 Assignment,
1049 PartialAssignment,
1050}
1051
1052#[derive(Debug)]
1053struct RootPlace<'tcx> {
1054 place_local: Local,
1055 place_projection: &'tcx [PlaceElem<'tcx>],
1056 is_local_mutation_allowed: LocalMutationIsAllowed,
1057}
1058
1059impl InitializationRequiringAction {
1060 fn as_noun(self) -> &'static str {
1061 match self {
1062 InitializationRequiringAction::Borrow => "borrow",
1063 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1065 InitializationRequiringAction::Assignment => "assign",
1066 InitializationRequiringAction::PartialAssignment => "assign to part",
1067 }
1068 }
1069
1070 fn as_verb_in_past_tense(self) -> &'static str {
1071 match self {
1072 InitializationRequiringAction::Borrow => "borrowed",
1073 InitializationRequiringAction::MatchOn => "matched on",
1074 InitializationRequiringAction::Use => "used",
1075 InitializationRequiringAction::Assignment => "assigned",
1076 InitializationRequiringAction::PartialAssignment => "partially assigned",
1077 }
1078 }
1079
1080 fn as_general_verb_in_past_tense(self) -> &'static str {
1081 match self {
1082 InitializationRequiringAction::Borrow
1083 | InitializationRequiringAction::MatchOn
1084 | InitializationRequiringAction::Use => "used",
1085 InitializationRequiringAction::Assignment => "assigned",
1086 InitializationRequiringAction::PartialAssignment => "partially assigned",
1087 }
1088 }
1089}
1090
1091impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1092 fn body(&self) -> &'a Body<'tcx> {
1093 self.body
1094 }
1095
1096 fn access_place(
1103 &mut self,
1104 location: Location,
1105 place_span: (Place<'tcx>, Span),
1106 kind: (AccessDepth, ReadOrWrite),
1107 is_local_mutation_allowed: LocalMutationIsAllowed,
1108 state: &BorrowckDomain,
1109 ) {
1110 let (sd, rw) = kind;
1111
1112 if let Activation(_, borrow_index) = rw {
1113 if self.reservation_error_reported.contains(&place_span.0) {
1114 debug!(
1115 "skipping access_place for activation of invalid reservation \
1116 place: {:?} borrow_index: {:?}",
1117 place_span.0, borrow_index
1118 );
1119 return;
1120 }
1121 }
1122
1123 if !self.access_place_error_reported.is_empty()
1126 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1127 {
1128 debug!(
1129 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1130 place_span, kind
1131 );
1132 return;
1133 }
1134
1135 let mutability_error = self.check_access_permissions(
1136 place_span,
1137 rw,
1138 is_local_mutation_allowed,
1139 state,
1140 location,
1141 );
1142 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1143
1144 if conflict_error || mutability_error {
1145 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1146 self.access_place_error_reported.insert((place_span.0, place_span.1));
1147 }
1148 }
1149
1150 fn borrows_in_scope<'s>(
1151 &self,
1152 location: Location,
1153 state: &'s BorrowckDomain,
1154 ) -> Cow<'s, DenseBitSet<BorrowIndex>> {
1155 if let Some(polonius) = &self.polonius_output {
1156 let location = self.location_table.start_index(location);
1158 let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
1159 for &idx in polonius.errors_at(location) {
1160 polonius_output.insert(idx);
1161 }
1162 Cow::Owned(polonius_output)
1163 } else {
1164 Cow::Borrowed(&state.borrows)
1165 }
1166 }
1167
1168 #[instrument(level = "debug", skip(self, state))]
1169 fn check_access_for_conflict(
1170 &mut self,
1171 location: Location,
1172 place_span: (Place<'tcx>, Span),
1173 sd: AccessDepth,
1174 rw: ReadOrWrite,
1175 state: &BorrowckDomain,
1176 ) -> bool {
1177 let mut error_reported = false;
1178
1179 let borrows_in_scope = self.borrows_in_scope(location, state);
1180
1181 each_borrow_involving_path(
1182 self,
1183 self.infcx.tcx,
1184 self.body,
1185 (sd, place_span.0),
1186 self.borrow_set,
1187 |borrow_index| borrows_in_scope.contains(borrow_index),
1188 |this, borrow_index, borrow| match (rw, borrow.kind) {
1189 (Activation(_, activating), _) if activating == borrow_index => {
1196 debug!(
1197 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1198 skipping {:?} b/c activation of same borrow_index",
1199 place_span,
1200 sd,
1201 rw,
1202 (borrow_index, borrow),
1203 );
1204 ControlFlow::Continue(())
1205 }
1206
1207 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1208 | (
1209 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1210 BorrowKind::Mut { .. },
1211 ) => ControlFlow::Continue(()),
1212
1213 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1214 ControlFlow::Continue(())
1217 }
1218
1219 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1220 ControlFlow::Continue(())
1222 }
1223
1224 (Read(kind), BorrowKind::Mut { .. }) => {
1225 if !is_active(this.dominators(), borrow, location) {
1227 assert!(borrow.kind.allows_two_phase_borrow());
1228 return ControlFlow::Continue(());
1229 }
1230
1231 error_reported = true;
1232 match kind {
1233 ReadKind::Copy => {
1234 let err = this
1235 .report_use_while_mutably_borrowed(location, place_span, borrow);
1236 this.buffer_error(err);
1237 }
1238 ReadKind::Borrow(bk) => {
1239 let err =
1240 this.report_conflicting_borrow(location, place_span, bk, borrow);
1241 this.buffer_error(err);
1242 }
1243 }
1244 ControlFlow::Break(())
1245 }
1246
1247 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1248 match rw {
1249 Reservation(..) => {
1250 debug!(
1251 "recording invalid reservation of \
1252 place: {:?}",
1253 place_span.0
1254 );
1255 this.reservation_error_reported.insert(place_span.0);
1256 }
1257 Activation(_, activating) => {
1258 debug!(
1259 "observing check_place for activation of \
1260 borrow_index: {:?}",
1261 activating
1262 );
1263 }
1264 Read(..) | Write(..) => {}
1265 }
1266
1267 error_reported = true;
1268 match kind {
1269 WriteKind::MutableBorrow(bk) => {
1270 let err =
1271 this.report_conflicting_borrow(location, place_span, bk, borrow);
1272 this.buffer_error(err);
1273 }
1274 WriteKind::StorageDeadOrDrop => this
1275 .report_borrowed_value_does_not_live_long_enough(
1276 location,
1277 borrow,
1278 place_span,
1279 Some(WriteKind::StorageDeadOrDrop),
1280 ),
1281 WriteKind::Mutate => {
1282 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1283 }
1284 WriteKind::Move => {
1285 this.report_move_out_while_borrowed(location, place_span, borrow)
1286 }
1287 WriteKind::Replace => {
1288 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1289 }
1290 }
1291 ControlFlow::Break(())
1292 }
1293 },
1294 );
1295
1296 error_reported
1297 }
1298
1299 #[instrument(level = "debug", skip(self, state))]
1302 fn check_backward_incompatible_drop(
1303 &mut self,
1304 location: Location,
1305 place: Place<'tcx>,
1306 state: &BorrowckDomain,
1307 ) {
1308 let tcx = self.infcx.tcx;
1309 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1313 AccessDepth::Drop
1314 } else {
1315 AccessDepth::Shallow(None)
1316 };
1317
1318 let borrows_in_scope = self.borrows_in_scope(location, state);
1319
1320 each_borrow_involving_path(
1323 self,
1324 self.infcx.tcx,
1325 self.body,
1326 (sd, place),
1327 self.borrow_set,
1328 |borrow_index| borrows_in_scope.contains(borrow_index),
1329 |this, _borrow_index, borrow| {
1330 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1331 return ControlFlow::Continue(());
1332 }
1333 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1334 let explain = this.explain_why_borrow_contains_point(
1335 location,
1336 borrow,
1337 Some((WriteKind::StorageDeadOrDrop, place)),
1338 );
1339 this.infcx.tcx.node_span_lint(
1340 TAIL_EXPR_DROP_ORDER,
1341 CRATE_HIR_ID,
1342 borrowed,
1343 |diag| {
1344 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1345 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1346 },
1347 );
1348 ControlFlow::Break(())
1350 },
1351 );
1352 }
1353
1354 fn mutate_place(
1355 &mut self,
1356 location: Location,
1357 place_span: (Place<'tcx>, Span),
1358 kind: AccessDepth,
1359 state: &BorrowckDomain,
1360 ) {
1361 self.check_if_assigned_path_is_moved(location, place_span, state);
1363
1364 self.access_place(
1365 location,
1366 place_span,
1367 (kind, Write(WriteKind::Mutate)),
1368 LocalMutationIsAllowed::No,
1369 state,
1370 );
1371 }
1372
1373 fn consume_rvalue(
1374 &mut self,
1375 location: Location,
1376 (rvalue, span): (&Rvalue<'tcx>, Span),
1377 state: &BorrowckDomain,
1378 ) {
1379 match rvalue {
1380 &Rvalue::Ref(_ , bk, place) => {
1381 let access_kind = match bk {
1382 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1383 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1384 }
1385 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1386 (Deep, Read(ReadKind::Borrow(bk)))
1387 }
1388 BorrowKind::Mut { .. } => {
1389 let wk = WriteKind::MutableBorrow(bk);
1390 if bk.allows_two_phase_borrow() {
1391 (Deep, Reservation(wk))
1392 } else {
1393 (Deep, Write(wk))
1394 }
1395 }
1396 };
1397
1398 self.access_place(
1399 location,
1400 (place, span),
1401 access_kind,
1402 LocalMutationIsAllowed::No,
1403 state,
1404 );
1405
1406 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1407 InitializationRequiringAction::MatchOn
1408 } else {
1409 InitializationRequiringAction::Borrow
1410 };
1411
1412 self.check_if_path_or_subpath_is_moved(
1413 location,
1414 action,
1415 (place.as_ref(), span),
1416 state,
1417 );
1418 }
1419
1420 &Rvalue::RawPtr(kind, place) => {
1421 let access_kind = match kind {
1422 RawPtrKind::Mut => (
1423 Deep,
1424 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1425 kind: MutBorrowKind::Default,
1426 })),
1427 ),
1428 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1429 RawPtrKind::FakeForPtrMetadata => {
1430 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1431 }
1432 };
1433
1434 self.access_place(
1435 location,
1436 (place, span),
1437 access_kind,
1438 LocalMutationIsAllowed::No,
1439 state,
1440 );
1441
1442 self.check_if_path_or_subpath_is_moved(
1443 location,
1444 InitializationRequiringAction::Borrow,
1445 (place.as_ref(), span),
1446 state,
1447 );
1448 }
1449
1450 Rvalue::ThreadLocalRef(_) => {}
1451
1452 Rvalue::Use(operand)
1453 | Rvalue::Repeat(operand, _)
1454 | Rvalue::UnaryOp(_ , operand)
1455 | Rvalue::Cast(_ , operand, _ )
1456 | Rvalue::ShallowInitBox(operand, _ ) => {
1457 self.consume_operand(location, (operand, span), state)
1458 }
1459
1460 &Rvalue::CopyForDeref(place) => {
1461 self.access_place(
1462 location,
1463 (place, span),
1464 (Deep, Read(ReadKind::Copy)),
1465 LocalMutationIsAllowed::No,
1466 state,
1467 );
1468
1469 self.check_if_path_or_subpath_is_moved(
1471 location,
1472 InitializationRequiringAction::Use,
1473 (place.as_ref(), span),
1474 state,
1475 );
1476 }
1477
1478 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1479 let af = match *rvalue {
1480 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1481 Rvalue::Discriminant(..) => None,
1482 _ => unreachable!(),
1483 };
1484 self.access_place(
1485 location,
1486 (place, span),
1487 (Shallow(af), Read(ReadKind::Copy)),
1488 LocalMutationIsAllowed::No,
1489 state,
1490 );
1491 self.check_if_path_or_subpath_is_moved(
1492 location,
1493 InitializationRequiringAction::Use,
1494 (place.as_ref(), span),
1495 state,
1496 );
1497 }
1498
1499 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1500 self.consume_operand(location, (operand1, span), state);
1501 self.consume_operand(location, (operand2, span), state);
1502 }
1503
1504 Rvalue::NullaryOp(_op, _ty) => {
1505 }
1507
1508 Rvalue::Aggregate(aggregate_kind, operands) => {
1509 match **aggregate_kind {
1513 AggregateKind::Closure(def_id, _)
1514 | AggregateKind::CoroutineClosure(def_id, _)
1515 | AggregateKind::Coroutine(def_id, _) => {
1516 let def_id = def_id.expect_local();
1517 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1518 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1519 for field in used_mut_upvars.clone() {
1523 self.propagate_closure_used_mut_upvar(&operands[field]);
1524 }
1525 }
1526 AggregateKind::Adt(..)
1527 | AggregateKind::Array(..)
1528 | AggregateKind::Tuple { .. }
1529 | AggregateKind::RawPtr(..) => (),
1530 }
1531
1532 for operand in operands {
1533 self.consume_operand(location, (operand, span), state);
1534 }
1535 }
1536
1537 Rvalue::WrapUnsafeBinder(op, _) => {
1538 self.consume_operand(location, (op, span), state);
1539 }
1540 }
1541 }
1542
1543 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1544 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1545 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1553 this.used_mut_upvars.push(field);
1554 return;
1555 }
1556
1557 for (place_ref, proj) in place.iter_projections().rev() {
1558 if proj == ProjectionElem::Deref {
1560 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1561 ty::Ref(_, _, hir::Mutability::Mut) => return,
1563
1564 _ => {}
1565 }
1566 }
1567
1568 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1570 this.used_mut_upvars.push(field);
1571 return;
1572 }
1573 }
1574
1575 this.used_mut.insert(place.local);
1577 };
1578
1579 match *operand {
1583 Operand::Move(place) | Operand::Copy(place) => {
1584 match place.as_local() {
1585 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1586 if self.body.local_decls[local].ty.is_mutable_ptr() {
1587 return;
1589 }
1590 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1606 bug!("temporary should be tracked");
1607 };
1608 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1609 &self.move_data.inits[init_index]
1610 } else {
1611 bug!("temporary should be initialized exactly once")
1612 };
1613
1614 let InitLocation::Statement(loc) = init.location else {
1615 bug!("temporary initialized in arguments")
1616 };
1617
1618 let body = self.body;
1619 let bbd = &body[loc.block];
1620 let stmt = &bbd.statements[loc.statement_index];
1621 debug!("temporary assigned in: stmt={:?}", stmt);
1622
1623 match stmt.kind {
1624 StatementKind::Assign(box (
1625 _,
1626 Rvalue::Ref(_, _, source)
1627 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1628 )) => {
1629 propagate_closure_used_mut_place(self, source);
1630 }
1631 _ => {
1632 bug!(
1633 "closures should only capture user variables \
1634 or references to user variables"
1635 );
1636 }
1637 }
1638 }
1639 _ => propagate_closure_used_mut_place(self, place),
1640 }
1641 }
1642 Operand::Constant(..) => {}
1643 }
1644 }
1645
1646 fn consume_operand(
1647 &mut self,
1648 location: Location,
1649 (operand, span): (&Operand<'tcx>, Span),
1650 state: &BorrowckDomain,
1651 ) {
1652 match *operand {
1653 Operand::Copy(place) => {
1654 self.access_place(
1657 location,
1658 (place, span),
1659 (Deep, Read(ReadKind::Copy)),
1660 LocalMutationIsAllowed::No,
1661 state,
1662 );
1663
1664 self.check_if_path_or_subpath_is_moved(
1666 location,
1667 InitializationRequiringAction::Use,
1668 (place.as_ref(), span),
1669 state,
1670 );
1671 }
1672 Operand::Move(place) => {
1673 self.check_movable_place(location, place);
1675
1676 self.access_place(
1678 location,
1679 (place, span),
1680 (Deep, Write(WriteKind::Move)),
1681 LocalMutationIsAllowed::Yes,
1682 state,
1683 );
1684
1685 self.check_if_path_or_subpath_is_moved(
1687 location,
1688 InitializationRequiringAction::Use,
1689 (place.as_ref(), span),
1690 state,
1691 );
1692 }
1693 Operand::Constant(_) => {}
1694 }
1695 }
1696
1697 #[instrument(level = "debug", skip(self))]
1700 fn check_for_invalidation_at_exit(
1701 &mut self,
1702 location: Location,
1703 borrow: &BorrowData<'tcx>,
1704 span: Span,
1705 ) {
1706 let place = borrow.borrowed_place;
1707 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1708
1709 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1715 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1719 true
1720 } else {
1721 false
1722 };
1723
1724 let sd = if might_be_alive { Deep } else { Shallow(None) };
1725
1726 if places_conflict::borrow_conflicts_with_place(
1727 self.infcx.tcx,
1728 self.body,
1729 place,
1730 borrow.kind,
1731 root_place,
1732 sd,
1733 places_conflict::PlaceConflictBias::Overlap,
1734 ) {
1735 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1736 let span = self.infcx.tcx.sess.source_map().end_point(span);
1739 self.report_borrowed_value_does_not_live_long_enough(
1740 location,
1741 borrow,
1742 (place, span),
1743 None,
1744 )
1745 }
1746 }
1747
1748 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1751 debug!("check_for_local_borrow({:?})", borrow);
1752
1753 if borrow_of_local_data(borrow.borrowed_place) {
1754 let err = self.cannot_borrow_across_coroutine_yield(
1755 self.retrieve_borrow_spans(borrow).var_or_use(),
1756 yield_span,
1757 );
1758
1759 self.buffer_error(err);
1760 }
1761 }
1762
1763 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1764 for &borrow_index in self.borrow_set.activations_at_location(location) {
1768 let borrow = &self.borrow_set[borrow_index];
1769
1770 assert!(match borrow.kind {
1772 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1773 BorrowKind::Mut { .. } => true,
1774 });
1775
1776 self.access_place(
1777 location,
1778 (borrow.borrowed_place, span),
1779 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1780 LocalMutationIsAllowed::No,
1781 state,
1782 );
1783 }
1787 }
1788
1789 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1790 use IllegalMoveOriginKind::*;
1791
1792 let body = self.body;
1793 let tcx = self.infcx.tcx;
1794 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1795 for (place_ref, elem) in place.iter_projections() {
1796 match elem {
1797 ProjectionElem::Deref => match place_ty.ty.kind() {
1798 ty::Ref(..) | ty::RawPtr(..) => {
1799 self.move_errors.push(MoveError::new(
1800 place,
1801 location,
1802 BorrowedContent {
1803 target_place: place_ref.project_deeper(&[elem], tcx),
1804 },
1805 ));
1806 return;
1807 }
1808 ty::Adt(adt, _) => {
1809 if !adt.is_box() {
1810 bug!("Adt should be a box type when Place is deref");
1811 }
1812 }
1813 ty::Bool
1814 | ty::Char
1815 | ty::Int(_)
1816 | ty::Uint(_)
1817 | ty::Float(_)
1818 | ty::Foreign(_)
1819 | ty::Str
1820 | ty::Array(_, _)
1821 | ty::Pat(_, _)
1822 | ty::Slice(_)
1823 | ty::FnDef(_, _)
1824 | ty::FnPtr(..)
1825 | ty::Dynamic(_, _, _)
1826 | ty::Closure(_, _)
1827 | ty::CoroutineClosure(_, _)
1828 | ty::Coroutine(_, _)
1829 | ty::CoroutineWitness(..)
1830 | ty::Never
1831 | ty::Tuple(_)
1832 | ty::UnsafeBinder(_)
1833 | ty::Alias(_, _)
1834 | ty::Param(_)
1835 | ty::Bound(_, _)
1836 | ty::Infer(_)
1837 | ty::Error(_)
1838 | ty::Placeholder(_) => {
1839 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1840 }
1841 },
1842 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1843 ty::Adt(adt, _) => {
1844 if adt.has_dtor(tcx) {
1845 self.move_errors.push(MoveError::new(
1846 place,
1847 location,
1848 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1849 ));
1850 return;
1851 }
1852 }
1853 ty::Closure(..)
1854 | ty::CoroutineClosure(..)
1855 | ty::Coroutine(_, _)
1856 | ty::Tuple(_) => (),
1857 ty::Bool
1858 | ty::Char
1859 | ty::Int(_)
1860 | ty::Uint(_)
1861 | ty::Float(_)
1862 | ty::Foreign(_)
1863 | ty::Str
1864 | ty::Array(_, _)
1865 | ty::Pat(_, _)
1866 | ty::Slice(_)
1867 | ty::RawPtr(_, _)
1868 | ty::Ref(_, _, _)
1869 | ty::FnDef(_, _)
1870 | ty::FnPtr(..)
1871 | ty::Dynamic(_, _, _)
1872 | ty::CoroutineWitness(..)
1873 | ty::Never
1874 | ty::UnsafeBinder(_)
1875 | ty::Alias(_, _)
1876 | ty::Param(_)
1877 | ty::Bound(_, _)
1878 | ty::Infer(_)
1879 | ty::Error(_)
1880 | ty::Placeholder(_) => bug!(
1881 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1882 ),
1883 },
1884 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1885 match place_ty.ty.kind() {
1886 ty::Slice(_) => {
1887 self.move_errors.push(MoveError::new(
1888 place,
1889 location,
1890 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1891 ));
1892 return;
1893 }
1894 ty::Array(_, _) => (),
1895 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1896 }
1897 }
1898 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1899 ty::Array(..) | ty::Slice(..) => {
1900 self.move_errors.push(MoveError::new(
1901 place,
1902 location,
1903 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1904 ));
1905 return;
1906 }
1907 _ => bug!("Unexpected type {place_ty:#?}"),
1908 },
1909 ProjectionElem::OpaqueCast(_)
1914 | ProjectionElem::Subtype(_)
1915 | ProjectionElem::Downcast(_, _)
1916 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1917 }
1918
1919 place_ty = place_ty.projection_ty(tcx, elem);
1920 }
1921 }
1922
1923 fn check_if_full_path_is_moved(
1924 &mut self,
1925 location: Location,
1926 desired_action: InitializationRequiringAction,
1927 place_span: (PlaceRef<'tcx>, Span),
1928 state: &BorrowckDomain,
1929 ) {
1930 let maybe_uninits = &state.uninits;
1931
1932 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1968 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1969 if maybe_uninits.contains(mpi) {
1970 self.report_use_of_moved_or_uninitialized(
1971 location,
1972 desired_action,
1973 (prefix, place_span.0, place_span.1),
1974 mpi,
1975 );
1976 } }
1983
1984 fn check_if_subslice_element_is_moved(
1990 &mut self,
1991 location: Location,
1992 desired_action: InitializationRequiringAction,
1993 place_span: (PlaceRef<'tcx>, Span),
1994 maybe_uninits: &MixedBitSet<MovePathIndex>,
1995 from: u64,
1996 to: u64,
1997 ) {
1998 if let Some(mpi) = self.move_path_for_place(place_span.0) {
1999 let move_paths = &self.move_data.move_paths;
2000
2001 let root_path = &move_paths[mpi];
2002 for (child_mpi, child_move_path) in root_path.children(move_paths) {
2003 let last_proj = child_move_path.place.projection.last().unwrap();
2004 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
2005 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
2006
2007 if (from..to).contains(offset) {
2008 let uninit_child =
2009 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
2010 maybe_uninits.contains(mpi)
2011 });
2012
2013 if let Some(uninit_child) = uninit_child {
2014 self.report_use_of_moved_or_uninitialized(
2015 location,
2016 desired_action,
2017 (place_span.0, place_span.0, place_span.1),
2018 uninit_child,
2019 );
2020 return; }
2022 }
2023 }
2024 }
2025 }
2026 }
2027
2028 fn check_if_path_or_subpath_is_moved(
2029 &mut self,
2030 location: Location,
2031 desired_action: InitializationRequiringAction,
2032 place_span: (PlaceRef<'tcx>, Span),
2033 state: &BorrowckDomain,
2034 ) {
2035 let maybe_uninits = &state.uninits;
2036
2037 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2053
2054 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2055 place_span.0.last_projection()
2056 {
2057 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2058 if let ty::Array(..) = place_ty.ty.kind() {
2059 self.check_if_subslice_element_is_moved(
2060 location,
2061 desired_action,
2062 (place_base, place_span.1),
2063 maybe_uninits,
2064 from,
2065 to,
2066 );
2067 return;
2068 }
2069 }
2070
2071 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2081 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2082 let uninit_mpi = self
2083 .move_data
2084 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2085
2086 if let Some(uninit_mpi) = uninit_mpi {
2087 self.report_use_of_moved_or_uninitialized(
2088 location,
2089 desired_action,
2090 (place_span.0, place_span.0, place_span.1),
2091 uninit_mpi,
2092 );
2093 return; }
2095 }
2096 }
2097
2098 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2109 match self.move_data.rev_lookup.find(place) {
2110 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2111 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2112 }
2113 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2114 }
2115 }
2116
2117 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2118 match self.move_data.rev_lookup.find(place) {
2123 LookupResult::Parent(_) => None,
2124 LookupResult::Exact(mpi) => Some(mpi),
2125 }
2126 }
2127
2128 fn check_if_assigned_path_is_moved(
2129 &mut self,
2130 location: Location,
2131 (place, span): (Place<'tcx>, Span),
2132 state: &BorrowckDomain,
2133 ) {
2134 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2135
2136 for (place_base, elem) in place.iter_projections().rev() {
2138 match elem {
2139 ProjectionElem::Index(_) |
2140 ProjectionElem::Subtype(_) |
2141 ProjectionElem::OpaqueCast(_) |
2142 ProjectionElem::ConstantIndex { .. } |
2143 ProjectionElem::Downcast(_, _) =>
2145 { }
2149
2150 ProjectionElem::UnwrapUnsafeBinder(_) => {
2151 check_parent_of_field(self, location, place_base, span, state);
2152 }
2153
2154 ProjectionElem::Deref => {
2156 self.check_if_full_path_is_moved(
2157 location, InitializationRequiringAction::Use,
2158 (place_base, span), state);
2159 break;
2162 }
2163
2164 ProjectionElem::Subslice { .. } => {
2165 panic!("we don't allow assignments to subslices, location: {location:?}");
2166 }
2167
2168 ProjectionElem::Field(..) => {
2169 let tcx = self.infcx.tcx;
2173 let base_ty = place_base.ty(self.body(), tcx).ty;
2174 match base_ty.kind() {
2175 ty::Adt(def, _) if def.has_dtor(tcx) => {
2176 self.check_if_path_or_subpath_is_moved(
2177 location, InitializationRequiringAction::Assignment,
2178 (place_base, span), state);
2179
2180 break;
2183 }
2184
2185 ty::Adt(..) | ty::Tuple(..) => {
2188 check_parent_of_field(self, location, place_base, span, state);
2189 }
2190
2191 _ => {}
2192 }
2193 }
2194 }
2195 }
2196
2197 fn check_parent_of_field<'a, 'tcx>(
2198 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2199 location: Location,
2200 base: PlaceRef<'tcx>,
2201 span: Span,
2202 state: &BorrowckDomain,
2203 ) {
2204 let maybe_uninits = &state.uninits;
2236
2237 let mut shortest_uninit_seen = None;
2240 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2241 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2242
2243 if maybe_uninits.contains(mpi) {
2244 debug!(
2245 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2246 shortest_uninit_seen,
2247 Some((prefix, mpi))
2248 );
2249 shortest_uninit_seen = Some((prefix, mpi));
2250 } else {
2251 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2252 }
2253 }
2254
2255 if let Some((prefix, mpi)) = shortest_uninit_seen {
2256 let tcx = this.infcx.tcx;
2262 if base.ty(this.body(), tcx).ty.is_union()
2263 && this.move_data.path_map[mpi].iter().any(|moi| {
2264 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2265 })
2266 {
2267 return;
2268 }
2269
2270 this.report_use_of_moved_or_uninitialized(
2271 location,
2272 InitializationRequiringAction::PartialAssignment,
2273 (prefix, base, span),
2274 mpi,
2275 );
2276
2277 this.used_mut.insert(base.local);
2281 }
2282 }
2283 }
2284
2285 fn check_access_permissions(
2289 &mut self,
2290 (place, span): (Place<'tcx>, Span),
2291 kind: ReadOrWrite,
2292 is_local_mutation_allowed: LocalMutationIsAllowed,
2293 state: &BorrowckDomain,
2294 location: Location,
2295 ) -> bool {
2296 debug!(
2297 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2298 place, kind, is_local_mutation_allowed
2299 );
2300
2301 let error_access;
2302 let the_place_err;
2303
2304 match kind {
2305 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2306 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2307 let is_local_mutation_allowed = match mut_borrow_kind {
2308 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2312 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2313 is_local_mutation_allowed
2314 }
2315 };
2316 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2317 Ok(root_place) => {
2318 self.add_used_mut(root_place, state);
2319 return false;
2320 }
2321 Err(place_err) => {
2322 error_access = AccessKind::MutableBorrow;
2323 the_place_err = place_err;
2324 }
2325 }
2326 }
2327 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2328 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2329 Ok(root_place) => {
2330 self.add_used_mut(root_place, state);
2331 return false;
2332 }
2333 Err(place_err) => {
2334 error_access = AccessKind::Mutate;
2335 the_place_err = place_err;
2336 }
2337 }
2338 }
2339
2340 Reservation(
2341 WriteKind::Move
2342 | WriteKind::Replace
2343 | WriteKind::StorageDeadOrDrop
2344 | WriteKind::MutableBorrow(BorrowKind::Shared)
2345 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2346 )
2347 | Write(
2348 WriteKind::Move
2349 | WriteKind::Replace
2350 | WriteKind::StorageDeadOrDrop
2351 | WriteKind::MutableBorrow(BorrowKind::Shared)
2352 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2353 ) => {
2354 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2355 && !self.has_buffered_diags()
2356 {
2357 self.dcx().span_delayed_bug(
2363 span,
2364 format!(
2365 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2366 ),
2367 );
2368 }
2369 return false;
2370 }
2371 Activation(..) => {
2372 return false;
2374 }
2375 Read(
2376 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2377 | ReadKind::Copy,
2378 ) => {
2379 return false;
2381 }
2382 }
2383
2384 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2389
2390 if let Some(init_index) = previously_initialized {
2392 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2393 let init = &self.move_data.inits[init_index];
2396 let assigned_span = init.span(self.body);
2397 self.report_illegal_reassignment((place, span), assigned_span, place);
2398 } else {
2399 self.report_mutability_error(place, span, the_place_err, error_access, location)
2400 }
2401 true
2402 } else {
2403 false
2404 }
2405 }
2406
2407 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2408 let mpi = self.move_data.rev_lookup.find_local(local)?;
2409 let ii = &self.move_data.init_path_map[mpi];
2410 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2411 }
2412
2413 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2415 match root_place {
2416 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2417 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2421 && self.is_local_ever_initialized(local, state).is_some()
2422 {
2423 self.used_mut.insert(local);
2424 }
2425 }
2426 RootPlace {
2427 place_local: _,
2428 place_projection: _,
2429 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2430 } => {}
2431 RootPlace {
2432 place_local,
2433 place_projection: place_projection @ [.., _],
2434 is_local_mutation_allowed: _,
2435 } => {
2436 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2437 local: place_local,
2438 projection: place_projection,
2439 }) {
2440 self.used_mut_upvars.push(field);
2441 }
2442 }
2443 }
2444 }
2445
2446 fn is_mutable(
2449 &self,
2450 place: PlaceRef<'tcx>,
2451 is_local_mutation_allowed: LocalMutationIsAllowed,
2452 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2453 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2454 match place.last_projection() {
2455 None => {
2456 let local = &self.body.local_decls[place.local];
2457 match local.mutability {
2458 Mutability::Not => match is_local_mutation_allowed {
2459 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2460 place_local: place.local,
2461 place_projection: place.projection,
2462 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2463 }),
2464 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2465 place_local: place.local,
2466 place_projection: place.projection,
2467 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2468 }),
2469 LocalMutationIsAllowed::No => Err(place),
2470 },
2471 Mutability::Mut => Ok(RootPlace {
2472 place_local: place.local,
2473 place_projection: place.projection,
2474 is_local_mutation_allowed,
2475 }),
2476 }
2477 }
2478 Some((place_base, elem)) => {
2479 match elem {
2480 ProjectionElem::Deref => {
2481 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2482
2483 match base_ty.kind() {
2485 ty::Ref(_, _, mutbl) => {
2486 match mutbl {
2487 hir::Mutability::Not => Err(place),
2489 hir::Mutability::Mut => {
2492 let mode = match self.is_upvar_field_projection(place) {
2493 Some(field)
2494 if self.upvars[field.index()].is_by_ref() =>
2495 {
2496 is_local_mutation_allowed
2497 }
2498 _ => LocalMutationIsAllowed::Yes,
2499 };
2500
2501 self.is_mutable(place_base, mode)
2502 }
2503 }
2504 }
2505 ty::RawPtr(_, mutbl) => {
2506 match mutbl {
2507 hir::Mutability::Not => Err(place),
2509 hir::Mutability::Mut => Ok(RootPlace {
2512 place_local: place.local,
2513 place_projection: place.projection,
2514 is_local_mutation_allowed,
2515 }),
2516 }
2517 }
2518 _ if base_ty.is_box() => {
2520 self.is_mutable(place_base, is_local_mutation_allowed)
2521 }
2522 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2524 }
2525 }
2526 ProjectionElem::Field(..)
2529 | ProjectionElem::Index(..)
2530 | ProjectionElem::ConstantIndex { .. }
2531 | ProjectionElem::Subslice { .. }
2532 | ProjectionElem::Subtype(..)
2533 | ProjectionElem::OpaqueCast { .. }
2534 | ProjectionElem::Downcast(..)
2535 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2536 let upvar_field_projection = self.is_upvar_field_projection(place);
2537 if let Some(field) = upvar_field_projection {
2538 let upvar = &self.upvars[field.index()];
2539 debug!(
2540 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2541 place={:?}, place_base={:?}",
2542 upvar, is_local_mutation_allowed, place, place_base
2543 );
2544 match (upvar.mutability, is_local_mutation_allowed) {
2545 (
2546 Mutability::Not,
2547 LocalMutationIsAllowed::No
2548 | LocalMutationIsAllowed::ExceptUpvars,
2549 ) => Err(place),
2550 (Mutability::Not, LocalMutationIsAllowed::Yes)
2551 | (Mutability::Mut, _) => {
2552 let _ =
2571 self.is_mutable(place_base, is_local_mutation_allowed)?;
2572 Ok(RootPlace {
2573 place_local: place.local,
2574 place_projection: place.projection,
2575 is_local_mutation_allowed,
2576 })
2577 }
2578 }
2579 } else {
2580 self.is_mutable(place_base, is_local_mutation_allowed)
2581 }
2582 }
2583 }
2584 }
2585 }
2586 }
2587
2588 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2593 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2594 }
2595
2596 fn dominators(&self) -> &Dominators<BasicBlock> {
2597 self.body.basic_blocks.dominators()
2599 }
2600
2601 fn lint_unused_mut(&self) {
2602 let tcx = self.infcx.tcx;
2603 let body = self.body;
2604 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2605 let local_decl = &body.local_decls[local];
2606 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2607 body.source_scopes[local_decl.source_info.scope].local_data
2608 else {
2609 continue;
2610 };
2611
2612 if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) {
2614 continue;
2615 }
2616
2617 let span = local_decl.source_info.span;
2618 if span.desugaring_kind().is_some() {
2619 continue;
2621 }
2622
2623 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2624
2625 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2626 }
2627 }
2628}
2629
2630enum Overlap {
2632 Arbitrary,
2638 EqualOrDisjoint,
2643 Disjoint,
2646}