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 nll;
82mod path_utils;
83mod place_ext;
84mod places_conflict;
85mod polonius;
86mod prefixes;
87mod region_infer;
88mod renumber;
89mod root_cx;
90mod session_diagnostics;
91mod type_check;
92mod universal_regions;
93mod used_muts;
94
95pub mod consumers;
97
98rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
99
100struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
102
103impl<'tcx> TyCtxtConsts<'tcx> {
104 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
105}
106
107pub fn provide(providers: &mut Providers) {
108 *providers = Providers { mir_borrowck, ..*providers };
109}
110
111fn mir_borrowck(
115 tcx: TyCtxt<'_>,
116 def: LocalDefId,
117) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
118 assert!(!tcx.is_typeck_child(def.to_def_id()));
119 let (input_body, _) = tcx.mir_promoted(def);
120 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
121
122 let input_body: &Body<'_> = &input_body.borrow();
123 if let Some(guar) = input_body.tainted_by_errors {
124 debug!("Skipping borrowck because of tainted body");
125 Err(guar)
126 } else if input_body.should_skip() {
127 debug!("Skipping borrowck because of injected body");
128 let opaque_types = ConcreteOpaqueTypes(Default::default());
129 Ok(tcx.arena.alloc(opaque_types))
130 } else {
131 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
132 let nested_bodies = tcx.nested_bodies_within(def);
136 for def_id in nested_bodies {
137 root_cx.get_or_insert_nested(def_id);
138 }
139
140 let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
141 do_mir_borrowck(&mut root_cx, def);
142 debug_assert!(closure_requirements.is_none());
143 debug_assert!(used_mut_upvars.is_empty());
144 root_cx.finalize()
145 }
146}
147
148#[derive(Debug)]
151struct PropagatedBorrowCheckResults<'tcx> {
152 closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
153 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
154}
155
156#[derive(Clone, Debug)]
199pub struct ClosureRegionRequirements<'tcx> {
200 pub num_external_vids: usize,
206
207 pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
210}
211
212#[derive(Copy, Clone, Debug)]
215pub struct ClosureOutlivesRequirement<'tcx> {
216 pub subject: ClosureOutlivesSubject<'tcx>,
218
219 pub outlived_free_region: ty::RegionVid,
221
222 pub blame_span: Span,
224
225 pub category: ConstraintCategory<'tcx>,
227}
228
229#[cfg(target_pointer_width = "64")]
231rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
232
233#[derive(Copy, Clone, Debug)]
236pub enum ClosureOutlivesSubject<'tcx> {
237 Ty(ClosureOutlivesSubjectTy<'tcx>),
241
242 Region(ty::RegionVid),
245}
246
247#[derive(Copy, Clone, Debug)]
253pub struct ClosureOutlivesSubjectTy<'tcx> {
254 inner: Ty<'tcx>,
255}
256impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
259impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
260
261impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
262 pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
265 let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
266 ty::ReVar(vid) => {
267 let br = ty::BoundRegion {
268 var: ty::BoundVar::from_usize(vid.index()),
269 kind: ty::BoundRegionKind::Anon,
270 };
271 ty::Region::new_bound(tcx, depth, br)
272 }
273 _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
274 });
275
276 Self { inner }
277 }
278
279 pub fn instantiate(
280 self,
281 tcx: TyCtxt<'tcx>,
282 mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
283 ) -> Ty<'tcx> {
284 fold_regions(tcx, self.inner, |r, depth| match r.kind() {
285 ty::ReBound(debruijn, br) => {
286 debug_assert_eq!(debruijn, depth);
287 map(ty::RegionVid::from_usize(br.var.index()))
288 }
289 _ => bug!("unexpected region {r:?}"),
290 })
291 }
292}
293
294#[instrument(skip(root_cx), level = "debug")]
298fn do_mir_borrowck<'tcx>(
299 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
300 def: LocalDefId,
301) -> PropagatedBorrowCheckResults<'tcx> {
302 let tcx = root_cx.tcx;
303 let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id());
304 let (input_body, promoted) = tcx.mir_promoted(def);
305 let input_body: &Body<'_> = &input_body.borrow();
306 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
307 if let Some(e) = input_body.tainted_by_errors {
308 infcx.set_tainted_by_errors(e);
309 root_cx.set_tainted_by_errors(e);
310 }
311
312 let mut body_owned = input_body.clone();
317 let mut promoted = input_promoted.to_owned();
318 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
319 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
322
323 let move_data = MoveData::gather_moves(body, tcx, |_| true);
324
325 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
326 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
327
328 let location_map = Rc::new(DenseLocationMap::new(body));
329
330 let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
331 || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
332 let mut polonius_facts =
333 (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
334
335 let MirTypeckResults {
337 mut constraints,
338 universal_region_relations,
339 region_bound_pairs,
340 known_type_outlives_obligations,
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 opaque_type_errors = region_infer::opaque_types::handle_opaque_type_uses(
356 root_cx,
357 &infcx,
358 &body,
359 &universal_region_relations,
360 ®ion_bound_pairs,
361 &known_type_outlives_obligations,
362 &location_map,
363 &mut constraints,
364 );
365
366 let nll::NllOutput {
369 regioncx,
370 polonius_input,
371 polonius_output,
372 opt_closure_req,
373 nll_errors,
374 polonius_diagnostics,
375 } = nll::compute_regions(
376 root_cx,
377 &infcx,
378 body,
379 &location_table,
380 &move_data,
381 &borrow_set,
382 location_map,
383 universal_region_relations,
384 constraints,
385 polonius_facts,
386 polonius_context,
387 );
388
389 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
392 polonius::dump_polonius_mir(
393 &infcx,
394 body,
395 ®ioncx,
396 &opt_closure_req,
397 &borrow_set,
398 polonius_diagnostics.as_ref(),
399 );
400
401 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
404
405 let movable_coroutine = body.coroutine.is_some()
406 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
407
408 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
409 for promoted_body in &promoted {
412 use rustc_middle::mir::visit::Visitor;
413 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
417 let mut promoted_mbcx = MirBorrowckCtxt {
418 root_cx,
419 infcx: &infcx,
420 body: promoted_body,
421 move_data: &move_data,
422 location_table: &location_table,
424 movable_coroutine,
425 fn_self_span_reported: Default::default(),
426 access_place_error_reported: Default::default(),
427 reservation_error_reported: Default::default(),
428 uninitialized_error_reported: Default::default(),
429 regioncx: ®ioncx,
430 used_mut: Default::default(),
431 used_mut_upvars: SmallVec::new(),
432 borrow_set: &borrow_set,
433 upvars: &[],
434 local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
435 region_names: RefCell::default(),
436 next_region_name: RefCell::new(1),
437 polonius_output: None,
438 move_errors: Vec::new(),
439 diags_buffer,
440 polonius_diagnostics: polonius_diagnostics.as_ref(),
441 };
442 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
443 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
444 }
445
446 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
447 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
448 if let Operand::Move(place) = operand {
449 self.ctxt.check_movable_place(location, *place);
450 }
451 }
452 }
453 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
454 promoted_mbcx.report_move_errors();
455 }
456
457 let mut mbcx = MirBorrowckCtxt {
458 root_cx,
459 infcx: &infcx,
460 body,
461 move_data: &move_data,
462 location_table: &location_table,
463 movable_coroutine,
464 fn_self_span_reported: Default::default(),
465 access_place_error_reported: Default::default(),
466 reservation_error_reported: Default::default(),
467 uninitialized_error_reported: Default::default(),
468 regioncx: ®ioncx,
469 used_mut: Default::default(),
470 used_mut_upvars: SmallVec::new(),
471 borrow_set: &borrow_set,
472 upvars: tcx.closure_captures(def),
473 local_names: OnceCell::new(),
474 region_names: RefCell::default(),
475 next_region_name: RefCell::new(1),
476 move_errors: Vec::new(),
477 diags_buffer,
478 polonius_output: polonius_output.as_deref(),
479 polonius_diagnostics: polonius_diagnostics.as_ref(),
480 };
481
482 if nll_errors.is_empty() {
484 mbcx.report_opaque_type_errors(opaque_type_errors);
485 } else {
486 mbcx.report_region_errors(nll_errors);
487 }
488
489 let (mut flow_analysis, flow_entry_states) =
490 get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
491 visit_results(
492 body,
493 traversal::reverse_postorder(body).map(|(bb, _)| bb),
494 &mut flow_analysis,
495 &flow_entry_states,
496 &mut mbcx,
497 );
498
499 mbcx.report_move_errors();
500
501 let temporary_used_locals: FxIndexSet<Local> = mbcx
507 .used_mut
508 .iter()
509 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
510 .cloned()
511 .collect();
512 let unused_mut_locals =
516 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
517 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
518
519 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
520 mbcx.lint_unused_mut();
521 if let Some(guar) = mbcx.emit_errors() {
522 mbcx.root_cx.set_tainted_by_errors(guar);
523 }
524
525 let result = PropagatedBorrowCheckResults {
526 closure_requirements: opt_closure_req,
527 used_mut_upvars: mbcx.used_mut_upvars,
528 };
529
530 if let Some(consumer) = &mut root_cx.consumer {
531 consumer.insert_body(
532 def,
533 BodyWithBorrowckFacts {
534 body: body_owned,
535 promoted,
536 borrow_set,
537 region_inference_context: regioncx,
538 location_table: polonius_input.as_ref().map(|_| location_table),
539 input_facts: polonius_input,
540 output_facts: polonius_output,
541 },
542 );
543 }
544
545 debug!("do_mir_borrowck: result = {:#?}", result);
546
547 result
548}
549
550fn get_flow_results<'a, 'tcx>(
551 tcx: TyCtxt<'tcx>,
552 body: &'a Body<'tcx>,
553 move_data: &'a MoveData<'tcx>,
554 borrow_set: &'a BorrowSet<'tcx>,
555 regioncx: &RegionInferenceContext<'tcx>,
556) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
557 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
560 tcx,
561 body,
562 Some("borrowck"),
563 );
564 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
565 tcx,
566 body,
567 Some("borrowck"),
568 );
569 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
570 tcx,
571 body,
572 Some("borrowck"),
573 );
574
575 let analysis = Borrowck {
576 borrows: borrows.analysis,
577 uninits: uninits.analysis,
578 ever_inits: ever_inits.analysis,
579 };
580
581 assert_eq!(borrows.results.len(), uninits.results.len());
582 assert_eq!(borrows.results.len(), ever_inits.results.len());
583 let results: Results<_> =
584 itertools::izip!(borrows.results, uninits.results, ever_inits.results)
585 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
586 .collect();
587
588 (analysis, results)
589}
590
591pub(crate) struct BorrowckInferCtxt<'tcx> {
592 pub(crate) infcx: InferCtxt<'tcx>,
593 pub(crate) root_def_id: LocalDefId,
594 pub(crate) param_env: ParamEnv<'tcx>,
595 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
596}
597
598impl<'tcx> BorrowckInferCtxt<'tcx> {
599 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self {
600 let typing_mode = if tcx.use_typing_mode_borrowck() {
601 TypingMode::borrowck(tcx, def_id)
602 } else {
603 TypingMode::analysis_in_body(tcx, def_id)
604 };
605 let infcx = tcx.infer_ctxt().build(typing_mode);
606 let param_env = tcx.param_env(def_id);
607 BorrowckInferCtxt {
608 infcx,
609 root_def_id,
610 reg_var_to_origin: RefCell::new(Default::default()),
611 param_env,
612 }
613 }
614
615 pub(crate) fn next_region_var<F>(
616 &self,
617 origin: RegionVariableOrigin,
618 get_ctxt_fn: F,
619 ) -> ty::Region<'tcx>
620 where
621 F: Fn() -> RegionCtxt,
622 {
623 let next_region = self.infcx.next_region_var(origin);
624 let vid = next_region.as_var();
625
626 if cfg!(debug_assertions) {
627 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
628 let ctxt = get_ctxt_fn();
629 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
630 assert_eq!(var_to_origin.insert(vid, ctxt), None);
631 }
632
633 next_region
634 }
635
636 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
637 pub(crate) fn next_nll_region_var<F>(
638 &self,
639 origin: NllRegionVariableOrigin,
640 get_ctxt_fn: F,
641 ) -> ty::Region<'tcx>
642 where
643 F: Fn() -> RegionCtxt,
644 {
645 let next_region = self.infcx.next_nll_region_var(origin);
646 let vid = next_region.as_var();
647
648 if cfg!(debug_assertions) {
649 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
650 let ctxt = get_ctxt_fn();
651 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
652 assert_eq!(var_to_origin.insert(vid, ctxt), None);
653 }
654
655 next_region
656 }
657}
658
659impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
660 type Target = InferCtxt<'tcx>;
661
662 fn deref(&self) -> &Self::Target {
663 &self.infcx
664 }
665}
666
667struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
668 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
669 infcx: &'infcx BorrowckInferCtxt<'tcx>,
670 body: &'a Body<'tcx>,
671 move_data: &'a MoveData<'tcx>,
672
673 location_table: &'a PoloniusLocationTable,
676
677 movable_coroutine: bool,
678 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
684 reservation_error_reported: FxIndexSet<Place<'tcx>>,
692 fn_self_span_reported: FxIndexSet<Span>,
696 uninitialized_error_reported: FxIndexSet<Local>,
699 used_mut: FxIndexSet<Local>,
702 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
705 regioncx: &'a RegionInferenceContext<'tcx>,
708
709 borrow_set: &'a BorrowSet<'tcx>,
711
712 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
714
715 local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
717
718 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
721
722 next_region_name: RefCell<usize>,
724
725 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
726 move_errors: Vec<MoveError<'tcx>>,
727
728 polonius_output: Option<&'a PoloniusOutput>,
730 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
732}
733
734impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
740 fn visit_after_early_statement_effect(
741 &mut self,
742 _analysis: &mut Borrowck<'a, 'tcx>,
743 state: &BorrowckDomain,
744 stmt: &Statement<'tcx>,
745 location: Location,
746 ) {
747 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
748 let span = stmt.source_info.span;
749
750 self.check_activations(location, span, state);
751
752 match &stmt.kind {
753 StatementKind::Assign(box (lhs, rhs)) => {
754 self.consume_rvalue(location, (rhs, span), state);
755
756 self.mutate_place(location, (*lhs, span), Shallow(None), state);
757 }
758 StatementKind::FakeRead(box (_, place)) => {
759 self.check_if_path_or_subpath_is_moved(
770 location,
771 InitializationRequiringAction::Use,
772 (place.as_ref(), span),
773 state,
774 );
775 }
776 StatementKind::Intrinsic(box kind) => match kind {
777 NonDivergingIntrinsic::Assume(op) => {
778 self.consume_operand(location, (op, span), state);
779 }
780 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
781 span,
782 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
783 )
784 }
785 StatementKind::AscribeUserType(..)
787 | StatementKind::PlaceMention(..)
789 | StatementKind::Coverage(..)
791 | StatementKind::ConstEvalCounter
793 | StatementKind::StorageLive(..) => {}
794 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
796 self.check_backward_incompatible_drop(location, **place, state);
797 }
798 StatementKind::StorageDead(local) => {
799 self.access_place(
800 location,
801 (Place::from(*local), span),
802 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
803 LocalMutationIsAllowed::Yes,
804 state,
805 );
806 }
807 StatementKind::Nop
808 | StatementKind::Retag { .. }
809 | StatementKind::Deinit(..)
810 | StatementKind::SetDiscriminant { .. } => {
811 bug!("Statement not allowed in this MIR phase")
812 }
813 }
814 }
815
816 fn visit_after_early_terminator_effect(
817 &mut self,
818 _analysis: &mut Borrowck<'a, 'tcx>,
819 state: &BorrowckDomain,
820 term: &Terminator<'tcx>,
821 loc: Location,
822 ) {
823 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
824 let span = term.source_info.span;
825
826 self.check_activations(loc, span, state);
827
828 match &term.kind {
829 TerminatorKind::SwitchInt { discr, targets: _ } => {
830 self.consume_operand(loc, (discr, span), state);
831 }
832 TerminatorKind::Drop {
833 place,
834 target: _,
835 unwind: _,
836 replace,
837 drop: _,
838 async_fut: _,
839 } => {
840 debug!(
841 "visit_terminator_drop \
842 loc: {:?} term: {:?} place: {:?} span: {:?}",
843 loc, term, place, span
844 );
845
846 let write_kind =
847 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
848 self.access_place(
849 loc,
850 (*place, span),
851 (AccessDepth::Drop, Write(write_kind)),
852 LocalMutationIsAllowed::Yes,
853 state,
854 );
855 }
856 TerminatorKind::Call {
857 func,
858 args,
859 destination,
860 target: _,
861 unwind: _,
862 call_source: _,
863 fn_span: _,
864 } => {
865 self.consume_operand(loc, (func, span), state);
866 for arg in args {
867 self.consume_operand(loc, (&arg.node, arg.span), state);
868 }
869 self.mutate_place(loc, (*destination, span), Deep, state);
870 }
871 TerminatorKind::TailCall { func, args, fn_span: _ } => {
872 self.consume_operand(loc, (func, span), state);
873 for arg in args {
874 self.consume_operand(loc, (&arg.node, arg.span), state);
875 }
876 }
877 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
878 self.consume_operand(loc, (cond, span), state);
879 if let AssertKind::BoundsCheck { len, index } = &**msg {
880 self.consume_operand(loc, (len, span), state);
881 self.consume_operand(loc, (index, span), state);
882 }
883 }
884
885 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
886 self.consume_operand(loc, (value, span), state);
887 self.mutate_place(loc, (*resume_arg, span), Deep, state);
888 }
889
890 TerminatorKind::InlineAsm {
891 asm_macro: _,
892 template: _,
893 operands,
894 options: _,
895 line_spans: _,
896 targets: _,
897 unwind: _,
898 } => {
899 for op in operands {
900 match op {
901 InlineAsmOperand::In { reg: _, value } => {
902 self.consume_operand(loc, (value, span), state);
903 }
904 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
905 if let Some(place) = place {
906 self.mutate_place(loc, (*place, span), Shallow(None), state);
907 }
908 }
909 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
910 self.consume_operand(loc, (in_value, span), state);
911 if let &Some(out_place) = out_place {
912 self.mutate_place(loc, (out_place, span), Shallow(None), state);
913 }
914 }
915 InlineAsmOperand::Const { value: _ }
916 | InlineAsmOperand::SymFn { value: _ }
917 | InlineAsmOperand::SymStatic { def_id: _ }
918 | InlineAsmOperand::Label { target_index: _ } => {}
919 }
920 }
921 }
922
923 TerminatorKind::Goto { target: _ }
924 | TerminatorKind::UnwindTerminate(_)
925 | TerminatorKind::Unreachable
926 | TerminatorKind::UnwindResume
927 | TerminatorKind::Return
928 | TerminatorKind::CoroutineDrop
929 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
930 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
931 }
933 }
934 }
935
936 fn visit_after_primary_terminator_effect(
937 &mut self,
938 _analysis: &mut Borrowck<'a, 'tcx>,
939 state: &BorrowckDomain,
940 term: &Terminator<'tcx>,
941 loc: Location,
942 ) {
943 let span = term.source_info.span;
944
945 match term.kind {
946 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
947 if self.movable_coroutine {
948 for i in state.borrows.iter() {
950 let borrow = &self.borrow_set[i];
951 self.check_for_local_borrow(borrow, span);
952 }
953 }
954 }
955
956 TerminatorKind::UnwindResume
957 | TerminatorKind::Return
958 | TerminatorKind::TailCall { .. }
959 | TerminatorKind::CoroutineDrop => {
960 match self.borrow_set.locals_state_at_exit() {
961 LocalsStateAtExit::AllAreInvalidated => {
962 for i in state.borrows.iter() {
967 let borrow = &self.borrow_set[i];
968 self.check_for_invalidation_at_exit(loc, borrow, span);
969 }
970 }
971 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
974 }
975 }
976
977 TerminatorKind::UnwindTerminate(_)
978 | TerminatorKind::Assert { .. }
979 | TerminatorKind::Call { .. }
980 | TerminatorKind::Drop { .. }
981 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
982 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
983 | TerminatorKind::Goto { .. }
984 | TerminatorKind::SwitchInt { .. }
985 | TerminatorKind::Unreachable
986 | TerminatorKind::InlineAsm { .. } => {}
987 }
988 }
989}
990
991use self::AccessDepth::{Deep, Shallow};
992use self::ReadOrWrite::{Activation, Read, Reservation, Write};
993
994#[derive(Copy, Clone, PartialEq, Eq, Debug)]
995enum ArtificialField {
996 ArrayLength,
997 FakeBorrow,
998}
999
1000#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1001enum AccessDepth {
1002 Shallow(Option<ArtificialField>),
1008
1009 Deep,
1013
1014 Drop,
1017}
1018
1019#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1022enum ReadOrWrite {
1023 Read(ReadKind),
1026
1027 Write(WriteKind),
1031
1032 Reservation(WriteKind),
1036 Activation(WriteKind, BorrowIndex),
1037}
1038
1039#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1042enum ReadKind {
1043 Borrow(BorrowKind),
1044 Copy,
1045}
1046
1047#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1050enum WriteKind {
1051 StorageDeadOrDrop,
1052 Replace,
1053 MutableBorrow(BorrowKind),
1054 Mutate,
1055 Move,
1056}
1057
1058#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1066enum LocalMutationIsAllowed {
1067 Yes,
1068 ExceptUpvars,
1071 No,
1072}
1073
1074#[derive(Copy, Clone, Debug)]
1075enum InitializationRequiringAction {
1076 Borrow,
1077 MatchOn,
1078 Use,
1079 Assignment,
1080 PartialAssignment,
1081}
1082
1083#[derive(Debug)]
1084struct RootPlace<'tcx> {
1085 place_local: Local,
1086 place_projection: &'tcx [PlaceElem<'tcx>],
1087 is_local_mutation_allowed: LocalMutationIsAllowed,
1088}
1089
1090impl InitializationRequiringAction {
1091 fn as_noun(self) -> &'static str {
1092 match self {
1093 InitializationRequiringAction::Borrow => "borrow",
1094 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1096 InitializationRequiringAction::Assignment => "assign",
1097 InitializationRequiringAction::PartialAssignment => "assign to part",
1098 }
1099 }
1100
1101 fn as_verb_in_past_tense(self) -> &'static str {
1102 match self {
1103 InitializationRequiringAction::Borrow => "borrowed",
1104 InitializationRequiringAction::MatchOn => "matched on",
1105 InitializationRequiringAction::Use => "used",
1106 InitializationRequiringAction::Assignment => "assigned",
1107 InitializationRequiringAction::PartialAssignment => "partially assigned",
1108 }
1109 }
1110
1111 fn as_general_verb_in_past_tense(self) -> &'static str {
1112 match self {
1113 InitializationRequiringAction::Borrow
1114 | InitializationRequiringAction::MatchOn
1115 | InitializationRequiringAction::Use => "used",
1116 InitializationRequiringAction::Assignment => "assigned",
1117 InitializationRequiringAction::PartialAssignment => "partially assigned",
1118 }
1119 }
1120}
1121
1122impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1123 fn body(&self) -> &'a Body<'tcx> {
1124 self.body
1125 }
1126
1127 fn access_place(
1134 &mut self,
1135 location: Location,
1136 place_span: (Place<'tcx>, Span),
1137 kind: (AccessDepth, ReadOrWrite),
1138 is_local_mutation_allowed: LocalMutationIsAllowed,
1139 state: &BorrowckDomain,
1140 ) {
1141 let (sd, rw) = kind;
1142
1143 if let Activation(_, borrow_index) = rw {
1144 if self.reservation_error_reported.contains(&place_span.0) {
1145 debug!(
1146 "skipping access_place for activation of invalid reservation \
1147 place: {:?} borrow_index: {:?}",
1148 place_span.0, borrow_index
1149 );
1150 return;
1151 }
1152 }
1153
1154 if !self.access_place_error_reported.is_empty()
1157 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1158 {
1159 debug!(
1160 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1161 place_span, kind
1162 );
1163 return;
1164 }
1165
1166 let mutability_error = self.check_access_permissions(
1167 place_span,
1168 rw,
1169 is_local_mutation_allowed,
1170 state,
1171 location,
1172 );
1173 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1174
1175 if conflict_error || mutability_error {
1176 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1177 self.access_place_error_reported.insert((place_span.0, place_span.1));
1178 }
1179 }
1180
1181 fn borrows_in_scope<'s>(
1182 &self,
1183 location: Location,
1184 state: &'s BorrowckDomain,
1185 ) -> Cow<'s, MixedBitSet<BorrowIndex>> {
1186 if let Some(polonius) = &self.polonius_output {
1187 let location = self.location_table.start_index(location);
1189 let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
1190 for &idx in polonius.errors_at(location) {
1191 polonius_output.insert(idx);
1192 }
1193 Cow::Owned(polonius_output)
1194 } else {
1195 Cow::Borrowed(&state.borrows)
1196 }
1197 }
1198
1199 #[instrument(level = "debug", skip(self, state))]
1200 fn check_access_for_conflict(
1201 &mut self,
1202 location: Location,
1203 place_span: (Place<'tcx>, Span),
1204 sd: AccessDepth,
1205 rw: ReadOrWrite,
1206 state: &BorrowckDomain,
1207 ) -> bool {
1208 let mut error_reported = false;
1209
1210 let borrows_in_scope = self.borrows_in_scope(location, state);
1211
1212 each_borrow_involving_path(
1213 self,
1214 self.infcx.tcx,
1215 self.body,
1216 (sd, place_span.0),
1217 self.borrow_set,
1218 |borrow_index| borrows_in_scope.contains(borrow_index),
1219 |this, borrow_index, borrow| match (rw, borrow.kind) {
1220 (Activation(_, activating), _) if activating == borrow_index => {
1227 debug!(
1228 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1229 skipping {:?} b/c activation of same borrow_index",
1230 place_span,
1231 sd,
1232 rw,
1233 (borrow_index, borrow),
1234 );
1235 ControlFlow::Continue(())
1236 }
1237
1238 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1239 | (
1240 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1241 BorrowKind::Mut { .. },
1242 ) => ControlFlow::Continue(()),
1243
1244 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1245 ControlFlow::Continue(())
1248 }
1249
1250 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1251 ControlFlow::Continue(())
1253 }
1254
1255 (Read(kind), BorrowKind::Mut { .. }) => {
1256 if !is_active(this.dominators(), borrow, location) {
1258 assert!(borrow.kind.allows_two_phase_borrow());
1259 return ControlFlow::Continue(());
1260 }
1261
1262 error_reported = true;
1263 match kind {
1264 ReadKind::Copy => {
1265 let err = this
1266 .report_use_while_mutably_borrowed(location, place_span, borrow);
1267 this.buffer_error(err);
1268 }
1269 ReadKind::Borrow(bk) => {
1270 let err =
1271 this.report_conflicting_borrow(location, place_span, bk, borrow);
1272 this.buffer_error(err);
1273 }
1274 }
1275 ControlFlow::Break(())
1276 }
1277
1278 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1279 match rw {
1280 Reservation(..) => {
1281 debug!(
1282 "recording invalid reservation of \
1283 place: {:?}",
1284 place_span.0
1285 );
1286 this.reservation_error_reported.insert(place_span.0);
1287 }
1288 Activation(_, activating) => {
1289 debug!(
1290 "observing check_place for activation of \
1291 borrow_index: {:?}",
1292 activating
1293 );
1294 }
1295 Read(..) | Write(..) => {}
1296 }
1297
1298 error_reported = true;
1299 match kind {
1300 WriteKind::MutableBorrow(bk) => {
1301 let err =
1302 this.report_conflicting_borrow(location, place_span, bk, borrow);
1303 this.buffer_error(err);
1304 }
1305 WriteKind::StorageDeadOrDrop => this
1306 .report_borrowed_value_does_not_live_long_enough(
1307 location,
1308 borrow,
1309 place_span,
1310 Some(WriteKind::StorageDeadOrDrop),
1311 ),
1312 WriteKind::Mutate => {
1313 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1314 }
1315 WriteKind::Move => {
1316 this.report_move_out_while_borrowed(location, place_span, borrow)
1317 }
1318 WriteKind::Replace => {
1319 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1320 }
1321 }
1322 ControlFlow::Break(())
1323 }
1324 },
1325 );
1326
1327 error_reported
1328 }
1329
1330 #[instrument(level = "debug", skip(self, state))]
1333 fn check_backward_incompatible_drop(
1334 &mut self,
1335 location: Location,
1336 place: Place<'tcx>,
1337 state: &BorrowckDomain,
1338 ) {
1339 let tcx = self.infcx.tcx;
1340 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1344 AccessDepth::Drop
1345 } else {
1346 AccessDepth::Shallow(None)
1347 };
1348
1349 let borrows_in_scope = self.borrows_in_scope(location, state);
1350
1351 each_borrow_involving_path(
1354 self,
1355 self.infcx.tcx,
1356 self.body,
1357 (sd, place),
1358 self.borrow_set,
1359 |borrow_index| borrows_in_scope.contains(borrow_index),
1360 |this, _borrow_index, borrow| {
1361 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1362 return ControlFlow::Continue(());
1363 }
1364 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1365 let explain = this.explain_why_borrow_contains_point(
1366 location,
1367 borrow,
1368 Some((WriteKind::StorageDeadOrDrop, place)),
1369 );
1370 this.infcx.tcx.node_span_lint(
1371 TAIL_EXPR_DROP_ORDER,
1372 CRATE_HIR_ID,
1373 borrowed,
1374 |diag| {
1375 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1376 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1377 },
1378 );
1379 ControlFlow::Break(())
1381 },
1382 );
1383 }
1384
1385 fn mutate_place(
1386 &mut self,
1387 location: Location,
1388 place_span: (Place<'tcx>, Span),
1389 kind: AccessDepth,
1390 state: &BorrowckDomain,
1391 ) {
1392 self.check_if_assigned_path_is_moved(location, place_span, state);
1394
1395 self.access_place(
1396 location,
1397 place_span,
1398 (kind, Write(WriteKind::Mutate)),
1399 LocalMutationIsAllowed::No,
1400 state,
1401 );
1402 }
1403
1404 fn consume_rvalue(
1405 &mut self,
1406 location: Location,
1407 (rvalue, span): (&Rvalue<'tcx>, Span),
1408 state: &BorrowckDomain,
1409 ) {
1410 match rvalue {
1411 &Rvalue::Ref(_ , bk, place) => {
1412 let access_kind = match bk {
1413 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1414 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1415 }
1416 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1417 (Deep, Read(ReadKind::Borrow(bk)))
1418 }
1419 BorrowKind::Mut { .. } => {
1420 let wk = WriteKind::MutableBorrow(bk);
1421 if bk.allows_two_phase_borrow() {
1422 (Deep, Reservation(wk))
1423 } else {
1424 (Deep, Write(wk))
1425 }
1426 }
1427 };
1428
1429 self.access_place(
1430 location,
1431 (place, span),
1432 access_kind,
1433 LocalMutationIsAllowed::No,
1434 state,
1435 );
1436
1437 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1438 InitializationRequiringAction::MatchOn
1439 } else {
1440 InitializationRequiringAction::Borrow
1441 };
1442
1443 self.check_if_path_or_subpath_is_moved(
1444 location,
1445 action,
1446 (place.as_ref(), span),
1447 state,
1448 );
1449 }
1450
1451 &Rvalue::RawPtr(kind, place) => {
1452 let access_kind = match kind {
1453 RawPtrKind::Mut => (
1454 Deep,
1455 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1456 kind: MutBorrowKind::Default,
1457 })),
1458 ),
1459 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1460 RawPtrKind::FakeForPtrMetadata => {
1461 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1462 }
1463 };
1464
1465 self.access_place(
1466 location,
1467 (place, span),
1468 access_kind,
1469 LocalMutationIsAllowed::No,
1470 state,
1471 );
1472
1473 self.check_if_path_or_subpath_is_moved(
1474 location,
1475 InitializationRequiringAction::Borrow,
1476 (place.as_ref(), span),
1477 state,
1478 );
1479 }
1480
1481 Rvalue::ThreadLocalRef(_) => {}
1482
1483 Rvalue::Use(operand)
1484 | Rvalue::Repeat(operand, _)
1485 | Rvalue::UnaryOp(_ , operand)
1486 | Rvalue::Cast(_ , operand, _ )
1487 | Rvalue::ShallowInitBox(operand, _ ) => {
1488 self.consume_operand(location, (operand, span), state)
1489 }
1490
1491 &Rvalue::CopyForDeref(place) => {
1492 self.access_place(
1493 location,
1494 (place, span),
1495 (Deep, Read(ReadKind::Copy)),
1496 LocalMutationIsAllowed::No,
1497 state,
1498 );
1499
1500 self.check_if_path_or_subpath_is_moved(
1502 location,
1503 InitializationRequiringAction::Use,
1504 (place.as_ref(), span),
1505 state,
1506 );
1507 }
1508
1509 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1510 let af = match *rvalue {
1511 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1512 Rvalue::Discriminant(..) => None,
1513 _ => unreachable!(),
1514 };
1515 self.access_place(
1516 location,
1517 (place, span),
1518 (Shallow(af), Read(ReadKind::Copy)),
1519 LocalMutationIsAllowed::No,
1520 state,
1521 );
1522 self.check_if_path_or_subpath_is_moved(
1523 location,
1524 InitializationRequiringAction::Use,
1525 (place.as_ref(), span),
1526 state,
1527 );
1528 }
1529
1530 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1531 self.consume_operand(location, (operand1, span), state);
1532 self.consume_operand(location, (operand2, span), state);
1533 }
1534
1535 Rvalue::NullaryOp(_op, _ty) => {
1536 }
1538
1539 Rvalue::Aggregate(aggregate_kind, operands) => {
1540 match **aggregate_kind {
1544 AggregateKind::Closure(def_id, _)
1545 | AggregateKind::CoroutineClosure(def_id, _)
1546 | AggregateKind::Coroutine(def_id, _) => {
1547 let def_id = def_id.expect_local();
1548 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1549 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1550 for field in used_mut_upvars.clone() {
1554 self.propagate_closure_used_mut_upvar(&operands[field]);
1555 }
1556 }
1557 AggregateKind::Adt(..)
1558 | AggregateKind::Array(..)
1559 | AggregateKind::Tuple { .. }
1560 | AggregateKind::RawPtr(..) => (),
1561 }
1562
1563 for operand in operands {
1564 self.consume_operand(location, (operand, span), state);
1565 }
1566 }
1567
1568 Rvalue::WrapUnsafeBinder(op, _) => {
1569 self.consume_operand(location, (op, span), state);
1570 }
1571 }
1572 }
1573
1574 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1575 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1576 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1584 this.used_mut_upvars.push(field);
1585 return;
1586 }
1587
1588 for (place_ref, proj) in place.iter_projections().rev() {
1589 if proj == ProjectionElem::Deref {
1591 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1592 ty::Ref(_, _, hir::Mutability::Mut) => return,
1594
1595 _ => {}
1596 }
1597 }
1598
1599 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1601 this.used_mut_upvars.push(field);
1602 return;
1603 }
1604 }
1605
1606 this.used_mut.insert(place.local);
1608 };
1609
1610 match *operand {
1614 Operand::Move(place) | Operand::Copy(place) => {
1615 match place.as_local() {
1616 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1617 if self.body.local_decls[local].ty.is_mutable_ptr() {
1618 return;
1620 }
1621 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1637 bug!("temporary should be tracked");
1638 };
1639 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1640 &self.move_data.inits[init_index]
1641 } else {
1642 bug!("temporary should be initialized exactly once")
1643 };
1644
1645 let InitLocation::Statement(loc) = init.location else {
1646 bug!("temporary initialized in arguments")
1647 };
1648
1649 let body = self.body;
1650 let bbd = &body[loc.block];
1651 let stmt = &bbd.statements[loc.statement_index];
1652 debug!("temporary assigned in: stmt={:?}", stmt);
1653
1654 match stmt.kind {
1655 StatementKind::Assign(box (
1656 _,
1657 Rvalue::Ref(_, _, source)
1658 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1659 )) => {
1660 propagate_closure_used_mut_place(self, source);
1661 }
1662 _ => {
1663 bug!(
1664 "closures should only capture user variables \
1665 or references to user variables"
1666 );
1667 }
1668 }
1669 }
1670 _ => propagate_closure_used_mut_place(self, place),
1671 }
1672 }
1673 Operand::Constant(..) => {}
1674 }
1675 }
1676
1677 fn consume_operand(
1678 &mut self,
1679 location: Location,
1680 (operand, span): (&Operand<'tcx>, Span),
1681 state: &BorrowckDomain,
1682 ) {
1683 match *operand {
1684 Operand::Copy(place) => {
1685 self.access_place(
1688 location,
1689 (place, span),
1690 (Deep, Read(ReadKind::Copy)),
1691 LocalMutationIsAllowed::No,
1692 state,
1693 );
1694
1695 self.check_if_path_or_subpath_is_moved(
1697 location,
1698 InitializationRequiringAction::Use,
1699 (place.as_ref(), span),
1700 state,
1701 );
1702 }
1703 Operand::Move(place) => {
1704 self.check_movable_place(location, place);
1706
1707 self.access_place(
1709 location,
1710 (place, span),
1711 (Deep, Write(WriteKind::Move)),
1712 LocalMutationIsAllowed::Yes,
1713 state,
1714 );
1715
1716 self.check_if_path_or_subpath_is_moved(
1718 location,
1719 InitializationRequiringAction::Use,
1720 (place.as_ref(), span),
1721 state,
1722 );
1723 }
1724 Operand::Constant(_) => {}
1725 }
1726 }
1727
1728 #[instrument(level = "debug", skip(self))]
1731 fn check_for_invalidation_at_exit(
1732 &mut self,
1733 location: Location,
1734 borrow: &BorrowData<'tcx>,
1735 span: Span,
1736 ) {
1737 let place = borrow.borrowed_place;
1738 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1739
1740 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1746 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1750 true
1751 } else {
1752 false
1753 };
1754
1755 let sd = if might_be_alive { Deep } else { Shallow(None) };
1756
1757 if places_conflict::borrow_conflicts_with_place(
1758 self.infcx.tcx,
1759 self.body,
1760 place,
1761 borrow.kind,
1762 root_place,
1763 sd,
1764 places_conflict::PlaceConflictBias::Overlap,
1765 ) {
1766 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1767 let span = self.infcx.tcx.sess.source_map().end_point(span);
1770 self.report_borrowed_value_does_not_live_long_enough(
1771 location,
1772 borrow,
1773 (place, span),
1774 None,
1775 )
1776 }
1777 }
1778
1779 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1782 debug!("check_for_local_borrow({:?})", borrow);
1783
1784 if borrow_of_local_data(borrow.borrowed_place) {
1785 let err = self.cannot_borrow_across_coroutine_yield(
1786 self.retrieve_borrow_spans(borrow).var_or_use(),
1787 yield_span,
1788 );
1789
1790 self.buffer_error(err);
1791 }
1792 }
1793
1794 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1795 for &borrow_index in self.borrow_set.activations_at_location(location) {
1799 let borrow = &self.borrow_set[borrow_index];
1800
1801 assert!(match borrow.kind {
1803 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1804 BorrowKind::Mut { .. } => true,
1805 });
1806
1807 self.access_place(
1808 location,
1809 (borrow.borrowed_place, span),
1810 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1811 LocalMutationIsAllowed::No,
1812 state,
1813 );
1814 }
1818 }
1819
1820 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1821 use IllegalMoveOriginKind::*;
1822
1823 let body = self.body;
1824 let tcx = self.infcx.tcx;
1825 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1826 for (place_ref, elem) in place.iter_projections() {
1827 match elem {
1828 ProjectionElem::Deref => match place_ty.ty.kind() {
1829 ty::Ref(..) | ty::RawPtr(..) => {
1830 self.move_errors.push(MoveError::new(
1831 place,
1832 location,
1833 BorrowedContent {
1834 target_place: place_ref.project_deeper(&[elem], tcx),
1835 },
1836 ));
1837 return;
1838 }
1839 ty::Adt(adt, _) => {
1840 if !adt.is_box() {
1841 bug!("Adt should be a box type when Place is deref");
1842 }
1843 }
1844 ty::Bool
1845 | ty::Char
1846 | ty::Int(_)
1847 | ty::Uint(_)
1848 | ty::Float(_)
1849 | ty::Foreign(_)
1850 | ty::Str
1851 | ty::Array(_, _)
1852 | ty::Pat(_, _)
1853 | ty::Slice(_)
1854 | ty::FnDef(_, _)
1855 | ty::FnPtr(..)
1856 | ty::Dynamic(_, _, _)
1857 | ty::Closure(_, _)
1858 | ty::CoroutineClosure(_, _)
1859 | ty::Coroutine(_, _)
1860 | ty::CoroutineWitness(..)
1861 | ty::Never
1862 | ty::Tuple(_)
1863 | ty::UnsafeBinder(_)
1864 | ty::Alias(_, _)
1865 | ty::Param(_)
1866 | ty::Bound(_, _)
1867 | ty::Infer(_)
1868 | ty::Error(_)
1869 | ty::Placeholder(_) => {
1870 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1871 }
1872 },
1873 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1874 ty::Adt(adt, _) => {
1875 if adt.has_dtor(tcx) {
1876 self.move_errors.push(MoveError::new(
1877 place,
1878 location,
1879 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1880 ));
1881 return;
1882 }
1883 }
1884 ty::Closure(..)
1885 | ty::CoroutineClosure(..)
1886 | ty::Coroutine(_, _)
1887 | ty::Tuple(_) => (),
1888 ty::Bool
1889 | ty::Char
1890 | ty::Int(_)
1891 | ty::Uint(_)
1892 | ty::Float(_)
1893 | ty::Foreign(_)
1894 | ty::Str
1895 | ty::Array(_, _)
1896 | ty::Pat(_, _)
1897 | ty::Slice(_)
1898 | ty::RawPtr(_, _)
1899 | ty::Ref(_, _, _)
1900 | ty::FnDef(_, _)
1901 | ty::FnPtr(..)
1902 | ty::Dynamic(_, _, _)
1903 | ty::CoroutineWitness(..)
1904 | ty::Never
1905 | ty::UnsafeBinder(_)
1906 | ty::Alias(_, _)
1907 | ty::Param(_)
1908 | ty::Bound(_, _)
1909 | ty::Infer(_)
1910 | ty::Error(_)
1911 | ty::Placeholder(_) => bug!(
1912 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1913 ),
1914 },
1915 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1916 match place_ty.ty.kind() {
1917 ty::Slice(_) => {
1918 self.move_errors.push(MoveError::new(
1919 place,
1920 location,
1921 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1922 ));
1923 return;
1924 }
1925 ty::Array(_, _) => (),
1926 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1927 }
1928 }
1929 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1930 ty::Array(..) | ty::Slice(..) => {
1931 self.move_errors.push(MoveError::new(
1932 place,
1933 location,
1934 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1935 ));
1936 return;
1937 }
1938 _ => bug!("Unexpected type {place_ty:#?}"),
1939 },
1940 ProjectionElem::OpaqueCast(_)
1945 | ProjectionElem::Subtype(_)
1946 | ProjectionElem::Downcast(_, _)
1947 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1948 }
1949
1950 place_ty = place_ty.projection_ty(tcx, elem);
1951 }
1952 }
1953
1954 fn check_if_full_path_is_moved(
1955 &mut self,
1956 location: Location,
1957 desired_action: InitializationRequiringAction,
1958 place_span: (PlaceRef<'tcx>, Span),
1959 state: &BorrowckDomain,
1960 ) {
1961 let maybe_uninits = &state.uninits;
1962
1963 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1999 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
2000 if maybe_uninits.contains(mpi) {
2001 self.report_use_of_moved_or_uninitialized(
2002 location,
2003 desired_action,
2004 (prefix, place_span.0, place_span.1),
2005 mpi,
2006 );
2007 } }
2014
2015 fn check_if_subslice_element_is_moved(
2021 &mut self,
2022 location: Location,
2023 desired_action: InitializationRequiringAction,
2024 place_span: (PlaceRef<'tcx>, Span),
2025 maybe_uninits: &MixedBitSet<MovePathIndex>,
2026 from: u64,
2027 to: u64,
2028 ) {
2029 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2030 let move_paths = &self.move_data.move_paths;
2031
2032 let root_path = &move_paths[mpi];
2033 for (child_mpi, child_move_path) in root_path.children(move_paths) {
2034 let last_proj = child_move_path.place.projection.last().unwrap();
2035 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
2036 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
2037
2038 if (from..to).contains(offset) {
2039 let uninit_child =
2040 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
2041 maybe_uninits.contains(mpi)
2042 });
2043
2044 if let Some(uninit_child) = uninit_child {
2045 self.report_use_of_moved_or_uninitialized(
2046 location,
2047 desired_action,
2048 (place_span.0, place_span.0, place_span.1),
2049 uninit_child,
2050 );
2051 return; }
2053 }
2054 }
2055 }
2056 }
2057 }
2058
2059 fn check_if_path_or_subpath_is_moved(
2060 &mut self,
2061 location: Location,
2062 desired_action: InitializationRequiringAction,
2063 place_span: (PlaceRef<'tcx>, Span),
2064 state: &BorrowckDomain,
2065 ) {
2066 let maybe_uninits = &state.uninits;
2067
2068 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2084
2085 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2086 place_span.0.last_projection()
2087 {
2088 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2089 if let ty::Array(..) = place_ty.ty.kind() {
2090 self.check_if_subslice_element_is_moved(
2091 location,
2092 desired_action,
2093 (place_base, place_span.1),
2094 maybe_uninits,
2095 from,
2096 to,
2097 );
2098 return;
2099 }
2100 }
2101
2102 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2112 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2113 let uninit_mpi = self
2114 .move_data
2115 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2116
2117 if let Some(uninit_mpi) = uninit_mpi {
2118 self.report_use_of_moved_or_uninitialized(
2119 location,
2120 desired_action,
2121 (place_span.0, place_span.0, place_span.1),
2122 uninit_mpi,
2123 );
2124 return; }
2126 }
2127 }
2128
2129 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2140 match self.move_data.rev_lookup.find(place) {
2141 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2142 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2143 }
2144 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2145 }
2146 }
2147
2148 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2149 match self.move_data.rev_lookup.find(place) {
2154 LookupResult::Parent(_) => None,
2155 LookupResult::Exact(mpi) => Some(mpi),
2156 }
2157 }
2158
2159 fn check_if_assigned_path_is_moved(
2160 &mut self,
2161 location: Location,
2162 (place, span): (Place<'tcx>, Span),
2163 state: &BorrowckDomain,
2164 ) {
2165 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2166
2167 for (place_base, elem) in place.iter_projections().rev() {
2169 match elem {
2170 ProjectionElem::Index(_) |
2171 ProjectionElem::Subtype(_) |
2172 ProjectionElem::OpaqueCast(_) |
2173 ProjectionElem::ConstantIndex { .. } |
2174 ProjectionElem::Downcast(_, _) =>
2176 { }
2180
2181 ProjectionElem::UnwrapUnsafeBinder(_) => {
2182 check_parent_of_field(self, location, place_base, span, state);
2183 }
2184
2185 ProjectionElem::Deref => {
2187 self.check_if_full_path_is_moved(
2188 location, InitializationRequiringAction::Use,
2189 (place_base, span), state);
2190 break;
2193 }
2194
2195 ProjectionElem::Subslice { .. } => {
2196 panic!("we don't allow assignments to subslices, location: {location:?}");
2197 }
2198
2199 ProjectionElem::Field(..) => {
2200 let tcx = self.infcx.tcx;
2204 let base_ty = place_base.ty(self.body(), tcx).ty;
2205 match base_ty.kind() {
2206 ty::Adt(def, _) if def.has_dtor(tcx) => {
2207 self.check_if_path_or_subpath_is_moved(
2208 location, InitializationRequiringAction::Assignment,
2209 (place_base, span), state);
2210
2211 break;
2214 }
2215
2216 ty::Adt(..) | ty::Tuple(..) => {
2219 check_parent_of_field(self, location, place_base, span, state);
2220 }
2221
2222 _ => {}
2223 }
2224 }
2225 }
2226 }
2227
2228 fn check_parent_of_field<'a, 'tcx>(
2229 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2230 location: Location,
2231 base: PlaceRef<'tcx>,
2232 span: Span,
2233 state: &BorrowckDomain,
2234 ) {
2235 let maybe_uninits = &state.uninits;
2267
2268 let mut shortest_uninit_seen = None;
2271 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2272 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2273
2274 if maybe_uninits.contains(mpi) {
2275 debug!(
2276 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2277 shortest_uninit_seen,
2278 Some((prefix, mpi))
2279 );
2280 shortest_uninit_seen = Some((prefix, mpi));
2281 } else {
2282 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2283 }
2284 }
2285
2286 if let Some((prefix, mpi)) = shortest_uninit_seen {
2287 let tcx = this.infcx.tcx;
2293 if base.ty(this.body(), tcx).ty.is_union()
2294 && this.move_data.path_map[mpi].iter().any(|moi| {
2295 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2296 })
2297 {
2298 return;
2299 }
2300
2301 this.report_use_of_moved_or_uninitialized(
2302 location,
2303 InitializationRequiringAction::PartialAssignment,
2304 (prefix, base, span),
2305 mpi,
2306 );
2307
2308 this.used_mut.insert(base.local);
2312 }
2313 }
2314 }
2315
2316 fn check_access_permissions(
2320 &mut self,
2321 (place, span): (Place<'tcx>, Span),
2322 kind: ReadOrWrite,
2323 is_local_mutation_allowed: LocalMutationIsAllowed,
2324 state: &BorrowckDomain,
2325 location: Location,
2326 ) -> bool {
2327 debug!(
2328 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2329 place, kind, is_local_mutation_allowed
2330 );
2331
2332 let error_access;
2333 let the_place_err;
2334
2335 match kind {
2336 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2337 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2338 let is_local_mutation_allowed = match mut_borrow_kind {
2339 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2343 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2344 is_local_mutation_allowed
2345 }
2346 };
2347 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2348 Ok(root_place) => {
2349 self.add_used_mut(root_place, state);
2350 return false;
2351 }
2352 Err(place_err) => {
2353 error_access = AccessKind::MutableBorrow;
2354 the_place_err = place_err;
2355 }
2356 }
2357 }
2358 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2359 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2360 Ok(root_place) => {
2361 self.add_used_mut(root_place, state);
2362 return false;
2363 }
2364 Err(place_err) => {
2365 error_access = AccessKind::Mutate;
2366 the_place_err = place_err;
2367 }
2368 }
2369 }
2370
2371 Reservation(
2372 WriteKind::Move
2373 | WriteKind::Replace
2374 | WriteKind::StorageDeadOrDrop
2375 | WriteKind::MutableBorrow(BorrowKind::Shared)
2376 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2377 )
2378 | Write(
2379 WriteKind::Move
2380 | WriteKind::Replace
2381 | WriteKind::StorageDeadOrDrop
2382 | WriteKind::MutableBorrow(BorrowKind::Shared)
2383 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2384 ) => {
2385 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2386 && !self.has_buffered_diags()
2387 {
2388 self.dcx().span_delayed_bug(
2394 span,
2395 format!(
2396 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2397 ),
2398 );
2399 }
2400 return false;
2401 }
2402 Activation(..) => {
2403 return false;
2405 }
2406 Read(
2407 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2408 | ReadKind::Copy,
2409 ) => {
2410 return false;
2412 }
2413 }
2414
2415 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2420
2421 if let Some(init_index) = previously_initialized {
2423 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2424 let init = &self.move_data.inits[init_index];
2427 let assigned_span = init.span(self.body);
2428 self.report_illegal_reassignment((place, span), assigned_span, place);
2429 } else {
2430 self.report_mutability_error(place, span, the_place_err, error_access, location)
2431 }
2432 true
2433 } else {
2434 false
2435 }
2436 }
2437
2438 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2439 let mpi = self.move_data.rev_lookup.find_local(local)?;
2440 let ii = &self.move_data.init_path_map[mpi];
2441 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2442 }
2443
2444 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2446 match root_place {
2447 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2448 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2452 && self.is_local_ever_initialized(local, state).is_some()
2453 {
2454 self.used_mut.insert(local);
2455 }
2456 }
2457 RootPlace {
2458 place_local: _,
2459 place_projection: _,
2460 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2461 } => {}
2462 RootPlace {
2463 place_local,
2464 place_projection: place_projection @ [.., _],
2465 is_local_mutation_allowed: _,
2466 } => {
2467 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2468 local: place_local,
2469 projection: place_projection,
2470 }) {
2471 self.used_mut_upvars.push(field);
2472 }
2473 }
2474 }
2475 }
2476
2477 fn is_mutable(
2480 &self,
2481 place: PlaceRef<'tcx>,
2482 is_local_mutation_allowed: LocalMutationIsAllowed,
2483 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2484 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2485 match place.last_projection() {
2486 None => {
2487 let local = &self.body.local_decls[place.local];
2488 match local.mutability {
2489 Mutability::Not => match is_local_mutation_allowed {
2490 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2491 place_local: place.local,
2492 place_projection: place.projection,
2493 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2494 }),
2495 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2496 place_local: place.local,
2497 place_projection: place.projection,
2498 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2499 }),
2500 LocalMutationIsAllowed::No => Err(place),
2501 },
2502 Mutability::Mut => Ok(RootPlace {
2503 place_local: place.local,
2504 place_projection: place.projection,
2505 is_local_mutation_allowed,
2506 }),
2507 }
2508 }
2509 Some((place_base, elem)) => {
2510 match elem {
2511 ProjectionElem::Deref => {
2512 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2513
2514 match base_ty.kind() {
2516 ty::Ref(_, _, mutbl) => {
2517 match mutbl {
2518 hir::Mutability::Not => Err(place),
2520 hir::Mutability::Mut => {
2523 let mode = match self.is_upvar_field_projection(place) {
2524 Some(field)
2525 if self.upvars[field.index()].is_by_ref() =>
2526 {
2527 is_local_mutation_allowed
2528 }
2529 _ => LocalMutationIsAllowed::Yes,
2530 };
2531
2532 self.is_mutable(place_base, mode)
2533 }
2534 }
2535 }
2536 ty::RawPtr(_, mutbl) => {
2537 match mutbl {
2538 hir::Mutability::Not => Err(place),
2540 hir::Mutability::Mut => Ok(RootPlace {
2543 place_local: place.local,
2544 place_projection: place.projection,
2545 is_local_mutation_allowed,
2546 }),
2547 }
2548 }
2549 _ if base_ty.is_box() => {
2551 self.is_mutable(place_base, is_local_mutation_allowed)
2552 }
2553 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2555 }
2556 }
2557 ProjectionElem::Field(..)
2560 | ProjectionElem::Index(..)
2561 | ProjectionElem::ConstantIndex { .. }
2562 | ProjectionElem::Subslice { .. }
2563 | ProjectionElem::Subtype(..)
2564 | ProjectionElem::OpaqueCast { .. }
2565 | ProjectionElem::Downcast(..)
2566 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2567 let upvar_field_projection = self.is_upvar_field_projection(place);
2568 if let Some(field) = upvar_field_projection {
2569 let upvar = &self.upvars[field.index()];
2570 debug!(
2571 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2572 place={:?}, place_base={:?}",
2573 upvar, is_local_mutation_allowed, place, place_base
2574 );
2575 match (upvar.mutability, is_local_mutation_allowed) {
2576 (
2577 Mutability::Not,
2578 LocalMutationIsAllowed::No
2579 | LocalMutationIsAllowed::ExceptUpvars,
2580 ) => Err(place),
2581 (Mutability::Not, LocalMutationIsAllowed::Yes)
2582 | (Mutability::Mut, _) => {
2583 let _ =
2602 self.is_mutable(place_base, is_local_mutation_allowed)?;
2603 Ok(RootPlace {
2604 place_local: place.local,
2605 place_projection: place.projection,
2606 is_local_mutation_allowed,
2607 })
2608 }
2609 }
2610 } else {
2611 self.is_mutable(place_base, is_local_mutation_allowed)
2612 }
2613 }
2614 }
2615 }
2616 }
2617 }
2618
2619 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2624 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2625 }
2626
2627 fn dominators(&self) -> &Dominators<BasicBlock> {
2628 self.body.basic_blocks.dominators()
2630 }
2631
2632 fn lint_unused_mut(&self) {
2633 let tcx = self.infcx.tcx;
2634 let body = self.body;
2635 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2636 let local_decl = &body.local_decls[local];
2637 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2638 body.source_scopes[local_decl.source_info.scope].local_data
2639 else {
2640 continue;
2641 };
2642
2643 if self.local_excluded_from_unused_mut_lint(local) {
2645 continue;
2646 }
2647
2648 let span = local_decl.source_info.span;
2649 if span.desugaring_kind().is_some() {
2650 continue;
2652 }
2653
2654 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2655
2656 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2657 }
2658 }
2659}
2660
2661enum Overlap {
2663 Arbitrary,
2669 EqualOrDisjoint,
2674 Disjoint,
2677}