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