1#![allow(internal_features)]
5#![doc(rust_logo)]
6#![feature(assert_matches)]
7#![feature(box_patterns)]
8#![feature(file_buffered)]
9#![feature(if_let_guard)]
10#![feature(negative_impls)]
11#![feature(never_type)]
12#![feature(rustc_attrs)]
13#![feature(rustdoc_internals)]
14#![feature(stmt_expr_attributes)]
15#![feature(try_blocks)]
16use std::borrow::Cow;
19use std::cell::{OnceCell, RefCell};
20use std::marker::PhantomData;
21use std::ops::{ControlFlow, Deref};
22use std::rc::Rc;
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::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::{EverInitializedPlaces, MaybeUninitializedPlaces};
45use rustc_mir_dataflow::move_paths::{
46 InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
47};
48use rustc_mir_dataflow::points::DenseLocationMap;
49use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
50use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
51use rustc_span::{ErrorGuaranteed, Span, Symbol};
52use smallvec::SmallVec;
53use tracing::{debug, instrument};
54
55use crate::borrow_set::{BorrowData, BorrowSet};
56use crate::consumers::BodyWithBorrowckFacts;
57use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
58use crate::diagnostics::{
59 AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
60};
61use crate::path_utils::*;
62use crate::place_ext::PlaceExt;
63use crate::places_conflict::{PlaceConflictBias, places_conflict};
64use crate::polonius::PoloniusDiagnosticsContext;
65use crate::polonius::legacy::{
66 PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
67};
68use crate::prefixes::PrefixSet;
69use crate::region_infer::RegionInferenceContext;
70use crate::renumber::RegionCtxt;
71use crate::session_diagnostics::VarNeedNotMut;
72use crate::type_check::MirTypeckResults;
73
74mod borrow_set;
75mod borrowck_errors;
76mod constraints;
77mod dataflow;
78mod def_use;
79mod diagnostics;
80mod handle_placeholders;
81mod member_constraints;
82mod nll;
83mod path_utils;
84mod place_ext;
85mod places_conflict;
86mod polonius;
87mod prefixes;
88mod region_infer;
89mod renumber;
90mod root_cx;
91mod session_diagnostics;
92mod type_check;
93mod universal_regions;
94mod used_muts;
95
96pub mod consumers;
98
99rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
100
101struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
103
104impl<'tcx> TyCtxtConsts<'tcx> {
105 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
106}
107
108pub fn provide(providers: &mut Providers) {
109 *providers = Providers { mir_borrowck, ..*providers };
110}
111
112fn mir_borrowck(
116 tcx: TyCtxt<'_>,
117 def: LocalDefId,
118) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
119 assert!(!tcx.is_typeck_child(def.to_def_id()));
120 let (input_body, _) = tcx.mir_promoted(def);
121 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
122
123 let input_body: &Body<'_> = &input_body.borrow();
124 if let Some(guar) = input_body.tainted_by_errors {
125 debug!("Skipping borrowck because of tainted body");
126 Err(guar)
127 } else if input_body.should_skip() {
128 debug!("Skipping borrowck because of injected body");
129 let opaque_types = ConcreteOpaqueTypes(Default::default());
130 Ok(tcx.arena.alloc(opaque_types))
131 } else {
132 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
133 let nested_bodies = tcx.nested_bodies_within(def);
137 for def_id in nested_bodies {
138 root_cx.get_or_insert_nested(def_id);
139 }
140
141 let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
142 do_mir_borrowck(&mut root_cx, def);
143 debug_assert!(closure_requirements.is_none());
144 debug_assert!(used_mut_upvars.is_empty());
145 root_cx.finalize()
146 }
147}
148
149#[derive(Debug)]
152struct PropagatedBorrowCheckResults<'tcx> {
153 closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
154 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
155}
156
157#[derive(Clone, Debug)]
200pub struct ClosureRegionRequirements<'tcx> {
201 pub num_external_vids: usize,
207
208 pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
211}
212
213#[derive(Copy, Clone, Debug)]
216pub struct ClosureOutlivesRequirement<'tcx> {
217 pub subject: ClosureOutlivesSubject<'tcx>,
219
220 pub outlived_free_region: ty::RegionVid,
222
223 pub blame_span: Span,
225
226 pub category: ConstraintCategory<'tcx>,
228}
229
230#[cfg(target_pointer_width = "64")]
232rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
233
234#[derive(Copy, Clone, Debug)]
237pub enum ClosureOutlivesSubject<'tcx> {
238 Ty(ClosureOutlivesSubjectTy<'tcx>),
242
243 Region(ty::RegionVid),
246}
247
248#[derive(Copy, Clone, Debug)]
254pub struct ClosureOutlivesSubjectTy<'tcx> {
255 inner: Ty<'tcx>,
256}
257impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
260impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
261
262impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
263 pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
266 let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
267 ty::ReVar(vid) => {
268 let br = ty::BoundRegion {
269 var: ty::BoundVar::from_usize(vid.index()),
270 kind: ty::BoundRegionKind::Anon,
271 };
272 ty::Region::new_bound(tcx, depth, br)
273 }
274 _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
275 });
276
277 Self { inner }
278 }
279
280 pub fn instantiate(
281 self,
282 tcx: TyCtxt<'tcx>,
283 mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
284 ) -> Ty<'tcx> {
285 fold_regions(tcx, self.inner, |r, depth| match r.kind() {
286 ty::ReBound(debruijn, br) => {
287 debug_assert_eq!(debruijn, depth);
288 map(ty::RegionVid::from_usize(br.var.index()))
289 }
290 _ => bug!("unexpected region {r:?}"),
291 })
292 }
293}
294
295#[instrument(skip(root_cx), level = "debug")]
299fn do_mir_borrowck<'tcx>(
300 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
301 def: LocalDefId,
302) -> PropagatedBorrowCheckResults<'tcx> {
303 let tcx = root_cx.tcx;
304 let infcx = BorrowckInferCtxt::new(tcx, def);
305 let (input_body, promoted) = tcx.mir_promoted(def);
306 let input_body: &Body<'_> = &input_body.borrow();
307 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
308 if let Some(e) = input_body.tainted_by_errors {
309 infcx.set_tainted_by_errors(e);
310 root_cx.set_tainted_by_errors(e);
311 }
312
313 let mut body_owned = input_body.clone();
318 let mut promoted = input_promoted.to_owned();
319 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
320 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
323
324 let move_data = MoveData::gather_moves(body, tcx, |_| true);
325
326 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
327 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
328
329 let location_map = Rc::new(DenseLocationMap::new(body));
330
331 let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
332 || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
333 let mut polonius_facts =
334 (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
335
336 let MirTypeckResults {
338 constraints,
339 universal_region_relations,
340 opaque_type_values,
341 polonius_context,
342 } = type_check::type_check(
343 root_cx,
344 &infcx,
345 body,
346 &promoted,
347 universal_regions,
348 &location_table,
349 &borrow_set,
350 &mut polonius_facts,
351 &move_data,
352 Rc::clone(&location_map),
353 );
354
355 let nll::NllOutput {
358 regioncx,
359 polonius_input,
360 polonius_output,
361 opt_closure_req,
362 nll_errors,
363 polonius_diagnostics,
364 } = nll::compute_regions(
365 root_cx,
366 &infcx,
367 body,
368 &location_table,
369 &move_data,
370 &borrow_set,
371 location_map,
372 universal_region_relations,
373 constraints,
374 polonius_facts,
375 polonius_context,
376 );
377
378 let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);
379
380 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
383 polonius::dump_polonius_mir(
384 &infcx,
385 body,
386 ®ioncx,
387 &opt_closure_req,
388 &borrow_set,
389 polonius_diagnostics.as_ref(),
390 );
391
392 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
395
396 let movable_coroutine = body.coroutine.is_some()
397 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
398
399 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
400 for promoted_body in &promoted {
403 use rustc_middle::mir::visit::Visitor;
404 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
408 let mut promoted_mbcx = MirBorrowckCtxt {
409 root_cx,
410 infcx: &infcx,
411 body: promoted_body,
412 move_data: &move_data,
413 location_table: &location_table,
415 movable_coroutine,
416 fn_self_span_reported: Default::default(),
417 access_place_error_reported: Default::default(),
418 reservation_error_reported: Default::default(),
419 uninitialized_error_reported: Default::default(),
420 regioncx: ®ioncx,
421 used_mut: Default::default(),
422 used_mut_upvars: SmallVec::new(),
423 borrow_set: &borrow_set,
424 upvars: &[],
425 local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
426 region_names: RefCell::default(),
427 next_region_name: RefCell::new(1),
428 polonius_output: None,
429 move_errors: Vec::new(),
430 diags_buffer,
431 polonius_diagnostics: polonius_diagnostics.as_ref(),
432 };
433 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
434 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
435 }
436
437 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
438 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
439 if let Operand::Move(place) = operand {
440 self.ctxt.check_movable_place(location, *place);
441 }
442 }
443 }
444 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
445 promoted_mbcx.report_move_errors();
446 }
447
448 let mut mbcx = MirBorrowckCtxt {
449 root_cx,
450 infcx: &infcx,
451 body,
452 move_data: &move_data,
453 location_table: &location_table,
454 movable_coroutine,
455 fn_self_span_reported: Default::default(),
456 access_place_error_reported: Default::default(),
457 reservation_error_reported: Default::default(),
458 uninitialized_error_reported: Default::default(),
459 regioncx: ®ioncx,
460 used_mut: Default::default(),
461 used_mut_upvars: SmallVec::new(),
462 borrow_set: &borrow_set,
463 upvars: tcx.closure_captures(def),
464 local_names: OnceCell::new(),
465 region_names: RefCell::default(),
466 next_region_name: RefCell::new(1),
467 move_errors: Vec::new(),
468 diags_buffer,
469 polonius_output: polonius_output.as_deref(),
470 polonius_diagnostics: polonius_diagnostics.as_ref(),
471 };
472
473 if nll_errors.is_empty() {
475 mbcx.report_opaque_type_errors(opaque_type_errors);
476 } else {
477 mbcx.report_region_errors(nll_errors);
478 }
479
480 let (mut flow_analysis, flow_entry_states) =
481 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
482 visit_results(
483 body,
484 traversal::reverse_postorder(body).map(|(bb, _)| bb),
485 &mut flow_analysis,
486 &flow_entry_states,
487 &mut mbcx,
488 );
489
490 mbcx.report_move_errors();
491
492 let temporary_used_locals: FxIndexSet<Local> = mbcx
498 .used_mut
499 .iter()
500 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
501 .cloned()
502 .collect();
503 let unused_mut_locals =
507 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
508 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
509
510 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
511 mbcx.lint_unused_mut();
512 if let Some(guar) = mbcx.emit_errors() {
513 mbcx.root_cx.set_tainted_by_errors(guar);
514 }
515
516 let result = PropagatedBorrowCheckResults {
517 closure_requirements: opt_closure_req,
518 used_mut_upvars: mbcx.used_mut_upvars,
519 };
520
521 if let Some(consumer) = &mut root_cx.consumer {
522 consumer.insert_body(
523 def,
524 BodyWithBorrowckFacts {
525 body: body_owned,
526 promoted,
527 borrow_set,
528 region_inference_context: regioncx,
529 location_table: polonius_input.as_ref().map(|_| location_table),
530 input_facts: polonius_input,
531 output_facts: polonius_output,
532 },
533 );
534 }
535
536 debug!("do_mir_borrowck: result = {:#?}", result);
537
538 result
539}
540
541fn get_flow_results<'a, 'tcx>(
542 tcx: TyCtxt<'tcx>,
543 body: &'a Body<'tcx>,
544 move_data: &'a MoveData<'tcx>,
545 borrow_set: &'a BorrowSet<'tcx>,
546 regioncx: &RegionInferenceContext<'tcx>,
547) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
548 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
551 tcx,
552 body,
553 Some("borrowck"),
554 );
555 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
556 tcx,
557 body,
558 Some("borrowck"),
559 );
560 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
561 tcx,
562 body,
563 Some("borrowck"),
564 );
565
566 let analysis = Borrowck {
567 borrows: borrows.analysis,
568 uninits: uninits.analysis,
569 ever_inits: ever_inits.analysis,
570 };
571
572 assert_eq!(borrows.results.len(), uninits.results.len());
573 assert_eq!(borrows.results.len(), ever_inits.results.len());
574 let results: Results<_> =
575 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
576 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
577 .collect();
578
579 (analysis, results)
580}
581
582pub(crate) struct BorrowckInferCtxt<'tcx> {
583 pub(crate) infcx: InferCtxt<'tcx>,
584 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
585 pub(crate) param_env: ParamEnv<'tcx>,
586}
587
588impl<'tcx> BorrowckInferCtxt<'tcx> {
589 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
590 let typing_mode = if tcx.use_typing_mode_borrowck() {
591 TypingMode::borrowck(tcx, def_id)
592 } else {
593 TypingMode::analysis_in_body(tcx, def_id)
594 };
595 let infcx = tcx.infer_ctxt().build(typing_mode);
596 let param_env = tcx.param_env(def_id);
597 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
598 }
599
600 pub(crate) fn next_region_var<F>(
601 &self,
602 origin: RegionVariableOrigin,
603 get_ctxt_fn: F,
604 ) -> ty::Region<'tcx>
605 where
606 F: Fn() -> RegionCtxt,
607 {
608 let next_region = self.infcx.next_region_var(origin);
609 let vid = next_region.as_var();
610
611 if cfg!(debug_assertions) {
612 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
613 let ctxt = get_ctxt_fn();
614 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
615 assert_eq!(var_to_origin.insert(vid, ctxt), None);
616 }
617
618 next_region
619 }
620
621 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
622 pub(crate) fn next_nll_region_var<F>(
623 &self,
624 origin: NllRegionVariableOrigin,
625 get_ctxt_fn: F,
626 ) -> ty::Region<'tcx>
627 where
628 F: Fn() -> RegionCtxt,
629 {
630 let next_region = self.infcx.next_nll_region_var(origin);
631 let vid = next_region.as_var();
632
633 if cfg!(debug_assertions) {
634 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
635 let ctxt = get_ctxt_fn();
636 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
637 assert_eq!(var_to_origin.insert(vid, ctxt), None);
638 }
639
640 next_region
641 }
642}
643
644impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
645 type Target = InferCtxt<'tcx>;
646
647 fn deref(&self) -> &Self::Target {
648 &self.infcx
649 }
650}
651
652struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
653 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
654 infcx: &'infcx BorrowckInferCtxt<'tcx>,
655 body: &'a Body<'tcx>,
656 move_data: &'a MoveData<'tcx>,
657
658 location_table: &'a PoloniusLocationTable,
661
662 movable_coroutine: bool,
663 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
669 reservation_error_reported: FxIndexSet<Place<'tcx>>,
677 fn_self_span_reported: FxIndexSet<Span>,
681 uninitialized_error_reported: FxIndexSet<Local>,
684 used_mut: FxIndexSet<Local>,
687 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
690 regioncx: &'a RegionInferenceContext<'tcx>,
693
694 borrow_set: &'a BorrowSet<'tcx>,
696
697 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
699
700 local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
702
703 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
706
707 next_region_name: RefCell<usize>,
709
710 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
711 move_errors: Vec<MoveError<'tcx>>,
712
713 polonius_output: Option<&'a PoloniusOutput>,
715 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
717}
718
719impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
725 fn visit_after_early_statement_effect(
726 &mut self,
727 _analysis: &mut Borrowck<'a, 'tcx>,
728 state: &BorrowckDomain,
729 stmt: &Statement<'tcx>,
730 location: Location,
731 ) {
732 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
733 let span = stmt.source_info.span;
734
735 self.check_activations(location, span, state);
736
737 match &stmt.kind {
738 StatementKind::Assign(box (lhs, rhs)) => {
739 self.consume_rvalue(location, (rhs, span), state);
740
741 self.mutate_place(location, (*lhs, span), Shallow(None), state);
742 }
743 StatementKind::FakeRead(box (_, place)) => {
744 self.check_if_path_or_subpath_is_moved(
755 location,
756 InitializationRequiringAction::Use,
757 (place.as_ref(), span),
758 state,
759 );
760 }
761 StatementKind::Intrinsic(box kind) => match kind {
762 NonDivergingIntrinsic::Assume(op) => {
763 self.consume_operand(location, (op, span), state);
764 }
765 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
766 span,
767 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
768 )
769 }
770 StatementKind::AscribeUserType(..)
772 | StatementKind::PlaceMention(..)
774 | StatementKind::Coverage(..)
776 | StatementKind::ConstEvalCounter
778 | StatementKind::StorageLive(..) => {}
779 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
781 self.check_backward_incompatible_drop(location, **place, state);
782 }
783 StatementKind::StorageDead(local) => {
784 self.access_place(
785 location,
786 (Place::from(*local), span),
787 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
788 LocalMutationIsAllowed::Yes,
789 state,
790 );
791 }
792 StatementKind::Nop
793 | StatementKind::Retag { .. }
794 | StatementKind::Deinit(..)
795 | StatementKind::SetDiscriminant { .. } => {
796 bug!("Statement not allowed in this MIR phase")
797 }
798 }
799 }
800
801 fn visit_after_early_terminator_effect(
802 &mut self,
803 _analysis: &mut Borrowck<'a, 'tcx>,
804 state: &BorrowckDomain,
805 term: &Terminator<'tcx>,
806 loc: Location,
807 ) {
808 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
809 let span = term.source_info.span;
810
811 self.check_activations(loc, span, state);
812
813 match &term.kind {
814 TerminatorKind::SwitchInt { discr, targets: _ } => {
815 self.consume_operand(loc, (discr, span), state);
816 }
817 TerminatorKind::Drop {
818 place,
819 target: _,
820 unwind: _,
821 replace,
822 drop: _,
823 async_fut: _,
824 } => {
825 debug!(
826 "visit_terminator_drop \
827 loc: {:?} term: {:?} place: {:?} span: {:?}",
828 loc, term, place, span
829 );
830
831 let write_kind =
832 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
833 self.access_place(
834 loc,
835 (*place, span),
836 (AccessDepth::Drop, Write(write_kind)),
837 LocalMutationIsAllowed::Yes,
838 state,
839 );
840 }
841 TerminatorKind::Call {
842 func,
843 args,
844 destination,
845 target: _,
846 unwind: _,
847 call_source: _,
848 fn_span: _,
849 } => {
850 self.consume_operand(loc, (func, span), state);
851 for arg in args {
852 self.consume_operand(loc, (&arg.node, arg.span), state);
853 }
854 self.mutate_place(loc, (*destination, span), Deep, state);
855 }
856 TerminatorKind::TailCall { func, args, fn_span: _ } => {
857 self.consume_operand(loc, (func, span), state);
858 for arg in args {
859 self.consume_operand(loc, (&arg.node, arg.span), state);
860 }
861 }
862 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
863 self.consume_operand(loc, (cond, span), state);
864 if let AssertKind::BoundsCheck { len, index } = &**msg {
865 self.consume_operand(loc, (len, span), state);
866 self.consume_operand(loc, (index, span), state);
867 }
868 }
869
870 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
871 self.consume_operand(loc, (value, span), state);
872 self.mutate_place(loc, (*resume_arg, span), Deep, state);
873 }
874
875 TerminatorKind::InlineAsm {
876 asm_macro: _,
877 template: _,
878 operands,
879 options: _,
880 line_spans: _,
881 targets: _,
882 unwind: _,
883 } => {
884 for op in operands {
885 match op {
886 InlineAsmOperand::In { reg: _, value } => {
887 self.consume_operand(loc, (value, span), state);
888 }
889 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
890 if let Some(place) = place {
891 self.mutate_place(loc, (*place, span), Shallow(None), state);
892 }
893 }
894 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
895 self.consume_operand(loc, (in_value, span), state);
896 if let &Some(out_place) = out_place {
897 self.mutate_place(loc, (out_place, span), Shallow(None), state);
898 }
899 }
900 InlineAsmOperand::Const { value: _ }
901 | InlineAsmOperand::SymFn { value: _ }
902 | InlineAsmOperand::SymStatic { def_id: _ }
903 | InlineAsmOperand::Label { target_index: _ } => {}
904 }
905 }
906 }
907
908 TerminatorKind::Goto { target: _ }
909 | TerminatorKind::UnwindTerminate(_)
910 | TerminatorKind::Unreachable
911 | TerminatorKind::UnwindResume
912 | TerminatorKind::Return
913 | TerminatorKind::CoroutineDrop
914 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
915 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
916 }
918 }
919 }
920
921 fn visit_after_primary_terminator_effect(
922 &mut self,
923 _analysis: &mut Borrowck<'a, 'tcx>,
924 state: &BorrowckDomain,
925 term: &Terminator<'tcx>,
926 loc: Location,
927 ) {
928 let span = term.source_info.span;
929
930 match term.kind {
931 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
932 if self.movable_coroutine {
933 for i in state.borrows.iter() {
935 let borrow = &self.borrow_set[i];
936 self.check_for_local_borrow(borrow, span);
937 }
938 }
939 }
940
941 TerminatorKind::UnwindResume
942 | TerminatorKind::Return
943 | TerminatorKind::TailCall { .. }
944 | TerminatorKind::CoroutineDrop => {
945 match self.borrow_set.locals_state_at_exit() {
946 LocalsStateAtExit::AllAreInvalidated => {
947 for i in state.borrows.iter() {
952 let borrow = &self.borrow_set[i];
953 self.check_for_invalidation_at_exit(loc, borrow, span);
954 }
955 }
956 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
959 }
960 }
961
962 TerminatorKind::UnwindTerminate(_)
963 | TerminatorKind::Assert { .. }
964 | TerminatorKind::Call { .. }
965 | TerminatorKind::Drop { .. }
966 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
967 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
968 | TerminatorKind::Goto { .. }
969 | TerminatorKind::SwitchInt { .. }
970 | TerminatorKind::Unreachable
971 | TerminatorKind::InlineAsm { .. } => {}
972 }
973 }
974}
975
976use self::AccessDepth::{Deep, Shallow};
977use self::ReadOrWrite::{Activation, Read, Reservation, Write};
978
979#[derive(Copy, Clone, PartialEq, Eq, Debug)]
980enum ArtificialField {
981 ArrayLength,
982 FakeBorrow,
983}
984
985#[derive(Copy, Clone, PartialEq, Eq, Debug)]
986enum AccessDepth {
987 Shallow(Option<ArtificialField>),
993
994 Deep,
998
999 Drop,
1002}
1003
1004#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1007enum ReadOrWrite {
1008 Read(ReadKind),
1011
1012 Write(WriteKind),
1016
1017 Reservation(WriteKind),
1021 Activation(WriteKind, BorrowIndex),
1022}
1023
1024#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1027enum ReadKind {
1028 Borrow(BorrowKind),
1029 Copy,
1030}
1031
1032#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1035enum WriteKind {
1036 StorageDeadOrDrop,
1037 Replace,
1038 MutableBorrow(BorrowKind),
1039 Mutate,
1040 Move,
1041}
1042
1043#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1051enum LocalMutationIsAllowed {
1052 Yes,
1053 ExceptUpvars,
1056 No,
1057}
1058
1059#[derive(Copy, Clone, Debug)]
1060enum InitializationRequiringAction {
1061 Borrow,
1062 MatchOn,
1063 Use,
1064 Assignment,
1065 PartialAssignment,
1066}
1067
1068#[derive(Debug)]
1069struct RootPlace<'tcx> {
1070 place_local: Local,
1071 place_projection: &'tcx [PlaceElem<'tcx>],
1072 is_local_mutation_allowed: LocalMutationIsAllowed,
1073}
1074
1075impl InitializationRequiringAction {
1076 fn as_noun(self) -> &'static str {
1077 match self {
1078 InitializationRequiringAction::Borrow => "borrow",
1079 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1081 InitializationRequiringAction::Assignment => "assign",
1082 InitializationRequiringAction::PartialAssignment => "assign to part",
1083 }
1084 }
1085
1086 fn as_verb_in_past_tense(self) -> &'static str {
1087 match self {
1088 InitializationRequiringAction::Borrow => "borrowed",
1089 InitializationRequiringAction::MatchOn => "matched on",
1090 InitializationRequiringAction::Use => "used",
1091 InitializationRequiringAction::Assignment => "assigned",
1092 InitializationRequiringAction::PartialAssignment => "partially assigned",
1093 }
1094 }
1095
1096 fn as_general_verb_in_past_tense(self) -> &'static str {
1097 match self {
1098 InitializationRequiringAction::Borrow
1099 | InitializationRequiringAction::MatchOn
1100 | InitializationRequiringAction::Use => "used",
1101 InitializationRequiringAction::Assignment => "assigned",
1102 InitializationRequiringAction::PartialAssignment => "partially assigned",
1103 }
1104 }
1105}
1106
1107impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1108 fn body(&self) -> &'a Body<'tcx> {
1109 self.body
1110 }
1111
1112 fn access_place(
1119 &mut self,
1120 location: Location,
1121 place_span: (Place<'tcx>, Span),
1122 kind: (AccessDepth, ReadOrWrite),
1123 is_local_mutation_allowed: LocalMutationIsAllowed,
1124 state: &BorrowckDomain,
1125 ) {
1126 let (sd, rw) = kind;
1127
1128 if let Activation(_, borrow_index) = rw {
1129 if self.reservation_error_reported.contains(&place_span.0) {
1130 debug!(
1131 "skipping access_place for activation of invalid reservation \
1132 place: {:?} borrow_index: {:?}",
1133 place_span.0, borrow_index
1134 );
1135 return;
1136 }
1137 }
1138
1139 if !self.access_place_error_reported.is_empty()
1142 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1143 {
1144 debug!(
1145 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1146 place_span, kind
1147 );
1148 return;
1149 }
1150
1151 let mutability_error = self.check_access_permissions(
1152 place_span,
1153 rw,
1154 is_local_mutation_allowed,
1155 state,
1156 location,
1157 );
1158 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1159
1160 if conflict_error || mutability_error {
1161 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1162 self.access_place_error_reported.insert((place_span.0, place_span.1));
1163 }
1164 }
1165
1166 fn borrows_in_scope<'s>(
1167 &self,
1168 location: Location,
1169 state: &'s BorrowckDomain,
1170 ) -> Cow<'s, MixedBitSet<BorrowIndex>> {
1171 if let Some(polonius) = &self.polonius_output {
1172 let location = self.location_table.start_index(location);
1174 let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
1175 for &idx in polonius.errors_at(location) {
1176 polonius_output.insert(idx);
1177 }
1178 Cow::Owned(polonius_output)
1179 } else {
1180 Cow::Borrowed(&state.borrows)
1181 }
1182 }
1183
1184 #[instrument(level = "debug", skip(self, state))]
1185 fn check_access_for_conflict(
1186 &mut self,
1187 location: Location,
1188 place_span: (Place<'tcx>, Span),
1189 sd: AccessDepth,
1190 rw: ReadOrWrite,
1191 state: &BorrowckDomain,
1192 ) -> bool {
1193 let mut error_reported = false;
1194
1195 let borrows_in_scope = self.borrows_in_scope(location, state);
1196
1197 each_borrow_involving_path(
1198 self,
1199 self.infcx.tcx,
1200 self.body,
1201 (sd, place_span.0),
1202 self.borrow_set,
1203 |borrow_index| borrows_in_scope.contains(borrow_index),
1204 |this, borrow_index, borrow| match (rw, borrow.kind) {
1205 (Activation(_, activating), _) if activating == borrow_index => {
1212 debug!(
1213 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1214 skipping {:?} b/c activation of same borrow_index",
1215 place_span,
1216 sd,
1217 rw,
1218 (borrow_index, borrow),
1219 );
1220 ControlFlow::Continue(())
1221 }
1222
1223 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1224 | (
1225 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1226 BorrowKind::Mut { .. },
1227 ) => ControlFlow::Continue(()),
1228
1229 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1230 ControlFlow::Continue(())
1233 }
1234
1235 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1236 ControlFlow::Continue(())
1238 }
1239
1240 (Read(kind), BorrowKind::Mut { .. }) => {
1241 if !is_active(this.dominators(), borrow, location) {
1243 assert!(borrow.kind.allows_two_phase_borrow());
1244 return ControlFlow::Continue(());
1245 }
1246
1247 error_reported = true;
1248 match kind {
1249 ReadKind::Copy => {
1250 let err = this
1251 .report_use_while_mutably_borrowed(location, place_span, borrow);
1252 this.buffer_error(err);
1253 }
1254 ReadKind::Borrow(bk) => {
1255 let err =
1256 this.report_conflicting_borrow(location, place_span, bk, borrow);
1257 this.buffer_error(err);
1258 }
1259 }
1260 ControlFlow::Break(())
1261 }
1262
1263 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1264 match rw {
1265 Reservation(..) => {
1266 debug!(
1267 "recording invalid reservation of \
1268 place: {:?}",
1269 place_span.0
1270 );
1271 this.reservation_error_reported.insert(place_span.0);
1272 }
1273 Activation(_, activating) => {
1274 debug!(
1275 "observing check_place for activation of \
1276 borrow_index: {:?}",
1277 activating
1278 );
1279 }
1280 Read(..) | Write(..) => {}
1281 }
1282
1283 error_reported = true;
1284 match kind {
1285 WriteKind::MutableBorrow(bk) => {
1286 let err =
1287 this.report_conflicting_borrow(location, place_span, bk, borrow);
1288 this.buffer_error(err);
1289 }
1290 WriteKind::StorageDeadOrDrop => this
1291 .report_borrowed_value_does_not_live_long_enough(
1292 location,
1293 borrow,
1294 place_span,
1295 Some(WriteKind::StorageDeadOrDrop),
1296 ),
1297 WriteKind::Mutate => {
1298 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1299 }
1300 WriteKind::Move => {
1301 this.report_move_out_while_borrowed(location, place_span, borrow)
1302 }
1303 WriteKind::Replace => {
1304 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1305 }
1306 }
1307 ControlFlow::Break(())
1308 }
1309 },
1310 );
1311
1312 error_reported
1313 }
1314
1315 #[instrument(level = "debug", skip(self, state))]
1318 fn check_backward_incompatible_drop(
1319 &mut self,
1320 location: Location,
1321 place: Place<'tcx>,
1322 state: &BorrowckDomain,
1323 ) {
1324 let tcx = self.infcx.tcx;
1325 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1329 AccessDepth::Drop
1330 } else {
1331 AccessDepth::Shallow(None)
1332 };
1333
1334 let borrows_in_scope = self.borrows_in_scope(location, state);
1335
1336 each_borrow_involving_path(
1339 self,
1340 self.infcx.tcx,
1341 self.body,
1342 (sd, place),
1343 self.borrow_set,
1344 |borrow_index| borrows_in_scope.contains(borrow_index),
1345 |this, _borrow_index, borrow| {
1346 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1347 return ControlFlow::Continue(());
1348 }
1349 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1350 let explain = this.explain_why_borrow_contains_point(
1351 location,
1352 borrow,
1353 Some((WriteKind::StorageDeadOrDrop, place)),
1354 );
1355 this.infcx.tcx.node_span_lint(
1356 TAIL_EXPR_DROP_ORDER,
1357 CRATE_HIR_ID,
1358 borrowed,
1359 |diag| {
1360 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1361 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1362 },
1363 );
1364 ControlFlow::Break(())
1366 },
1367 );
1368 }
1369
1370 fn mutate_place(
1371 &mut self,
1372 location: Location,
1373 place_span: (Place<'tcx>, Span),
1374 kind: AccessDepth,
1375 state: &BorrowckDomain,
1376 ) {
1377 self.check_if_assigned_path_is_moved(location, place_span, state);
1379
1380 self.access_place(
1381 location,
1382 place_span,
1383 (kind, Write(WriteKind::Mutate)),
1384 LocalMutationIsAllowed::No,
1385 state,
1386 );
1387 }
1388
1389 fn consume_rvalue(
1390 &mut self,
1391 location: Location,
1392 (rvalue, span): (&Rvalue<'tcx>, Span),
1393 state: &BorrowckDomain,
1394 ) {
1395 match rvalue {
1396 &Rvalue::Ref(_ , bk, place) => {
1397 let access_kind = match bk {
1398 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1399 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1400 }
1401 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1402 (Deep, Read(ReadKind::Borrow(bk)))
1403 }
1404 BorrowKind::Mut { .. } => {
1405 let wk = WriteKind::MutableBorrow(bk);
1406 if bk.allows_two_phase_borrow() {
1407 (Deep, Reservation(wk))
1408 } else {
1409 (Deep, Write(wk))
1410 }
1411 }
1412 };
1413
1414 self.access_place(
1415 location,
1416 (place, span),
1417 access_kind,
1418 LocalMutationIsAllowed::No,
1419 state,
1420 );
1421
1422 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1423 InitializationRequiringAction::MatchOn
1424 } else {
1425 InitializationRequiringAction::Borrow
1426 };
1427
1428 self.check_if_path_or_subpath_is_moved(
1429 location,
1430 action,
1431 (place.as_ref(), span),
1432 state,
1433 );
1434 }
1435
1436 &Rvalue::RawPtr(kind, place) => {
1437 let access_kind = match kind {
1438 RawPtrKind::Mut => (
1439 Deep,
1440 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1441 kind: MutBorrowKind::Default,
1442 })),
1443 ),
1444 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1445 RawPtrKind::FakeForPtrMetadata => {
1446 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1447 }
1448 };
1449
1450 self.access_place(
1451 location,
1452 (place, span),
1453 access_kind,
1454 LocalMutationIsAllowed::No,
1455 state,
1456 );
1457
1458 self.check_if_path_or_subpath_is_moved(
1459 location,
1460 InitializationRequiringAction::Borrow,
1461 (place.as_ref(), span),
1462 state,
1463 );
1464 }
1465
1466 Rvalue::ThreadLocalRef(_) => {}
1467
1468 Rvalue::Use(operand)
1469 | Rvalue::Repeat(operand, _)
1470 | Rvalue::UnaryOp(_ , operand)
1471 | Rvalue::Cast(_ , operand, _ )
1472 | Rvalue::ShallowInitBox(operand, _ ) => {
1473 self.consume_operand(location, (operand, span), state)
1474 }
1475
1476 &Rvalue::CopyForDeref(place) => {
1477 self.access_place(
1478 location,
1479 (place, span),
1480 (Deep, Read(ReadKind::Copy)),
1481 LocalMutationIsAllowed::No,
1482 state,
1483 );
1484
1485 self.check_if_path_or_subpath_is_moved(
1487 location,
1488 InitializationRequiringAction::Use,
1489 (place.as_ref(), span),
1490 state,
1491 );
1492 }
1493
1494 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1495 let af = match *rvalue {
1496 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1497 Rvalue::Discriminant(..) => None,
1498 _ => unreachable!(),
1499 };
1500 self.access_place(
1501 location,
1502 (place, span),
1503 (Shallow(af), Read(ReadKind::Copy)),
1504 LocalMutationIsAllowed::No,
1505 state,
1506 );
1507 self.check_if_path_or_subpath_is_moved(
1508 location,
1509 InitializationRequiringAction::Use,
1510 (place.as_ref(), span),
1511 state,
1512 );
1513 }
1514
1515 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1516 self.consume_operand(location, (operand1, span), state);
1517 self.consume_operand(location, (operand2, span), state);
1518 }
1519
1520 Rvalue::NullaryOp(_op, _ty) => {
1521 }
1523
1524 Rvalue::Aggregate(aggregate_kind, operands) => {
1525 match **aggregate_kind {
1529 AggregateKind::Closure(def_id, _)
1530 | AggregateKind::CoroutineClosure(def_id, _)
1531 | AggregateKind::Coroutine(def_id, _) => {
1532 let def_id = def_id.expect_local();
1533 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1534 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1535 for field in used_mut_upvars.clone() {
1539 self.propagate_closure_used_mut_upvar(&operands[field]);
1540 }
1541 }
1542 AggregateKind::Adt(..)
1543 | AggregateKind::Array(..)
1544 | AggregateKind::Tuple { .. }
1545 | AggregateKind::RawPtr(..) => (),
1546 }
1547
1548 for operand in operands {
1549 self.consume_operand(location, (operand, span), state);
1550 }
1551 }
1552
1553 Rvalue::WrapUnsafeBinder(op, _) => {
1554 self.consume_operand(location, (op, span), state);
1555 }
1556 }
1557 }
1558
1559 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1560 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1561 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1569 this.used_mut_upvars.push(field);
1570 return;
1571 }
1572
1573 for (place_ref, proj) in place.iter_projections().rev() {
1574 if proj == ProjectionElem::Deref {
1576 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1577 ty::Ref(_, _, hir::Mutability::Mut) => return,
1579
1580 _ => {}
1581 }
1582 }
1583
1584 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1586 this.used_mut_upvars.push(field);
1587 return;
1588 }
1589 }
1590
1591 this.used_mut.insert(place.local);
1593 };
1594
1595 match *operand {
1599 Operand::Move(place) | Operand::Copy(place) => {
1600 match place.as_local() {
1601 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1602 if self.body.local_decls[local].ty.is_mutable_ptr() {
1603 return;
1605 }
1606 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1622 bug!("temporary should be tracked");
1623 };
1624 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1625 &self.move_data.inits[init_index]
1626 } else {
1627 bug!("temporary should be initialized exactly once")
1628 };
1629
1630 let InitLocation::Statement(loc) = init.location else {
1631 bug!("temporary initialized in arguments")
1632 };
1633
1634 let body = self.body;
1635 let bbd = &body[loc.block];
1636 let stmt = &bbd.statements[loc.statement_index];
1637 debug!("temporary assigned in: stmt={:?}", stmt);
1638
1639 match stmt.kind {
1640 StatementKind::Assign(box (
1641 _,
1642 Rvalue::Ref(_, _, source)
1643 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1644 )) => {
1645 propagate_closure_used_mut_place(self, source);
1646 }
1647 _ => {
1648 bug!(
1649 "closures should only capture user variables \
1650 or references to user variables"
1651 );
1652 }
1653 }
1654 }
1655 _ => propagate_closure_used_mut_place(self, place),
1656 }
1657 }
1658 Operand::Constant(..) => {}
1659 }
1660 }
1661
1662 fn consume_operand(
1663 &mut self,
1664 location: Location,
1665 (operand, span): (&Operand<'tcx>, Span),
1666 state: &BorrowckDomain,
1667 ) {
1668 match *operand {
1669 Operand::Copy(place) => {
1670 self.access_place(
1673 location,
1674 (place, span),
1675 (Deep, Read(ReadKind::Copy)),
1676 LocalMutationIsAllowed::No,
1677 state,
1678 );
1679
1680 self.check_if_path_or_subpath_is_moved(
1682 location,
1683 InitializationRequiringAction::Use,
1684 (place.as_ref(), span),
1685 state,
1686 );
1687 }
1688 Operand::Move(place) => {
1689 self.check_movable_place(location, place);
1691
1692 self.access_place(
1694 location,
1695 (place, span),
1696 (Deep, Write(WriteKind::Move)),
1697 LocalMutationIsAllowed::Yes,
1698 state,
1699 );
1700
1701 self.check_if_path_or_subpath_is_moved(
1703 location,
1704 InitializationRequiringAction::Use,
1705 (place.as_ref(), span),
1706 state,
1707 );
1708 }
1709 Operand::Constant(_) => {}
1710 }
1711 }
1712
1713 #[instrument(level = "debug", skip(self))]
1716 fn check_for_invalidation_at_exit(
1717 &mut self,
1718 location: Location,
1719 borrow: &BorrowData<'tcx>,
1720 span: Span,
1721 ) {
1722 let place = borrow.borrowed_place;
1723 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1724
1725 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1731 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1735 true
1736 } else {
1737 false
1738 };
1739
1740 let sd = if might_be_alive { Deep } else { Shallow(None) };
1741
1742 if places_conflict::borrow_conflicts_with_place(
1743 self.infcx.tcx,
1744 self.body,
1745 place,
1746 borrow.kind,
1747 root_place,
1748 sd,
1749 places_conflict::PlaceConflictBias::Overlap,
1750 ) {
1751 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1752 let span = self.infcx.tcx.sess.source_map().end_point(span);
1755 self.report_borrowed_value_does_not_live_long_enough(
1756 location,
1757 borrow,
1758 (place, span),
1759 None,
1760 )
1761 }
1762 }
1763
1764 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1767 debug!("check_for_local_borrow({:?})", borrow);
1768
1769 if borrow_of_local_data(borrow.borrowed_place) {
1770 let err = self.cannot_borrow_across_coroutine_yield(
1771 self.retrieve_borrow_spans(borrow).var_or_use(),
1772 yield_span,
1773 );
1774
1775 self.buffer_error(err);
1776 }
1777 }
1778
1779 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1780 for &borrow_index in self.borrow_set.activations_at_location(location) {
1784 let borrow = &self.borrow_set[borrow_index];
1785
1786 assert!(match borrow.kind {
1788 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1789 BorrowKind::Mut { .. } => true,
1790 });
1791
1792 self.access_place(
1793 location,
1794 (borrow.borrowed_place, span),
1795 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1796 LocalMutationIsAllowed::No,
1797 state,
1798 );
1799 }
1803 }
1804
1805 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1806 use IllegalMoveOriginKind::*;
1807
1808 let body = self.body;
1809 let tcx = self.infcx.tcx;
1810 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1811 for (place_ref, elem) in place.iter_projections() {
1812 match elem {
1813 ProjectionElem::Deref => match place_ty.ty.kind() {
1814 ty::Ref(..) | ty::RawPtr(..) => {
1815 self.move_errors.push(MoveError::new(
1816 place,
1817 location,
1818 BorrowedContent {
1819 target_place: place_ref.project_deeper(&[elem], tcx),
1820 },
1821 ));
1822 return;
1823 }
1824 ty::Adt(adt, _) => {
1825 if !adt.is_box() {
1826 bug!("Adt should be a box type when Place is deref");
1827 }
1828 }
1829 ty::Bool
1830 | ty::Char
1831 | ty::Int(_)
1832 | ty::Uint(_)
1833 | ty::Float(_)
1834 | ty::Foreign(_)
1835 | ty::Str
1836 | ty::Array(_, _)
1837 | ty::Pat(_, _)
1838 | ty::Slice(_)
1839 | ty::FnDef(_, _)
1840 | ty::FnPtr(..)
1841 | ty::Dynamic(_, _, _)
1842 | ty::Closure(_, _)
1843 | ty::CoroutineClosure(_, _)
1844 | ty::Coroutine(_, _)
1845 | ty::CoroutineWitness(..)
1846 | ty::Never
1847 | ty::Tuple(_)
1848 | ty::UnsafeBinder(_)
1849 | ty::Alias(_, _)
1850 | ty::Param(_)
1851 | ty::Bound(_, _)
1852 | ty::Infer(_)
1853 | ty::Error(_)
1854 | ty::Placeholder(_) => {
1855 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1856 }
1857 },
1858 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1859 ty::Adt(adt, _) => {
1860 if adt.has_dtor(tcx) {
1861 self.move_errors.push(MoveError::new(
1862 place,
1863 location,
1864 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1865 ));
1866 return;
1867 }
1868 }
1869 ty::Closure(..)
1870 | ty::CoroutineClosure(..)
1871 | ty::Coroutine(_, _)
1872 | ty::Tuple(_) => (),
1873 ty::Bool
1874 | ty::Char
1875 | ty::Int(_)
1876 | ty::Uint(_)
1877 | ty::Float(_)
1878 | ty::Foreign(_)
1879 | ty::Str
1880 | ty::Array(_, _)
1881 | ty::Pat(_, _)
1882 | ty::Slice(_)
1883 | ty::RawPtr(_, _)
1884 | ty::Ref(_, _, _)
1885 | ty::FnDef(_, _)
1886 | ty::FnPtr(..)
1887 | ty::Dynamic(_, _, _)
1888 | ty::CoroutineWitness(..)
1889 | ty::Never
1890 | ty::UnsafeBinder(_)
1891 | ty::Alias(_, _)
1892 | ty::Param(_)
1893 | ty::Bound(_, _)
1894 | ty::Infer(_)
1895 | ty::Error(_)
1896 | ty::Placeholder(_) => bug!(
1897 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1898 ),
1899 },
1900 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1901 match place_ty.ty.kind() {
1902 ty::Slice(_) => {
1903 self.move_errors.push(MoveError::new(
1904 place,
1905 location,
1906 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1907 ));
1908 return;
1909 }
1910 ty::Array(_, _) => (),
1911 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1912 }
1913 }
1914 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1915 ty::Array(..) | ty::Slice(..) => {
1916 self.move_errors.push(MoveError::new(
1917 place,
1918 location,
1919 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1920 ));
1921 return;
1922 }
1923 _ => bug!("Unexpected type {place_ty:#?}"),
1924 },
1925 ProjectionElem::OpaqueCast(_)
1930 | ProjectionElem::Subtype(_)
1931 | ProjectionElem::Downcast(_, _)
1932 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1933 }
1934
1935 place_ty = place_ty.projection_ty(tcx, elem);
1936 }
1937 }
1938
1939 fn check_if_full_path_is_moved(
1940 &mut self,
1941 location: Location,
1942 desired_action: InitializationRequiringAction,
1943 place_span: (PlaceRef<'tcx>, Span),
1944 state: &BorrowckDomain,
1945 ) {
1946 let maybe_uninits = &state.uninits;
1947
1948 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1984 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1985 if maybe_uninits.contains(mpi) {
1986 self.report_use_of_moved_or_uninitialized(
1987 location,
1988 desired_action,
1989 (prefix, place_span.0, place_span.1),
1990 mpi,
1991 );
1992 } }
1999
2000 fn check_if_subslice_element_is_moved(
2006 &mut self,
2007 location: Location,
2008 desired_action: InitializationRequiringAction,
2009 place_span: (PlaceRef<'tcx>, Span),
2010 maybe_uninits: &MixedBitSet<MovePathIndex>,
2011 from: u64,
2012 to: u64,
2013 ) {
2014 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2015 let move_paths = &self.move_data.move_paths;
2016
2017 let root_path = &move_paths[mpi];
2018 for (child_mpi, child_move_path) in root_path.children(move_paths) {
2019 let last_proj = child_move_path.place.projection.last().unwrap();
2020 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
2021 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
2022
2023 if (from..to).contains(offset) {
2024 let uninit_child =
2025 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
2026 maybe_uninits.contains(mpi)
2027 });
2028
2029 if let Some(uninit_child) = uninit_child {
2030 self.report_use_of_moved_or_uninitialized(
2031 location,
2032 desired_action,
2033 (place_span.0, place_span.0, place_span.1),
2034 uninit_child,
2035 );
2036 return; }
2038 }
2039 }
2040 }
2041 }
2042 }
2043
2044 fn check_if_path_or_subpath_is_moved(
2045 &mut self,
2046 location: Location,
2047 desired_action: InitializationRequiringAction,
2048 place_span: (PlaceRef<'tcx>, Span),
2049 state: &BorrowckDomain,
2050 ) {
2051 let maybe_uninits = &state.uninits;
2052
2053 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2069
2070 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2071 place_span.0.last_projection()
2072 {
2073 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2074 if let ty::Array(..) = place_ty.ty.kind() {
2075 self.check_if_subslice_element_is_moved(
2076 location,
2077 desired_action,
2078 (place_base, place_span.1),
2079 maybe_uninits,
2080 from,
2081 to,
2082 );
2083 return;
2084 }
2085 }
2086
2087 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2097 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2098 let uninit_mpi = self
2099 .move_data
2100 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2101
2102 if let Some(uninit_mpi) = uninit_mpi {
2103 self.report_use_of_moved_or_uninitialized(
2104 location,
2105 desired_action,
2106 (place_span.0, place_span.0, place_span.1),
2107 uninit_mpi,
2108 );
2109 return; }
2111 }
2112 }
2113
2114 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2125 match self.move_data.rev_lookup.find(place) {
2126 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2127 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2128 }
2129 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2130 }
2131 }
2132
2133 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2134 match self.move_data.rev_lookup.find(place) {
2139 LookupResult::Parent(_) => None,
2140 LookupResult::Exact(mpi) => Some(mpi),
2141 }
2142 }
2143
2144 fn check_if_assigned_path_is_moved(
2145 &mut self,
2146 location: Location,
2147 (place, span): (Place<'tcx>, Span),
2148 state: &BorrowckDomain,
2149 ) {
2150 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2151
2152 for (place_base, elem) in place.iter_projections().rev() {
2154 match elem {
2155 ProjectionElem::Index(_) |
2156 ProjectionElem::Subtype(_) |
2157 ProjectionElem::OpaqueCast(_) |
2158 ProjectionElem::ConstantIndex { .. } |
2159 ProjectionElem::Downcast(_, _) =>
2161 { }
2165
2166 ProjectionElem::UnwrapUnsafeBinder(_) => {
2167 check_parent_of_field(self, location, place_base, span, state);
2168 }
2169
2170 ProjectionElem::Deref => {
2172 self.check_if_full_path_is_moved(
2173 location, InitializationRequiringAction::Use,
2174 (place_base, span), state);
2175 break;
2178 }
2179
2180 ProjectionElem::Subslice { .. } => {
2181 panic!("we don't allow assignments to subslices, location: {location:?}");
2182 }
2183
2184 ProjectionElem::Field(..) => {
2185 let tcx = self.infcx.tcx;
2189 let base_ty = place_base.ty(self.body(), tcx).ty;
2190 match base_ty.kind() {
2191 ty::Adt(def, _) if def.has_dtor(tcx) => {
2192 self.check_if_path_or_subpath_is_moved(
2193 location, InitializationRequiringAction::Assignment,
2194 (place_base, span), state);
2195
2196 break;
2199 }
2200
2201 ty::Adt(..) | ty::Tuple(..) => {
2204 check_parent_of_field(self, location, place_base, span, state);
2205 }
2206
2207 _ => {}
2208 }
2209 }
2210 }
2211 }
2212
2213 fn check_parent_of_field<'a, 'tcx>(
2214 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2215 location: Location,
2216 base: PlaceRef<'tcx>,
2217 span: Span,
2218 state: &BorrowckDomain,
2219 ) {
2220 let maybe_uninits = &state.uninits;
2252
2253 let mut shortest_uninit_seen = None;
2256 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2257 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2258
2259 if maybe_uninits.contains(mpi) {
2260 debug!(
2261 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2262 shortest_uninit_seen,
2263 Some((prefix, mpi))
2264 );
2265 shortest_uninit_seen = Some((prefix, mpi));
2266 } else {
2267 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2268 }
2269 }
2270
2271 if let Some((prefix, mpi)) = shortest_uninit_seen {
2272 let tcx = this.infcx.tcx;
2278 if base.ty(this.body(), tcx).ty.is_union()
2279 && this.move_data.path_map[mpi].iter().any(|moi| {
2280 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2281 })
2282 {
2283 return;
2284 }
2285
2286 this.report_use_of_moved_or_uninitialized(
2287 location,
2288 InitializationRequiringAction::PartialAssignment,
2289 (prefix, base, span),
2290 mpi,
2291 );
2292
2293 this.used_mut.insert(base.local);
2297 }
2298 }
2299 }
2300
2301 fn check_access_permissions(
2305 &mut self,
2306 (place, span): (Place<'tcx>, Span),
2307 kind: ReadOrWrite,
2308 is_local_mutation_allowed: LocalMutationIsAllowed,
2309 state: &BorrowckDomain,
2310 location: Location,
2311 ) -> bool {
2312 debug!(
2313 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2314 place, kind, is_local_mutation_allowed
2315 );
2316
2317 let error_access;
2318 let the_place_err;
2319
2320 match kind {
2321 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2322 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2323 let is_local_mutation_allowed = match mut_borrow_kind {
2324 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2328 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2329 is_local_mutation_allowed
2330 }
2331 };
2332 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2333 Ok(root_place) => {
2334 self.add_used_mut(root_place, state);
2335 return false;
2336 }
2337 Err(place_err) => {
2338 error_access = AccessKind::MutableBorrow;
2339 the_place_err = place_err;
2340 }
2341 }
2342 }
2343 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2344 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2345 Ok(root_place) => {
2346 self.add_used_mut(root_place, state);
2347 return false;
2348 }
2349 Err(place_err) => {
2350 error_access = AccessKind::Mutate;
2351 the_place_err = place_err;
2352 }
2353 }
2354 }
2355
2356 Reservation(
2357 WriteKind::Move
2358 | WriteKind::Replace
2359 | WriteKind::StorageDeadOrDrop
2360 | WriteKind::MutableBorrow(BorrowKind::Shared)
2361 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2362 )
2363 | Write(
2364 WriteKind::Move
2365 | WriteKind::Replace
2366 | WriteKind::StorageDeadOrDrop
2367 | WriteKind::MutableBorrow(BorrowKind::Shared)
2368 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2369 ) => {
2370 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2371 && !self.has_buffered_diags()
2372 {
2373 self.dcx().span_delayed_bug(
2379 span,
2380 format!(
2381 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2382 ),
2383 );
2384 }
2385 return false;
2386 }
2387 Activation(..) => {
2388 return false;
2390 }
2391 Read(
2392 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2393 | ReadKind::Copy,
2394 ) => {
2395 return false;
2397 }
2398 }
2399
2400 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2405
2406 if let Some(init_index) = previously_initialized {
2408 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2409 let init = &self.move_data.inits[init_index];
2412 let assigned_span = init.span(self.body);
2413 self.report_illegal_reassignment((place, span), assigned_span, place);
2414 } else {
2415 self.report_mutability_error(place, span, the_place_err, error_access, location)
2416 }
2417 true
2418 } else {
2419 false
2420 }
2421 }
2422
2423 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2424 let mpi = self.move_data.rev_lookup.find_local(local)?;
2425 let ii = &self.move_data.init_path_map[mpi];
2426 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2427 }
2428
2429 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2431 match root_place {
2432 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2433 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2437 && self.is_local_ever_initialized(local, state).is_some()
2438 {
2439 self.used_mut.insert(local);
2440 }
2441 }
2442 RootPlace {
2443 place_local: _,
2444 place_projection: _,
2445 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2446 } => {}
2447 RootPlace {
2448 place_local,
2449 place_projection: place_projection @ [.., _],
2450 is_local_mutation_allowed: _,
2451 } => {
2452 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2453 local: place_local,
2454 projection: place_projection,
2455 }) {
2456 self.used_mut_upvars.push(field);
2457 }
2458 }
2459 }
2460 }
2461
2462 fn is_mutable(
2465 &self,
2466 place: PlaceRef<'tcx>,
2467 is_local_mutation_allowed: LocalMutationIsAllowed,
2468 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2469 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2470 match place.last_projection() {
2471 None => {
2472 let local = &self.body.local_decls[place.local];
2473 match local.mutability {
2474 Mutability::Not => match is_local_mutation_allowed {
2475 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2476 place_local: place.local,
2477 place_projection: place.projection,
2478 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2479 }),
2480 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2481 place_local: place.local,
2482 place_projection: place.projection,
2483 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2484 }),
2485 LocalMutationIsAllowed::No => Err(place),
2486 },
2487 Mutability::Mut => Ok(RootPlace {
2488 place_local: place.local,
2489 place_projection: place.projection,
2490 is_local_mutation_allowed,
2491 }),
2492 }
2493 }
2494 Some((place_base, elem)) => {
2495 match elem {
2496 ProjectionElem::Deref => {
2497 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2498
2499 match base_ty.kind() {
2501 ty::Ref(_, _, mutbl) => {
2502 match mutbl {
2503 hir::Mutability::Not => Err(place),
2505 hir::Mutability::Mut => {
2508 let mode = match self.is_upvar_field_projection(place) {
2509 Some(field)
2510 if self.upvars[field.index()].is_by_ref() =>
2511 {
2512 is_local_mutation_allowed
2513 }
2514 _ => LocalMutationIsAllowed::Yes,
2515 };
2516
2517 self.is_mutable(place_base, mode)
2518 }
2519 }
2520 }
2521 ty::RawPtr(_, mutbl) => {
2522 match mutbl {
2523 hir::Mutability::Not => Err(place),
2525 hir::Mutability::Mut => Ok(RootPlace {
2528 place_local: place.local,
2529 place_projection: place.projection,
2530 is_local_mutation_allowed,
2531 }),
2532 }
2533 }
2534 _ if base_ty.is_box() => {
2536 self.is_mutable(place_base, is_local_mutation_allowed)
2537 }
2538 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2540 }
2541 }
2542 ProjectionElem::Field(..)
2545 | ProjectionElem::Index(..)
2546 | ProjectionElem::ConstantIndex { .. }
2547 | ProjectionElem::Subslice { .. }
2548 | ProjectionElem::Subtype(..)
2549 | ProjectionElem::OpaqueCast { .. }
2550 | ProjectionElem::Downcast(..)
2551 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2552 let upvar_field_projection = self.is_upvar_field_projection(place);
2553 if let Some(field) = upvar_field_projection {
2554 let upvar = &self.upvars[field.index()];
2555 debug!(
2556 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2557 place={:?}, place_base={:?}",
2558 upvar, is_local_mutation_allowed, place, place_base
2559 );
2560 match (upvar.mutability, is_local_mutation_allowed) {
2561 (
2562 Mutability::Not,
2563 LocalMutationIsAllowed::No
2564 | LocalMutationIsAllowed::ExceptUpvars,
2565 ) => Err(place),
2566 (Mutability::Not, LocalMutationIsAllowed::Yes)
2567 | (Mutability::Mut, _) => {
2568 let _ =
2587 self.is_mutable(place_base, is_local_mutation_allowed)?;
2588 Ok(RootPlace {
2589 place_local: place.local,
2590 place_projection: place.projection,
2591 is_local_mutation_allowed,
2592 })
2593 }
2594 }
2595 } else {
2596 self.is_mutable(place_base, is_local_mutation_allowed)
2597 }
2598 }
2599 }
2600 }
2601 }
2602 }
2603
2604 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2609 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2610 }
2611
2612 fn dominators(&self) -> &Dominators<BasicBlock> {
2613 self.body.basic_blocks.dominators()
2615 }
2616
2617 fn lint_unused_mut(&self) {
2618 let tcx = self.infcx.tcx;
2619 let body = self.body;
2620 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2621 let local_decl = &body.local_decls[local];
2622 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2623 body.source_scopes[local_decl.source_info.scope].local_data
2624 else {
2625 continue;
2626 };
2627
2628 if self.local_excluded_from_unused_mut_lint(local) {
2630 continue;
2631 }
2632
2633 let span = local_decl.source_info.span;
2634 if span.desugaring_kind().is_some() {
2635 continue;
2637 }
2638
2639 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2640
2641 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2642 }
2643 }
2644}
2645
2646enum Overlap {
2648 Arbitrary,
2654 EqualOrDisjoint,
2659 Disjoint,
2662}