1#![allow(internal_features)]
5#![cfg_attr(bootstrap, feature(let_chains))]
6#![doc(rust_logo)]
7#![feature(assert_matches)]
8#![feature(box_patterns)]
9#![feature(file_buffered)]
10#![feature(if_let_guard)]
11#![feature(negative_impls)]
12#![feature(never_type)]
13#![feature(rustc_attrs)]
14#![feature(rustdoc_internals)]
15#![feature(stmt_expr_attributes)]
16#![feature(try_blocks)]
17use std::borrow::Cow;
20use std::cell::RefCell;
21use std::marker::PhantomData;
22use std::ops::{ControlFlow, Deref};
23
24use borrow_set::LocalsStateAtExit;
25use root_cx::BorrowCheckRootCtxt;
26use rustc_abi::FieldIdx;
27use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
28use rustc_data_structures::graph::dominators::Dominators;
29use rustc_errors::LintDiagnostic;
30use rustc_hir as hir;
31use rustc_hir::CRATE_HIR_ID;
32use rustc_hir::def_id::LocalDefId;
33use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
34use rustc_index::{IndexSlice, IndexVec};
35use rustc_infer::infer::{
36 InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
37};
38use rustc_middle::mir::*;
39use rustc_middle::query::Providers;
40use rustc_middle::ty::{
41 self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions,
42};
43use rustc_middle::{bug, span_bug};
44use rustc_mir_dataflow::impls::{
45 EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
46};
47use rustc_mir_dataflow::move_paths::{
48 InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
49};
50use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
51use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
52use rustc_span::{ErrorGuaranteed, Span, Symbol};
53use smallvec::SmallVec;
54use tracing::{debug, instrument};
55
56use crate::borrow_set::{BorrowData, BorrowSet};
57use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
58use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
59use crate::diagnostics::{
60 AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
61};
62use crate::path_utils::*;
63use crate::place_ext::PlaceExt;
64use crate::places_conflict::{PlaceConflictBias, places_conflict};
65use crate::polonius::PoloniusDiagnosticsContext;
66use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
67use crate::prefixes::PrefixSet;
68use crate::region_infer::RegionInferenceContext;
69use crate::renumber::RegionCtxt;
70use crate::session_diagnostics::VarNeedNotMut;
71
72mod borrow_set;
73mod borrowck_errors;
74mod constraints;
75mod dataflow;
76mod def_use;
77mod diagnostics;
78mod member_constraints;
79mod nll;
80mod path_utils;
81mod place_ext;
82mod places_conflict;
83mod polonius;
84mod prefixes;
85mod region_infer;
86mod renumber;
87mod root_cx;
88mod session_diagnostics;
89mod type_check;
90mod universal_regions;
91mod used_muts;
92
93pub mod consumers;
95
96rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
97
98struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
100
101impl<'tcx> TyCtxtConsts<'tcx> {
102 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
103}
104
105pub fn provide(providers: &mut Providers) {
106 *providers = Providers { mir_borrowck, ..*providers };
107}
108
109fn mir_borrowck(
113 tcx: TyCtxt<'_>,
114 def: LocalDefId,
115) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
116 assert!(!tcx.is_typeck_child(def.to_def_id()));
117 let (input_body, _) = tcx.mir_promoted(def);
118 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
119
120 let input_body: &Body<'_> = &input_body.borrow();
121 if let Some(guar) = input_body.tainted_by_errors {
122 debug!("Skipping borrowck because of tainted body");
123 Err(guar)
124 } else if input_body.should_skip() {
125 debug!("Skipping borrowck because of injected body");
126 let opaque_types = ConcreteOpaqueTypes(Default::default());
127 Ok(tcx.arena.alloc(opaque_types))
128 } else {
129 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
130 let nested_bodies = tcx.nested_bodies_within(def);
134 for def_id in nested_bodies {
135 root_cx.get_or_insert_nested(def_id);
136 }
137
138 let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
139 do_mir_borrowck(&mut root_cx, def, None).0;
140 debug_assert!(closure_requirements.is_none());
141 debug_assert!(used_mut_upvars.is_empty());
142 root_cx.finalize()
143 }
144}
145
146#[derive(Debug)]
149struct PropagatedBorrowCheckResults<'tcx> {
150 closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
151 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
152}
153
154#[derive(Clone, Debug)]
197pub struct ClosureRegionRequirements<'tcx> {
198 pub num_external_vids: usize,
204
205 pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
208}
209
210#[derive(Copy, Clone, Debug)]
213pub struct ClosureOutlivesRequirement<'tcx> {
214 pub subject: ClosureOutlivesSubject<'tcx>,
216
217 pub outlived_free_region: ty::RegionVid,
219
220 pub blame_span: Span,
222
223 pub category: ConstraintCategory<'tcx>,
225}
226
227#[cfg(target_pointer_width = "64")]
229rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
230
231#[derive(Copy, Clone, Debug)]
234pub enum ClosureOutlivesSubject<'tcx> {
235 Ty(ClosureOutlivesSubjectTy<'tcx>),
239
240 Region(ty::RegionVid),
243}
244
245#[derive(Copy, Clone, Debug)]
251pub struct ClosureOutlivesSubjectTy<'tcx> {
252 inner: Ty<'tcx>,
253}
254impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
257impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
258
259impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
260 pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
263 let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
264 ty::ReVar(vid) => {
265 let br = ty::BoundRegion {
266 var: ty::BoundVar::from_usize(vid.index()),
267 kind: ty::BoundRegionKind::Anon,
268 };
269 ty::Region::new_bound(tcx, depth, br)
270 }
271 _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
272 });
273
274 Self { inner }
275 }
276
277 pub fn instantiate(
278 self,
279 tcx: TyCtxt<'tcx>,
280 mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
281 ) -> Ty<'tcx> {
282 fold_regions(tcx, self.inner, |r, depth| match r.kind() {
283 ty::ReBound(debruijn, br) => {
284 debug_assert_eq!(debruijn, depth);
285 map(ty::RegionVid::from_usize(br.var.index()))
286 }
287 _ => bug!("unexpected region {r:?}"),
288 })
289 }
290}
291
292#[instrument(skip(root_cx), level = "debug")]
300fn do_mir_borrowck<'tcx>(
301 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
302 def: LocalDefId,
303 consumer_options: Option<ConsumerOptions>,
304) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
305 let tcx = root_cx.tcx;
306 let infcx = BorrowckInferCtxt::new(tcx, def);
307 let (input_body, promoted) = tcx.mir_promoted(def);
308 let input_body: &Body<'_> = &input_body.borrow();
309 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
310 if let Some(e) = input_body.tainted_by_errors {
311 infcx.set_tainted_by_errors(e);
312 root_cx.set_tainted_by_errors(e);
313 }
314
315 let mut body_owned = input_body.clone();
320 let mut promoted = input_promoted.to_owned();
321 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
322 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
325
326 let move_data = MoveData::gather_moves(body, tcx, |_| true);
327
328 let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
329 .iterate_to_fixpoint(tcx, body, Some("borrowck"))
330 .into_results_cursor(body);
331
332 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
333 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
334
335 let nll::NllOutput {
337 regioncx,
338 polonius_input,
339 polonius_output,
340 opt_closure_req,
341 nll_errors,
342 polonius_diagnostics,
343 } = nll::compute_regions(
344 root_cx,
345 &infcx,
346 universal_regions,
347 body,
348 &promoted,
349 &location_table,
350 flow_inits,
351 &move_data,
352 &borrow_set,
353 consumer_options,
354 );
355
356 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
359 polonius::dump_polonius_mir(
360 &infcx,
361 body,
362 ®ioncx,
363 &opt_closure_req,
364 &borrow_set,
365 polonius_diagnostics.as_ref(),
366 );
367
368 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
371
372 let movable_coroutine = body.coroutine.is_some()
373 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
374
375 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
376 for promoted_body in &promoted {
379 use rustc_middle::mir::visit::Visitor;
380 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
384 let mut promoted_mbcx = MirBorrowckCtxt {
385 root_cx,
386 infcx: &infcx,
387 body: promoted_body,
388 move_data: &move_data,
389 location_table: &location_table,
391 movable_coroutine,
392 fn_self_span_reported: Default::default(),
393 access_place_error_reported: Default::default(),
394 reservation_error_reported: Default::default(),
395 uninitialized_error_reported: Default::default(),
396 regioncx: ®ioncx,
397 used_mut: Default::default(),
398 used_mut_upvars: SmallVec::new(),
399 borrow_set: &borrow_set,
400 upvars: &[],
401 local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
402 region_names: RefCell::default(),
403 next_region_name: RefCell::new(1),
404 polonius_output: None,
405 move_errors: Vec::new(),
406 diags_buffer,
407 polonius_diagnostics: polonius_diagnostics.as_ref(),
408 };
409 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
410 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
411 }
412
413 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
414 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
415 if let Operand::Move(place) = operand {
416 self.ctxt.check_movable_place(location, *place);
417 }
418 }
419 }
420 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
421 promoted_mbcx.report_move_errors();
422 }
423
424 let mut local_names = IndexVec::from_elem(None, &body.local_decls);
425 for var_debug_info in &body.var_debug_info {
426 if let VarDebugInfoContents::Place(place) = var_debug_info.value {
427 if let Some(local) = place.as_local() {
428 if let Some(prev_name) = local_names[local]
429 && var_debug_info.name != prev_name
430 {
431 span_bug!(
432 var_debug_info.source_info.span,
433 "local {:?} has many names (`{}` vs `{}`)",
434 local,
435 prev_name,
436 var_debug_info.name
437 );
438 }
439 local_names[local] = Some(var_debug_info.name);
440 }
441 }
442 }
443
444 let mut mbcx = MirBorrowckCtxt {
445 root_cx,
446 infcx: &infcx,
447 body,
448 move_data: &move_data,
449 location_table: &location_table,
450 movable_coroutine,
451 fn_self_span_reported: Default::default(),
452 access_place_error_reported: Default::default(),
453 reservation_error_reported: Default::default(),
454 uninitialized_error_reported: Default::default(),
455 regioncx: ®ioncx,
456 used_mut: Default::default(),
457 used_mut_upvars: SmallVec::new(),
458 borrow_set: &borrow_set,
459 upvars: tcx.closure_captures(def),
460 local_names,
461 region_names: RefCell::default(),
462 next_region_name: RefCell::new(1),
463 move_errors: Vec::new(),
464 diags_buffer,
465 polonius_output: polonius_output.as_deref(),
466 polonius_diagnostics: polonius_diagnostics.as_ref(),
467 };
468
469 mbcx.report_region_errors(nll_errors);
471
472 let (mut flow_analysis, flow_entry_states) =
473 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
474 visit_results(
475 body,
476 traversal::reverse_postorder(body).map(|(bb, _)| bb),
477 &mut flow_analysis,
478 &flow_entry_states,
479 &mut mbcx,
480 );
481
482 mbcx.report_move_errors();
483
484 let temporary_used_locals: FxIndexSet<Local> = mbcx
490 .used_mut
491 .iter()
492 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
493 .cloned()
494 .collect();
495 let unused_mut_locals =
499 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
500 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
501
502 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
503 mbcx.lint_unused_mut();
504 if let Some(guar) = mbcx.emit_errors() {
505 mbcx.root_cx.set_tainted_by_errors(guar);
506 }
507
508 let result = PropagatedBorrowCheckResults {
509 closure_requirements: opt_closure_req,
510 used_mut_upvars: mbcx.used_mut_upvars,
511 };
512
513 let body_with_facts = if consumer_options.is_some() {
514 Some(Box::new(BodyWithBorrowckFacts {
515 body: body_owned,
516 promoted,
517 borrow_set,
518 region_inference_context: regioncx,
519 location_table: polonius_input.as_ref().map(|_| location_table),
520 input_facts: polonius_input,
521 output_facts: polonius_output,
522 }))
523 } else {
524 None
525 };
526
527 debug!("do_mir_borrowck: result = {:#?}", result);
528
529 (result, body_with_facts)
530}
531
532fn get_flow_results<'a, 'tcx>(
533 tcx: TyCtxt<'tcx>,
534 body: &'a Body<'tcx>,
535 move_data: &'a MoveData<'tcx>,
536 borrow_set: &'a BorrowSet<'tcx>,
537 regioncx: &RegionInferenceContext<'tcx>,
538) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
539 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
542 tcx,
543 body,
544 Some("borrowck"),
545 );
546 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
547 tcx,
548 body,
549 Some("borrowck"),
550 );
551 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
552 tcx,
553 body,
554 Some("borrowck"),
555 );
556
557 let analysis = Borrowck {
558 borrows: borrows.analysis,
559 uninits: uninits.analysis,
560 ever_inits: ever_inits.analysis,
561 };
562
563 assert_eq!(borrows.results.len(), uninits.results.len());
564 assert_eq!(borrows.results.len(), ever_inits.results.len());
565 let results: Results<_> =
566 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
567 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
568 .collect();
569
570 (analysis, results)
571}
572
573pub(crate) struct BorrowckInferCtxt<'tcx> {
574 pub(crate) infcx: InferCtxt<'tcx>,
575 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
576 pub(crate) param_env: ParamEnv<'tcx>,
577}
578
579impl<'tcx> BorrowckInferCtxt<'tcx> {
580 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
581 let typing_mode = if tcx.use_typing_mode_borrowck() {
582 TypingMode::borrowck(tcx, def_id)
583 } else {
584 TypingMode::analysis_in_body(tcx, def_id)
585 };
586 let infcx = tcx.infer_ctxt().build(typing_mode);
587 let param_env = tcx.param_env(def_id);
588 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
589 }
590
591 pub(crate) fn next_region_var<F>(
592 &self,
593 origin: RegionVariableOrigin,
594 get_ctxt_fn: F,
595 ) -> ty::Region<'tcx>
596 where
597 F: Fn() -> RegionCtxt,
598 {
599 let next_region = self.infcx.next_region_var(origin);
600 let vid = next_region.as_var();
601
602 if cfg!(debug_assertions) {
603 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
604 let ctxt = get_ctxt_fn();
605 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
606 assert_eq!(var_to_origin.insert(vid, ctxt), None);
607 }
608
609 next_region
610 }
611
612 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
613 pub(crate) fn next_nll_region_var<F>(
614 &self,
615 origin: NllRegionVariableOrigin,
616 get_ctxt_fn: F,
617 ) -> ty::Region<'tcx>
618 where
619 F: Fn() -> RegionCtxt,
620 {
621 let next_region = self.infcx.next_nll_region_var(origin);
622 let vid = next_region.as_var();
623
624 if cfg!(debug_assertions) {
625 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
626 let ctxt = get_ctxt_fn();
627 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
628 assert_eq!(var_to_origin.insert(vid, ctxt), None);
629 }
630
631 next_region
632 }
633}
634
635impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
636 type Target = InferCtxt<'tcx>;
637
638 fn deref(&self) -> &Self::Target {
639 &self.infcx
640 }
641}
642
643struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
644 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
645 infcx: &'infcx BorrowckInferCtxt<'tcx>,
646 body: &'a Body<'tcx>,
647 move_data: &'a MoveData<'tcx>,
648
649 location_table: &'a PoloniusLocationTable,
652
653 movable_coroutine: bool,
654 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
660 reservation_error_reported: FxIndexSet<Place<'tcx>>,
668 fn_self_span_reported: FxIndexSet<Span>,
672 uninitialized_error_reported: FxIndexSet<Local>,
675 used_mut: FxIndexSet<Local>,
678 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
681 regioncx: &'a RegionInferenceContext<'tcx>,
684
685 borrow_set: &'a BorrowSet<'tcx>,
687
688 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
690
691 local_names: IndexVec<Local, Option<Symbol>>,
693
694 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
697
698 next_region_name: RefCell<usize>,
700
701 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
702 move_errors: Vec<MoveError<'tcx>>,
703
704 polonius_output: Option<&'a PoloniusOutput>,
706 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
708}
709
710impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
716 fn visit_after_early_statement_effect(
717 &mut self,
718 _analysis: &mut Borrowck<'a, 'tcx>,
719 state: &BorrowckDomain,
720 stmt: &Statement<'tcx>,
721 location: Location,
722 ) {
723 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
724 let span = stmt.source_info.span;
725
726 self.check_activations(location, span, state);
727
728 match &stmt.kind {
729 StatementKind::Assign(box (lhs, rhs)) => {
730 self.consume_rvalue(location, (rhs, span), state);
731
732 self.mutate_place(location, (*lhs, span), Shallow(None), state);
733 }
734 StatementKind::FakeRead(box (_, place)) => {
735 self.check_if_path_or_subpath_is_moved(
746 location,
747 InitializationRequiringAction::Use,
748 (place.as_ref(), span),
749 state,
750 );
751 }
752 StatementKind::Intrinsic(box kind) => match kind {
753 NonDivergingIntrinsic::Assume(op) => {
754 self.consume_operand(location, (op, span), state);
755 }
756 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
757 span,
758 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
759 )
760 }
761 StatementKind::AscribeUserType(..)
763 | StatementKind::PlaceMention(..)
765 | StatementKind::Coverage(..)
767 | StatementKind::ConstEvalCounter
769 | StatementKind::StorageLive(..) => {}
770 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
772 self.check_backward_incompatible_drop(location, **place, state);
773 }
774 StatementKind::StorageDead(local) => {
775 self.access_place(
776 location,
777 (Place::from(*local), span),
778 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
779 LocalMutationIsAllowed::Yes,
780 state,
781 );
782 }
783 StatementKind::Nop
784 | StatementKind::Retag { .. }
785 | StatementKind::Deinit(..)
786 | StatementKind::SetDiscriminant { .. } => {
787 bug!("Statement not allowed in this MIR phase")
788 }
789 }
790 }
791
792 fn visit_after_early_terminator_effect(
793 &mut self,
794 _analysis: &mut Borrowck<'a, 'tcx>,
795 state: &BorrowckDomain,
796 term: &Terminator<'tcx>,
797 loc: Location,
798 ) {
799 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
800 let span = term.source_info.span;
801
802 self.check_activations(loc, span, state);
803
804 match &term.kind {
805 TerminatorKind::SwitchInt { discr, targets: _ } => {
806 self.consume_operand(loc, (discr, span), state);
807 }
808 TerminatorKind::Drop {
809 place,
810 target: _,
811 unwind: _,
812 replace,
813 drop: _,
814 async_fut: _,
815 } => {
816 debug!(
817 "visit_terminator_drop \
818 loc: {:?} term: {:?} place: {:?} span: {:?}",
819 loc, term, place, span
820 );
821
822 let write_kind =
823 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
824 self.access_place(
825 loc,
826 (*place, span),
827 (AccessDepth::Drop, Write(write_kind)),
828 LocalMutationIsAllowed::Yes,
829 state,
830 );
831 }
832 TerminatorKind::Call {
833 func,
834 args,
835 destination,
836 target: _,
837 unwind: _,
838 call_source: _,
839 fn_span: _,
840 } => {
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 self.mutate_place(loc, (*destination, span), Deep, state);
846 }
847 TerminatorKind::TailCall { func, args, fn_span: _ } => {
848 self.consume_operand(loc, (func, span), state);
849 for arg in args {
850 self.consume_operand(loc, (&arg.node, arg.span), state);
851 }
852 }
853 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
854 self.consume_operand(loc, (cond, span), state);
855 if let AssertKind::BoundsCheck { len, index } = &**msg {
856 self.consume_operand(loc, (len, span), state);
857 self.consume_operand(loc, (index, span), state);
858 }
859 }
860
861 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
862 self.consume_operand(loc, (value, span), state);
863 self.mutate_place(loc, (*resume_arg, span), Deep, state);
864 }
865
866 TerminatorKind::InlineAsm {
867 asm_macro: _,
868 template: _,
869 operands,
870 options: _,
871 line_spans: _,
872 targets: _,
873 unwind: _,
874 } => {
875 for op in operands {
876 match op {
877 InlineAsmOperand::In { reg: _, value } => {
878 self.consume_operand(loc, (value, span), state);
879 }
880 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
881 if let Some(place) = place {
882 self.mutate_place(loc, (*place, span), Shallow(None), state);
883 }
884 }
885 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
886 self.consume_operand(loc, (in_value, span), state);
887 if let &Some(out_place) = out_place {
888 self.mutate_place(loc, (out_place, span), Shallow(None), state);
889 }
890 }
891 InlineAsmOperand::Const { value: _ }
892 | InlineAsmOperand::SymFn { value: _ }
893 | InlineAsmOperand::SymStatic { def_id: _ }
894 | InlineAsmOperand::Label { target_index: _ } => {}
895 }
896 }
897 }
898
899 TerminatorKind::Goto { target: _ }
900 | TerminatorKind::UnwindTerminate(_)
901 | TerminatorKind::Unreachable
902 | TerminatorKind::UnwindResume
903 | TerminatorKind::Return
904 | TerminatorKind::CoroutineDrop
905 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
906 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
907 }
909 }
910 }
911
912 fn visit_after_primary_terminator_effect(
913 &mut self,
914 _analysis: &mut Borrowck<'a, 'tcx>,
915 state: &BorrowckDomain,
916 term: &Terminator<'tcx>,
917 loc: Location,
918 ) {
919 let span = term.source_info.span;
920
921 match term.kind {
922 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
923 if self.movable_coroutine {
924 for i in state.borrows.iter() {
926 let borrow = &self.borrow_set[i];
927 self.check_for_local_borrow(borrow, span);
928 }
929 }
930 }
931
932 TerminatorKind::UnwindResume
933 | TerminatorKind::Return
934 | TerminatorKind::TailCall { .. }
935 | TerminatorKind::CoroutineDrop => {
936 match self.borrow_set.locals_state_at_exit() {
937 LocalsStateAtExit::AllAreInvalidated => {
938 for i in state.borrows.iter() {
943 let borrow = &self.borrow_set[i];
944 self.check_for_invalidation_at_exit(loc, borrow, span);
945 }
946 }
947 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
950 }
951 }
952
953 TerminatorKind::UnwindTerminate(_)
954 | TerminatorKind::Assert { .. }
955 | TerminatorKind::Call { .. }
956 | TerminatorKind::Drop { .. }
957 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
958 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
959 | TerminatorKind::Goto { .. }
960 | TerminatorKind::SwitchInt { .. }
961 | TerminatorKind::Unreachable
962 | TerminatorKind::InlineAsm { .. } => {}
963 }
964 }
965}
966
967use self::AccessDepth::{Deep, Shallow};
968use self::ReadOrWrite::{Activation, Read, Reservation, Write};
969
970#[derive(Copy, Clone, PartialEq, Eq, Debug)]
971enum ArtificialField {
972 ArrayLength,
973 FakeBorrow,
974}
975
976#[derive(Copy, Clone, PartialEq, Eq, Debug)]
977enum AccessDepth {
978 Shallow(Option<ArtificialField>),
984
985 Deep,
989
990 Drop,
993}
994
995#[derive(Copy, Clone, PartialEq, Eq, Debug)]
998enum ReadOrWrite {
999 Read(ReadKind),
1002
1003 Write(WriteKind),
1007
1008 Reservation(WriteKind),
1012 Activation(WriteKind, BorrowIndex),
1013}
1014
1015#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1018enum ReadKind {
1019 Borrow(BorrowKind),
1020 Copy,
1021}
1022
1023#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1026enum WriteKind {
1027 StorageDeadOrDrop,
1028 Replace,
1029 MutableBorrow(BorrowKind),
1030 Mutate,
1031 Move,
1032}
1033
1034#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1042enum LocalMutationIsAllowed {
1043 Yes,
1044 ExceptUpvars,
1047 No,
1048}
1049
1050#[derive(Copy, Clone, Debug)]
1051enum InitializationRequiringAction {
1052 Borrow,
1053 MatchOn,
1054 Use,
1055 Assignment,
1056 PartialAssignment,
1057}
1058
1059#[derive(Debug)]
1060struct RootPlace<'tcx> {
1061 place_local: Local,
1062 place_projection: &'tcx [PlaceElem<'tcx>],
1063 is_local_mutation_allowed: LocalMutationIsAllowed,
1064}
1065
1066impl InitializationRequiringAction {
1067 fn as_noun(self) -> &'static str {
1068 match self {
1069 InitializationRequiringAction::Borrow => "borrow",
1070 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1072 InitializationRequiringAction::Assignment => "assign",
1073 InitializationRequiringAction::PartialAssignment => "assign to part",
1074 }
1075 }
1076
1077 fn as_verb_in_past_tense(self) -> &'static str {
1078 match self {
1079 InitializationRequiringAction::Borrow => "borrowed",
1080 InitializationRequiringAction::MatchOn => "matched on",
1081 InitializationRequiringAction::Use => "used",
1082 InitializationRequiringAction::Assignment => "assigned",
1083 InitializationRequiringAction::PartialAssignment => "partially assigned",
1084 }
1085 }
1086
1087 fn as_general_verb_in_past_tense(self) -> &'static str {
1088 match self {
1089 InitializationRequiringAction::Borrow
1090 | InitializationRequiringAction::MatchOn
1091 | InitializationRequiringAction::Use => "used",
1092 InitializationRequiringAction::Assignment => "assigned",
1093 InitializationRequiringAction::PartialAssignment => "partially assigned",
1094 }
1095 }
1096}
1097
1098impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1099 fn body(&self) -> &'a Body<'tcx> {
1100 self.body
1101 }
1102
1103 fn access_place(
1110 &mut self,
1111 location: Location,
1112 place_span: (Place<'tcx>, Span),
1113 kind: (AccessDepth, ReadOrWrite),
1114 is_local_mutation_allowed: LocalMutationIsAllowed,
1115 state: &BorrowckDomain,
1116 ) {
1117 let (sd, rw) = kind;
1118
1119 if let Activation(_, borrow_index) = rw {
1120 if self.reservation_error_reported.contains(&place_span.0) {
1121 debug!(
1122 "skipping access_place for activation of invalid reservation \
1123 place: {:?} borrow_index: {:?}",
1124 place_span.0, borrow_index
1125 );
1126 return;
1127 }
1128 }
1129
1130 if !self.access_place_error_reported.is_empty()
1133 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1134 {
1135 debug!(
1136 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1137 place_span, kind
1138 );
1139 return;
1140 }
1141
1142 let mutability_error = self.check_access_permissions(
1143 place_span,
1144 rw,
1145 is_local_mutation_allowed,
1146 state,
1147 location,
1148 );
1149 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1150
1151 if conflict_error || mutability_error {
1152 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1153 self.access_place_error_reported.insert((place_span.0, place_span.1));
1154 }
1155 }
1156
1157 fn borrows_in_scope<'s>(
1158 &self,
1159 location: Location,
1160 state: &'s BorrowckDomain,
1161 ) -> Cow<'s, DenseBitSet<BorrowIndex>> {
1162 if let Some(polonius) = &self.polonius_output {
1163 let location = self.location_table.start_index(location);
1165 let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
1166 for &idx in polonius.errors_at(location) {
1167 polonius_output.insert(idx);
1168 }
1169 Cow::Owned(polonius_output)
1170 } else {
1171 Cow::Borrowed(&state.borrows)
1172 }
1173 }
1174
1175 #[instrument(level = "debug", skip(self, state))]
1176 fn check_access_for_conflict(
1177 &mut self,
1178 location: Location,
1179 place_span: (Place<'tcx>, Span),
1180 sd: AccessDepth,
1181 rw: ReadOrWrite,
1182 state: &BorrowckDomain,
1183 ) -> bool {
1184 let mut error_reported = false;
1185
1186 let borrows_in_scope = self.borrows_in_scope(location, state);
1187
1188 each_borrow_involving_path(
1189 self,
1190 self.infcx.tcx,
1191 self.body,
1192 (sd, place_span.0),
1193 self.borrow_set,
1194 |borrow_index| borrows_in_scope.contains(borrow_index),
1195 |this, borrow_index, borrow| match (rw, borrow.kind) {
1196 (Activation(_, activating), _) if activating == borrow_index => {
1203 debug!(
1204 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1205 skipping {:?} b/c activation of same borrow_index",
1206 place_span,
1207 sd,
1208 rw,
1209 (borrow_index, borrow),
1210 );
1211 ControlFlow::Continue(())
1212 }
1213
1214 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1215 | (
1216 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1217 BorrowKind::Mut { .. },
1218 ) => ControlFlow::Continue(()),
1219
1220 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1221 ControlFlow::Continue(())
1224 }
1225
1226 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1227 ControlFlow::Continue(())
1229 }
1230
1231 (Read(kind), BorrowKind::Mut { .. }) => {
1232 if !is_active(this.dominators(), borrow, location) {
1234 assert!(borrow.kind.allows_two_phase_borrow());
1235 return ControlFlow::Continue(());
1236 }
1237
1238 error_reported = true;
1239 match kind {
1240 ReadKind::Copy => {
1241 let err = this
1242 .report_use_while_mutably_borrowed(location, place_span, borrow);
1243 this.buffer_error(err);
1244 }
1245 ReadKind::Borrow(bk) => {
1246 let err =
1247 this.report_conflicting_borrow(location, place_span, bk, borrow);
1248 this.buffer_error(err);
1249 }
1250 }
1251 ControlFlow::Break(())
1252 }
1253
1254 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1255 match rw {
1256 Reservation(..) => {
1257 debug!(
1258 "recording invalid reservation of \
1259 place: {:?}",
1260 place_span.0
1261 );
1262 this.reservation_error_reported.insert(place_span.0);
1263 }
1264 Activation(_, activating) => {
1265 debug!(
1266 "observing check_place for activation of \
1267 borrow_index: {:?}",
1268 activating
1269 );
1270 }
1271 Read(..) | Write(..) => {}
1272 }
1273
1274 error_reported = true;
1275 match kind {
1276 WriteKind::MutableBorrow(bk) => {
1277 let err =
1278 this.report_conflicting_borrow(location, place_span, bk, borrow);
1279 this.buffer_error(err);
1280 }
1281 WriteKind::StorageDeadOrDrop => this
1282 .report_borrowed_value_does_not_live_long_enough(
1283 location,
1284 borrow,
1285 place_span,
1286 Some(WriteKind::StorageDeadOrDrop),
1287 ),
1288 WriteKind::Mutate => {
1289 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1290 }
1291 WriteKind::Move => {
1292 this.report_move_out_while_borrowed(location, place_span, borrow)
1293 }
1294 WriteKind::Replace => {
1295 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1296 }
1297 }
1298 ControlFlow::Break(())
1299 }
1300 },
1301 );
1302
1303 error_reported
1304 }
1305
1306 #[instrument(level = "debug", skip(self, state))]
1309 fn check_backward_incompatible_drop(
1310 &mut self,
1311 location: Location,
1312 place: Place<'tcx>,
1313 state: &BorrowckDomain,
1314 ) {
1315 let tcx = self.infcx.tcx;
1316 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1320 AccessDepth::Drop
1321 } else {
1322 AccessDepth::Shallow(None)
1323 };
1324
1325 let borrows_in_scope = self.borrows_in_scope(location, state);
1326
1327 each_borrow_involving_path(
1330 self,
1331 self.infcx.tcx,
1332 self.body,
1333 (sd, place),
1334 self.borrow_set,
1335 |borrow_index| borrows_in_scope.contains(borrow_index),
1336 |this, _borrow_index, borrow| {
1337 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1338 return ControlFlow::Continue(());
1339 }
1340 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1341 let explain = this.explain_why_borrow_contains_point(
1342 location,
1343 borrow,
1344 Some((WriteKind::StorageDeadOrDrop, place)),
1345 );
1346 this.infcx.tcx.node_span_lint(
1347 TAIL_EXPR_DROP_ORDER,
1348 CRATE_HIR_ID,
1349 borrowed,
1350 |diag| {
1351 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1352 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1353 },
1354 );
1355 ControlFlow::Break(())
1357 },
1358 );
1359 }
1360
1361 fn mutate_place(
1362 &mut self,
1363 location: Location,
1364 place_span: (Place<'tcx>, Span),
1365 kind: AccessDepth,
1366 state: &BorrowckDomain,
1367 ) {
1368 self.check_if_assigned_path_is_moved(location, place_span, state);
1370
1371 self.access_place(
1372 location,
1373 place_span,
1374 (kind, Write(WriteKind::Mutate)),
1375 LocalMutationIsAllowed::No,
1376 state,
1377 );
1378 }
1379
1380 fn consume_rvalue(
1381 &mut self,
1382 location: Location,
1383 (rvalue, span): (&Rvalue<'tcx>, Span),
1384 state: &BorrowckDomain,
1385 ) {
1386 match rvalue {
1387 &Rvalue::Ref(_ , bk, place) => {
1388 let access_kind = match bk {
1389 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1390 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1391 }
1392 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1393 (Deep, Read(ReadKind::Borrow(bk)))
1394 }
1395 BorrowKind::Mut { .. } => {
1396 let wk = WriteKind::MutableBorrow(bk);
1397 if bk.allows_two_phase_borrow() {
1398 (Deep, Reservation(wk))
1399 } else {
1400 (Deep, Write(wk))
1401 }
1402 }
1403 };
1404
1405 self.access_place(
1406 location,
1407 (place, span),
1408 access_kind,
1409 LocalMutationIsAllowed::No,
1410 state,
1411 );
1412
1413 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1414 InitializationRequiringAction::MatchOn
1415 } else {
1416 InitializationRequiringAction::Borrow
1417 };
1418
1419 self.check_if_path_or_subpath_is_moved(
1420 location,
1421 action,
1422 (place.as_ref(), span),
1423 state,
1424 );
1425 }
1426
1427 &Rvalue::RawPtr(kind, place) => {
1428 let access_kind = match kind {
1429 RawPtrKind::Mut => (
1430 Deep,
1431 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1432 kind: MutBorrowKind::Default,
1433 })),
1434 ),
1435 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1436 RawPtrKind::FakeForPtrMetadata => {
1437 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1438 }
1439 };
1440
1441 self.access_place(
1442 location,
1443 (place, span),
1444 access_kind,
1445 LocalMutationIsAllowed::No,
1446 state,
1447 );
1448
1449 self.check_if_path_or_subpath_is_moved(
1450 location,
1451 InitializationRequiringAction::Borrow,
1452 (place.as_ref(), span),
1453 state,
1454 );
1455 }
1456
1457 Rvalue::ThreadLocalRef(_) => {}
1458
1459 Rvalue::Use(operand)
1460 | Rvalue::Repeat(operand, _)
1461 | Rvalue::UnaryOp(_ , operand)
1462 | Rvalue::Cast(_ , operand, _ )
1463 | Rvalue::ShallowInitBox(operand, _ ) => {
1464 self.consume_operand(location, (operand, span), state)
1465 }
1466
1467 &Rvalue::CopyForDeref(place) => {
1468 self.access_place(
1469 location,
1470 (place, span),
1471 (Deep, Read(ReadKind::Copy)),
1472 LocalMutationIsAllowed::No,
1473 state,
1474 );
1475
1476 self.check_if_path_or_subpath_is_moved(
1478 location,
1479 InitializationRequiringAction::Use,
1480 (place.as_ref(), span),
1481 state,
1482 );
1483 }
1484
1485 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1486 let af = match *rvalue {
1487 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1488 Rvalue::Discriminant(..) => None,
1489 _ => unreachable!(),
1490 };
1491 self.access_place(
1492 location,
1493 (place, span),
1494 (Shallow(af), Read(ReadKind::Copy)),
1495 LocalMutationIsAllowed::No,
1496 state,
1497 );
1498 self.check_if_path_or_subpath_is_moved(
1499 location,
1500 InitializationRequiringAction::Use,
1501 (place.as_ref(), span),
1502 state,
1503 );
1504 }
1505
1506 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1507 self.consume_operand(location, (operand1, span), state);
1508 self.consume_operand(location, (operand2, span), state);
1509 }
1510
1511 Rvalue::NullaryOp(_op, _ty) => {
1512 }
1514
1515 Rvalue::Aggregate(aggregate_kind, operands) => {
1516 match **aggregate_kind {
1520 AggregateKind::Closure(def_id, _)
1521 | AggregateKind::CoroutineClosure(def_id, _)
1522 | AggregateKind::Coroutine(def_id, _) => {
1523 let def_id = def_id.expect_local();
1524 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1525 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1526 for field in used_mut_upvars.clone() {
1530 self.propagate_closure_used_mut_upvar(&operands[field]);
1531 }
1532 }
1533 AggregateKind::Adt(..)
1534 | AggregateKind::Array(..)
1535 | AggregateKind::Tuple { .. }
1536 | AggregateKind::RawPtr(..) => (),
1537 }
1538
1539 for operand in operands {
1540 self.consume_operand(location, (operand, span), state);
1541 }
1542 }
1543
1544 Rvalue::WrapUnsafeBinder(op, _) => {
1545 self.consume_operand(location, (op, span), state);
1546 }
1547 }
1548 }
1549
1550 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1551 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1552 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1560 this.used_mut_upvars.push(field);
1561 return;
1562 }
1563
1564 for (place_ref, proj) in place.iter_projections().rev() {
1565 if proj == ProjectionElem::Deref {
1567 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1568 ty::Ref(_, _, hir::Mutability::Mut) => return,
1570
1571 _ => {}
1572 }
1573 }
1574
1575 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1577 this.used_mut_upvars.push(field);
1578 return;
1579 }
1580 }
1581
1582 this.used_mut.insert(place.local);
1584 };
1585
1586 match *operand {
1590 Operand::Move(place) | Operand::Copy(place) => {
1591 match place.as_local() {
1592 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1593 if self.body.local_decls[local].ty.is_mutable_ptr() {
1594 return;
1596 }
1597 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1613 bug!("temporary should be tracked");
1614 };
1615 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1616 &self.move_data.inits[init_index]
1617 } else {
1618 bug!("temporary should be initialized exactly once")
1619 };
1620
1621 let InitLocation::Statement(loc) = init.location else {
1622 bug!("temporary initialized in arguments")
1623 };
1624
1625 let body = self.body;
1626 let bbd = &body[loc.block];
1627 let stmt = &bbd.statements[loc.statement_index];
1628 debug!("temporary assigned in: stmt={:?}", stmt);
1629
1630 match stmt.kind {
1631 StatementKind::Assign(box (
1632 _,
1633 Rvalue::Ref(_, _, source)
1634 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1635 )) => {
1636 propagate_closure_used_mut_place(self, source);
1637 }
1638 _ => {
1639 bug!(
1640 "closures should only capture user variables \
1641 or references to user variables"
1642 );
1643 }
1644 }
1645 }
1646 _ => propagate_closure_used_mut_place(self, place),
1647 }
1648 }
1649 Operand::Constant(..) => {}
1650 }
1651 }
1652
1653 fn consume_operand(
1654 &mut self,
1655 location: Location,
1656 (operand, span): (&Operand<'tcx>, Span),
1657 state: &BorrowckDomain,
1658 ) {
1659 match *operand {
1660 Operand::Copy(place) => {
1661 self.access_place(
1664 location,
1665 (place, span),
1666 (Deep, Read(ReadKind::Copy)),
1667 LocalMutationIsAllowed::No,
1668 state,
1669 );
1670
1671 self.check_if_path_or_subpath_is_moved(
1673 location,
1674 InitializationRequiringAction::Use,
1675 (place.as_ref(), span),
1676 state,
1677 );
1678 }
1679 Operand::Move(place) => {
1680 self.check_movable_place(location, place);
1682
1683 self.access_place(
1685 location,
1686 (place, span),
1687 (Deep, Write(WriteKind::Move)),
1688 LocalMutationIsAllowed::Yes,
1689 state,
1690 );
1691
1692 self.check_if_path_or_subpath_is_moved(
1694 location,
1695 InitializationRequiringAction::Use,
1696 (place.as_ref(), span),
1697 state,
1698 );
1699 }
1700 Operand::Constant(_) => {}
1701 }
1702 }
1703
1704 #[instrument(level = "debug", skip(self))]
1707 fn check_for_invalidation_at_exit(
1708 &mut self,
1709 location: Location,
1710 borrow: &BorrowData<'tcx>,
1711 span: Span,
1712 ) {
1713 let place = borrow.borrowed_place;
1714 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1715
1716 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1722 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1726 true
1727 } else {
1728 false
1729 };
1730
1731 let sd = if might_be_alive { Deep } else { Shallow(None) };
1732
1733 if places_conflict::borrow_conflicts_with_place(
1734 self.infcx.tcx,
1735 self.body,
1736 place,
1737 borrow.kind,
1738 root_place,
1739 sd,
1740 places_conflict::PlaceConflictBias::Overlap,
1741 ) {
1742 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1743 let span = self.infcx.tcx.sess.source_map().end_point(span);
1746 self.report_borrowed_value_does_not_live_long_enough(
1747 location,
1748 borrow,
1749 (place, span),
1750 None,
1751 )
1752 }
1753 }
1754
1755 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1758 debug!("check_for_local_borrow({:?})", borrow);
1759
1760 if borrow_of_local_data(borrow.borrowed_place) {
1761 let err = self.cannot_borrow_across_coroutine_yield(
1762 self.retrieve_borrow_spans(borrow).var_or_use(),
1763 yield_span,
1764 );
1765
1766 self.buffer_error(err);
1767 }
1768 }
1769
1770 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1771 for &borrow_index in self.borrow_set.activations_at_location(location) {
1775 let borrow = &self.borrow_set[borrow_index];
1776
1777 assert!(match borrow.kind {
1779 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1780 BorrowKind::Mut { .. } => true,
1781 });
1782
1783 self.access_place(
1784 location,
1785 (borrow.borrowed_place, span),
1786 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1787 LocalMutationIsAllowed::No,
1788 state,
1789 );
1790 }
1794 }
1795
1796 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1797 use IllegalMoveOriginKind::*;
1798
1799 let body = self.body;
1800 let tcx = self.infcx.tcx;
1801 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1802 for (place_ref, elem) in place.iter_projections() {
1803 match elem {
1804 ProjectionElem::Deref => match place_ty.ty.kind() {
1805 ty::Ref(..) | ty::RawPtr(..) => {
1806 self.move_errors.push(MoveError::new(
1807 place,
1808 location,
1809 BorrowedContent {
1810 target_place: place_ref.project_deeper(&[elem], tcx),
1811 },
1812 ));
1813 return;
1814 }
1815 ty::Adt(adt, _) => {
1816 if !adt.is_box() {
1817 bug!("Adt should be a box type when Place is deref");
1818 }
1819 }
1820 ty::Bool
1821 | ty::Char
1822 | ty::Int(_)
1823 | ty::Uint(_)
1824 | ty::Float(_)
1825 | ty::Foreign(_)
1826 | ty::Str
1827 | ty::Array(_, _)
1828 | ty::Pat(_, _)
1829 | ty::Slice(_)
1830 | ty::FnDef(_, _)
1831 | ty::FnPtr(..)
1832 | ty::Dynamic(_, _, _)
1833 | ty::Closure(_, _)
1834 | ty::CoroutineClosure(_, _)
1835 | ty::Coroutine(_, _)
1836 | ty::CoroutineWitness(..)
1837 | ty::Never
1838 | ty::Tuple(_)
1839 | ty::UnsafeBinder(_)
1840 | ty::Alias(_, _)
1841 | ty::Param(_)
1842 | ty::Bound(_, _)
1843 | ty::Infer(_)
1844 | ty::Error(_)
1845 | ty::Placeholder(_) => {
1846 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1847 }
1848 },
1849 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1850 ty::Adt(adt, _) => {
1851 if adt.has_dtor(tcx) {
1852 self.move_errors.push(MoveError::new(
1853 place,
1854 location,
1855 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1856 ));
1857 return;
1858 }
1859 }
1860 ty::Closure(..)
1861 | ty::CoroutineClosure(..)
1862 | ty::Coroutine(_, _)
1863 | ty::Tuple(_) => (),
1864 ty::Bool
1865 | ty::Char
1866 | ty::Int(_)
1867 | ty::Uint(_)
1868 | ty::Float(_)
1869 | ty::Foreign(_)
1870 | ty::Str
1871 | ty::Array(_, _)
1872 | ty::Pat(_, _)
1873 | ty::Slice(_)
1874 | ty::RawPtr(_, _)
1875 | ty::Ref(_, _, _)
1876 | ty::FnDef(_, _)
1877 | ty::FnPtr(..)
1878 | ty::Dynamic(_, _, _)
1879 | ty::CoroutineWitness(..)
1880 | ty::Never
1881 | ty::UnsafeBinder(_)
1882 | ty::Alias(_, _)
1883 | ty::Param(_)
1884 | ty::Bound(_, _)
1885 | ty::Infer(_)
1886 | ty::Error(_)
1887 | ty::Placeholder(_) => bug!(
1888 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1889 ),
1890 },
1891 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1892 match place_ty.ty.kind() {
1893 ty::Slice(_) => {
1894 self.move_errors.push(MoveError::new(
1895 place,
1896 location,
1897 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1898 ));
1899 return;
1900 }
1901 ty::Array(_, _) => (),
1902 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1903 }
1904 }
1905 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1906 ty::Array(..) | ty::Slice(..) => {
1907 self.move_errors.push(MoveError::new(
1908 place,
1909 location,
1910 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1911 ));
1912 return;
1913 }
1914 _ => bug!("Unexpected type {place_ty:#?}"),
1915 },
1916 ProjectionElem::OpaqueCast(_)
1921 | ProjectionElem::Subtype(_)
1922 | ProjectionElem::Downcast(_, _)
1923 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1924 }
1925
1926 place_ty = place_ty.projection_ty(tcx, elem);
1927 }
1928 }
1929
1930 fn check_if_full_path_is_moved(
1931 &mut self,
1932 location: Location,
1933 desired_action: InitializationRequiringAction,
1934 place_span: (PlaceRef<'tcx>, Span),
1935 state: &BorrowckDomain,
1936 ) {
1937 let maybe_uninits = &state.uninits;
1938
1939 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1975 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1976 if maybe_uninits.contains(mpi) {
1977 self.report_use_of_moved_or_uninitialized(
1978 location,
1979 desired_action,
1980 (prefix, place_span.0, place_span.1),
1981 mpi,
1982 );
1983 } }
1990
1991 fn check_if_subslice_element_is_moved(
1997 &mut self,
1998 location: Location,
1999 desired_action: InitializationRequiringAction,
2000 place_span: (PlaceRef<'tcx>, Span),
2001 maybe_uninits: &MixedBitSet<MovePathIndex>,
2002 from: u64,
2003 to: u64,
2004 ) {
2005 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2006 let move_paths = &self.move_data.move_paths;
2007
2008 let root_path = &move_paths[mpi];
2009 for (child_mpi, child_move_path) in root_path.children(move_paths) {
2010 let last_proj = child_move_path.place.projection.last().unwrap();
2011 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
2012 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
2013
2014 if (from..to).contains(offset) {
2015 let uninit_child =
2016 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
2017 maybe_uninits.contains(mpi)
2018 });
2019
2020 if let Some(uninit_child) = uninit_child {
2021 self.report_use_of_moved_or_uninitialized(
2022 location,
2023 desired_action,
2024 (place_span.0, place_span.0, place_span.1),
2025 uninit_child,
2026 );
2027 return; }
2029 }
2030 }
2031 }
2032 }
2033 }
2034
2035 fn check_if_path_or_subpath_is_moved(
2036 &mut self,
2037 location: Location,
2038 desired_action: InitializationRequiringAction,
2039 place_span: (PlaceRef<'tcx>, Span),
2040 state: &BorrowckDomain,
2041 ) {
2042 let maybe_uninits = &state.uninits;
2043
2044 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2060
2061 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2062 place_span.0.last_projection()
2063 {
2064 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2065 if let ty::Array(..) = place_ty.ty.kind() {
2066 self.check_if_subslice_element_is_moved(
2067 location,
2068 desired_action,
2069 (place_base, place_span.1),
2070 maybe_uninits,
2071 from,
2072 to,
2073 );
2074 return;
2075 }
2076 }
2077
2078 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2088 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2089 let uninit_mpi = self
2090 .move_data
2091 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2092
2093 if let Some(uninit_mpi) = uninit_mpi {
2094 self.report_use_of_moved_or_uninitialized(
2095 location,
2096 desired_action,
2097 (place_span.0, place_span.0, place_span.1),
2098 uninit_mpi,
2099 );
2100 return; }
2102 }
2103 }
2104
2105 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2116 match self.move_data.rev_lookup.find(place) {
2117 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2118 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2119 }
2120 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2121 }
2122 }
2123
2124 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2125 match self.move_data.rev_lookup.find(place) {
2130 LookupResult::Parent(_) => None,
2131 LookupResult::Exact(mpi) => Some(mpi),
2132 }
2133 }
2134
2135 fn check_if_assigned_path_is_moved(
2136 &mut self,
2137 location: Location,
2138 (place, span): (Place<'tcx>, Span),
2139 state: &BorrowckDomain,
2140 ) {
2141 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2142
2143 for (place_base, elem) in place.iter_projections().rev() {
2145 match elem {
2146 ProjectionElem::Index(_) |
2147 ProjectionElem::Subtype(_) |
2148 ProjectionElem::OpaqueCast(_) |
2149 ProjectionElem::ConstantIndex { .. } |
2150 ProjectionElem::Downcast(_, _) =>
2152 { }
2156
2157 ProjectionElem::UnwrapUnsafeBinder(_) => {
2158 check_parent_of_field(self, location, place_base, span, state);
2159 }
2160
2161 ProjectionElem::Deref => {
2163 self.check_if_full_path_is_moved(
2164 location, InitializationRequiringAction::Use,
2165 (place_base, span), state);
2166 break;
2169 }
2170
2171 ProjectionElem::Subslice { .. } => {
2172 panic!("we don't allow assignments to subslices, location: {location:?}");
2173 }
2174
2175 ProjectionElem::Field(..) => {
2176 let tcx = self.infcx.tcx;
2180 let base_ty = place_base.ty(self.body(), tcx).ty;
2181 match base_ty.kind() {
2182 ty::Adt(def, _) if def.has_dtor(tcx) => {
2183 self.check_if_path_or_subpath_is_moved(
2184 location, InitializationRequiringAction::Assignment,
2185 (place_base, span), state);
2186
2187 break;
2190 }
2191
2192 ty::Adt(..) | ty::Tuple(..) => {
2195 check_parent_of_field(self, location, place_base, span, state);
2196 }
2197
2198 _ => {}
2199 }
2200 }
2201 }
2202 }
2203
2204 fn check_parent_of_field<'a, 'tcx>(
2205 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2206 location: Location,
2207 base: PlaceRef<'tcx>,
2208 span: Span,
2209 state: &BorrowckDomain,
2210 ) {
2211 let maybe_uninits = &state.uninits;
2243
2244 let mut shortest_uninit_seen = None;
2247 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2248 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2249
2250 if maybe_uninits.contains(mpi) {
2251 debug!(
2252 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2253 shortest_uninit_seen,
2254 Some((prefix, mpi))
2255 );
2256 shortest_uninit_seen = Some((prefix, mpi));
2257 } else {
2258 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2259 }
2260 }
2261
2262 if let Some((prefix, mpi)) = shortest_uninit_seen {
2263 let tcx = this.infcx.tcx;
2269 if base.ty(this.body(), tcx).ty.is_union()
2270 && this.move_data.path_map[mpi].iter().any(|moi| {
2271 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2272 })
2273 {
2274 return;
2275 }
2276
2277 this.report_use_of_moved_or_uninitialized(
2278 location,
2279 InitializationRequiringAction::PartialAssignment,
2280 (prefix, base, span),
2281 mpi,
2282 );
2283
2284 this.used_mut.insert(base.local);
2288 }
2289 }
2290 }
2291
2292 fn check_access_permissions(
2296 &mut self,
2297 (place, span): (Place<'tcx>, Span),
2298 kind: ReadOrWrite,
2299 is_local_mutation_allowed: LocalMutationIsAllowed,
2300 state: &BorrowckDomain,
2301 location: Location,
2302 ) -> bool {
2303 debug!(
2304 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2305 place, kind, is_local_mutation_allowed
2306 );
2307
2308 let error_access;
2309 let the_place_err;
2310
2311 match kind {
2312 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2313 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2314 let is_local_mutation_allowed = match mut_borrow_kind {
2315 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2319 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2320 is_local_mutation_allowed
2321 }
2322 };
2323 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2324 Ok(root_place) => {
2325 self.add_used_mut(root_place, state);
2326 return false;
2327 }
2328 Err(place_err) => {
2329 error_access = AccessKind::MutableBorrow;
2330 the_place_err = place_err;
2331 }
2332 }
2333 }
2334 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2335 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2336 Ok(root_place) => {
2337 self.add_used_mut(root_place, state);
2338 return false;
2339 }
2340 Err(place_err) => {
2341 error_access = AccessKind::Mutate;
2342 the_place_err = place_err;
2343 }
2344 }
2345 }
2346
2347 Reservation(
2348 WriteKind::Move
2349 | WriteKind::Replace
2350 | WriteKind::StorageDeadOrDrop
2351 | WriteKind::MutableBorrow(BorrowKind::Shared)
2352 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2353 )
2354 | Write(
2355 WriteKind::Move
2356 | WriteKind::Replace
2357 | WriteKind::StorageDeadOrDrop
2358 | WriteKind::MutableBorrow(BorrowKind::Shared)
2359 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2360 ) => {
2361 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2362 && !self.has_buffered_diags()
2363 {
2364 self.dcx().span_delayed_bug(
2370 span,
2371 format!(
2372 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2373 ),
2374 );
2375 }
2376 return false;
2377 }
2378 Activation(..) => {
2379 return false;
2381 }
2382 Read(
2383 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2384 | ReadKind::Copy,
2385 ) => {
2386 return false;
2388 }
2389 }
2390
2391 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2396
2397 if let Some(init_index) = previously_initialized {
2399 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2400 let init = &self.move_data.inits[init_index];
2403 let assigned_span = init.span(self.body);
2404 self.report_illegal_reassignment((place, span), assigned_span, place);
2405 } else {
2406 self.report_mutability_error(place, span, the_place_err, error_access, location)
2407 }
2408 true
2409 } else {
2410 false
2411 }
2412 }
2413
2414 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2415 let mpi = self.move_data.rev_lookup.find_local(local)?;
2416 let ii = &self.move_data.init_path_map[mpi];
2417 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2418 }
2419
2420 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2422 match root_place {
2423 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2424 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2428 && self.is_local_ever_initialized(local, state).is_some()
2429 {
2430 self.used_mut.insert(local);
2431 }
2432 }
2433 RootPlace {
2434 place_local: _,
2435 place_projection: _,
2436 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2437 } => {}
2438 RootPlace {
2439 place_local,
2440 place_projection: place_projection @ [.., _],
2441 is_local_mutation_allowed: _,
2442 } => {
2443 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2444 local: place_local,
2445 projection: place_projection,
2446 }) {
2447 self.used_mut_upvars.push(field);
2448 }
2449 }
2450 }
2451 }
2452
2453 fn is_mutable(
2456 &self,
2457 place: PlaceRef<'tcx>,
2458 is_local_mutation_allowed: LocalMutationIsAllowed,
2459 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2460 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2461 match place.last_projection() {
2462 None => {
2463 let local = &self.body.local_decls[place.local];
2464 match local.mutability {
2465 Mutability::Not => match is_local_mutation_allowed {
2466 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2467 place_local: place.local,
2468 place_projection: place.projection,
2469 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2470 }),
2471 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2472 place_local: place.local,
2473 place_projection: place.projection,
2474 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2475 }),
2476 LocalMutationIsAllowed::No => Err(place),
2477 },
2478 Mutability::Mut => Ok(RootPlace {
2479 place_local: place.local,
2480 place_projection: place.projection,
2481 is_local_mutation_allowed,
2482 }),
2483 }
2484 }
2485 Some((place_base, elem)) => {
2486 match elem {
2487 ProjectionElem::Deref => {
2488 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2489
2490 match base_ty.kind() {
2492 ty::Ref(_, _, mutbl) => {
2493 match mutbl {
2494 hir::Mutability::Not => Err(place),
2496 hir::Mutability::Mut => {
2499 let mode = match self.is_upvar_field_projection(place) {
2500 Some(field)
2501 if self.upvars[field.index()].is_by_ref() =>
2502 {
2503 is_local_mutation_allowed
2504 }
2505 _ => LocalMutationIsAllowed::Yes,
2506 };
2507
2508 self.is_mutable(place_base, mode)
2509 }
2510 }
2511 }
2512 ty::RawPtr(_, mutbl) => {
2513 match mutbl {
2514 hir::Mutability::Not => Err(place),
2516 hir::Mutability::Mut => Ok(RootPlace {
2519 place_local: place.local,
2520 place_projection: place.projection,
2521 is_local_mutation_allowed,
2522 }),
2523 }
2524 }
2525 _ if base_ty.is_box() => {
2527 self.is_mutable(place_base, is_local_mutation_allowed)
2528 }
2529 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2531 }
2532 }
2533 ProjectionElem::Field(..)
2536 | ProjectionElem::Index(..)
2537 | ProjectionElem::ConstantIndex { .. }
2538 | ProjectionElem::Subslice { .. }
2539 | ProjectionElem::Subtype(..)
2540 | ProjectionElem::OpaqueCast { .. }
2541 | ProjectionElem::Downcast(..)
2542 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2543 let upvar_field_projection = self.is_upvar_field_projection(place);
2544 if let Some(field) = upvar_field_projection {
2545 let upvar = &self.upvars[field.index()];
2546 debug!(
2547 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2548 place={:?}, place_base={:?}",
2549 upvar, is_local_mutation_allowed, place, place_base
2550 );
2551 match (upvar.mutability, is_local_mutation_allowed) {
2552 (
2553 Mutability::Not,
2554 LocalMutationIsAllowed::No
2555 | LocalMutationIsAllowed::ExceptUpvars,
2556 ) => Err(place),
2557 (Mutability::Not, LocalMutationIsAllowed::Yes)
2558 | (Mutability::Mut, _) => {
2559 let _ =
2578 self.is_mutable(place_base, is_local_mutation_allowed)?;
2579 Ok(RootPlace {
2580 place_local: place.local,
2581 place_projection: place.projection,
2582 is_local_mutation_allowed,
2583 })
2584 }
2585 }
2586 } else {
2587 self.is_mutable(place_base, is_local_mutation_allowed)
2588 }
2589 }
2590 }
2591 }
2592 }
2593 }
2594
2595 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2600 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2601 }
2602
2603 fn dominators(&self) -> &Dominators<BasicBlock> {
2604 self.body.basic_blocks.dominators()
2606 }
2607
2608 fn lint_unused_mut(&self) {
2609 let tcx = self.infcx.tcx;
2610 let body = self.body;
2611 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2612 let local_decl = &body.local_decls[local];
2613 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2614 body.source_scopes[local_decl.source_info.scope].local_data
2615 else {
2616 continue;
2617 };
2618
2619 if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) {
2621 continue;
2622 }
2623
2624 let span = local_decl.source_info.span;
2625 if span.desugaring_kind().is_some() {
2626 continue;
2628 }
2629
2630 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2631
2632 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2633 }
2634 }
2635}
2636
2637enum Overlap {
2639 Arbitrary,
2645 EqualOrDisjoint,
2650 Disjoint,
2653}