1#![allow(internal_features)]
5#![feature(assert_matches)]
6#![feature(box_patterns)]
7#![feature(file_buffered)]
8#![feature(if_let_guard)]
9#![feature(negative_impls)]
10#![feature(never_type)]
11#![feature(rustc_attrs)]
12#![feature(stmt_expr_attributes)]
13#![feature(try_blocks)]
14use std::borrow::Cow;
17use std::cell::{OnceCell, RefCell};
18use std::marker::PhantomData;
19use std::ops::{ControlFlow, Deref};
20use std::rc::Rc;
21
22use borrow_set::LocalsStateAtExit;
23use polonius_engine::AllFacts;
24use root_cx::BorrowCheckRootCtxt;
25use rustc_abi::FieldIdx;
26use rustc_data_structures::frozen::Frozen;
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::outlives::env::RegionBoundPairs;
36use rustc_infer::infer::{
37 InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
38};
39use rustc_middle::mir::*;
40use rustc_middle::query::Providers;
41use rustc_middle::ty::{
42 self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions,
43};
44use rustc_middle::{bug, span_bug};
45use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
46use rustc_mir_dataflow::move_paths::{
47 InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
48};
49use rustc_mir_dataflow::points::DenseLocationMap;
50use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
51use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
52use rustc_span::{ErrorGuaranteed, Span, Symbol};
53use smallvec::SmallVec;
54use tracing::{debug, instrument};
55
56use crate::borrow_set::{BorrowData, BorrowSet};
57use crate::consumers::{BodyWithBorrowckFacts, RustcFacts};
58use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
59use crate::diagnostics::{
60 AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
61};
62use crate::path_utils::*;
63use crate::place_ext::PlaceExt;
64use crate::places_conflict::{PlaceConflictBias, places_conflict};
65use crate::polonius::legacy::{
66 PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
67};
68use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
69use crate::prefixes::PrefixSet;
70use crate::region_infer::RegionInferenceContext;
71use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
72use crate::renumber::RegionCtxt;
73use crate::session_diagnostics::VarNeedNotMut;
74use crate::type_check::free_region_relations::UniversalRegionRelations;
75use crate::type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults};
76
77mod borrow_set;
78mod borrowck_errors;
79mod constraints;
80mod dataflow;
81mod def_use;
82mod diagnostics;
83mod handle_placeholders;
84mod nll;
85mod path_utils;
86mod place_ext;
87mod places_conflict;
88mod polonius;
89mod prefixes;
90mod region_infer;
91mod renumber;
92mod root_cx;
93mod session_diagnostics;
94mod type_check;
95mod universal_regions;
96mod used_muts;
97
98pub mod consumers;
100
101rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
102
103struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
105
106impl<'tcx> TyCtxtConsts<'tcx> {
107 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
108}
109
110pub fn provide(providers: &mut Providers) {
111 *providers = Providers { mir_borrowck, ..*providers };
112}
113
114fn mir_borrowck(
118 tcx: TyCtxt<'_>,
119 def: LocalDefId,
120) -> Result<&FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'_>>, ErrorGuaranteed> {
121 assert!(!tcx.is_typeck_child(def.to_def_id()));
122 let (input_body, _) = tcx.mir_promoted(def);
123 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
124
125 let input_body: &Body<'_> = &input_body.borrow();
126 if let Some(guar) = input_body.tainted_by_errors {
127 debug!("Skipping borrowck because of tainted body");
128 Err(guar)
129 } else if input_body.should_skip() {
130 debug!("Skipping borrowck because of injected body");
131 let opaque_types = Default::default();
132 Ok(tcx.arena.alloc(opaque_types))
133 } else {
134 let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
135 root_cx.do_mir_borrowck();
136 root_cx.finalize()
137 }
138}
139
140#[derive(Debug)]
143struct PropagatedBorrowCheckResults<'tcx> {
144 closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
145 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
146}
147
148type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>;
149
150#[derive(Clone, Debug)]
193pub struct ClosureRegionRequirements<'tcx> {
194 pub num_external_vids: usize,
200
201 pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
204}
205
206#[derive(Copy, Clone, Debug)]
209pub struct ClosureOutlivesRequirement<'tcx> {
210 pub subject: ClosureOutlivesSubject<'tcx>,
212
213 pub outlived_free_region: ty::RegionVid,
215
216 pub blame_span: Span,
218
219 pub category: ConstraintCategory<'tcx>,
221}
222
223#[cfg(target_pointer_width = "64")]
225rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
226
227#[derive(Copy, Clone, Debug)]
230pub enum ClosureOutlivesSubject<'tcx> {
231 Ty(ClosureOutlivesSubjectTy<'tcx>),
235
236 Region(ty::RegionVid),
239}
240
241#[derive(Copy, Clone, Debug)]
247pub struct ClosureOutlivesSubjectTy<'tcx> {
248 inner: Ty<'tcx>,
249}
250impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
253impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
254
255impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
256 pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
259 let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
260 ty::ReVar(vid) => {
261 let br = ty::BoundRegion {
262 var: ty::BoundVar::from_usize(vid.index()),
263 kind: ty::BoundRegionKind::Anon,
264 };
265 ty::Region::new_bound(tcx, depth, br)
266 }
267 _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
268 });
269
270 Self { inner }
271 }
272
273 pub fn instantiate(
274 self,
275 tcx: TyCtxt<'tcx>,
276 mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
277 ) -> Ty<'tcx> {
278 fold_regions(tcx, self.inner, |r, depth| match r.kind() {
279 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) => {
280 debug_assert_eq!(debruijn, depth);
281 map(ty::RegionVid::from_usize(br.var.index()))
282 }
283 _ => bug!("unexpected region {r:?}"),
284 })
285 }
286}
287
288struct CollectRegionConstraintsResult<'tcx> {
289 infcx: BorrowckInferCtxt<'tcx>,
290 body_owned: Body<'tcx>,
291 promoted: IndexVec<Promoted, Body<'tcx>>,
292 move_data: MoveData<'tcx>,
293 borrow_set: BorrowSet<'tcx>,
294 location_table: PoloniusLocationTable,
295 location_map: Rc<DenseLocationMap>,
296 universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
297 region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
298 known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
299 constraints: MirTypeckRegionConstraints<'tcx>,
300 deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
301 deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>,
302 polonius_facts: Option<AllFacts<RustcFacts>>,
303 polonius_context: Option<PoloniusContext>,
304}
305
306fn borrowck_collect_region_constraints<'tcx>(
310 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
311 def: LocalDefId,
312) -> CollectRegionConstraintsResult<'tcx> {
313 let tcx = root_cx.tcx;
314 let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id());
315 let (input_body, promoted) = tcx.mir_promoted(def);
316 let input_body: &Body<'_> = &input_body.borrow();
317 let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
318 if let Some(e) = input_body.tainted_by_errors {
319 infcx.set_tainted_by_errors(e);
320 root_cx.set_tainted_by_errors(e);
321 }
322
323 let mut body_owned = input_body.clone();
328 let mut promoted = input_promoted.to_owned();
329 let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
330 let body = &body_owned; let location_table = PoloniusLocationTable::new(body);
333
334 let move_data = MoveData::gather_moves(body, tcx, |_| true);
335
336 let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
337 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
338
339 let location_map = Rc::new(DenseLocationMap::new(body));
340
341 let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
342 || infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
343 let mut polonius_facts =
344 (polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
345
346 let MirTypeckResults {
348 constraints,
349 universal_region_relations,
350 region_bound_pairs,
351 known_type_outlives_obligations,
352 deferred_closure_requirements,
353 polonius_context,
354 } = type_check::type_check(
355 root_cx,
356 &infcx,
357 body,
358 &promoted,
359 universal_regions,
360 &location_table,
361 &borrow_set,
362 &mut polonius_facts,
363 &move_data,
364 Rc::clone(&location_map),
365 );
366
367 CollectRegionConstraintsResult {
368 infcx,
369 body_owned,
370 promoted,
371 move_data,
372 borrow_set,
373 location_table,
374 location_map,
375 universal_region_relations,
376 region_bound_pairs,
377 known_type_outlives_obligations,
378 constraints,
379 deferred_closure_requirements,
380 deferred_opaque_type_errors: Default::default(),
381 polonius_facts,
382 polonius_context,
383 }
384}
385
386fn borrowck_check_region_constraints<'tcx>(
390 root_cx: &mut BorrowCheckRootCtxt<'tcx>,
391 CollectRegionConstraintsResult {
392 infcx,
393 body_owned,
394 promoted,
395 move_data,
396 borrow_set,
397 location_table,
398 location_map,
399 universal_region_relations,
400 region_bound_pairs: _,
401 known_type_outlives_obligations: _,
402 constraints,
403 deferred_closure_requirements,
404 deferred_opaque_type_errors,
405 polonius_facts,
406 polonius_context,
407 }: CollectRegionConstraintsResult<'tcx>,
408) -> PropagatedBorrowCheckResults<'tcx> {
409 assert!(!infcx.has_opaque_types_in_storage());
410 assert!(deferred_closure_requirements.is_empty());
411 let tcx = root_cx.tcx;
412 let body = &body_owned;
413 let def = body.source.def_id().expect_local();
414
415 let nll::NllOutput {
418 regioncx,
419 polonius_input,
420 polonius_output,
421 opt_closure_req,
422 nll_errors,
423 polonius_diagnostics,
424 } = nll::compute_regions(
425 root_cx,
426 &infcx,
427 body,
428 &location_table,
429 &move_data,
430 &borrow_set,
431 location_map,
432 universal_region_relations,
433 constraints,
434 polonius_facts,
435 polonius_context,
436 );
437
438 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
441 polonius::dump_polonius_mir(
442 &infcx,
443 body,
444 ®ioncx,
445 &opt_closure_req,
446 &borrow_set,
447 polonius_diagnostics.as_ref(),
448 );
449
450 nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
453
454 let movable_coroutine = body.coroutine.is_some()
455 && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
456
457 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
458 for promoted_body in &promoted {
461 use rustc_middle::mir::visit::Visitor;
462 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
466 let mut promoted_mbcx = MirBorrowckCtxt {
467 root_cx,
468 infcx: &infcx,
469 body: promoted_body,
470 move_data: &move_data,
471 location_table: &location_table,
473 movable_coroutine,
474 fn_self_span_reported: Default::default(),
475 access_place_error_reported: Default::default(),
476 reservation_error_reported: Default::default(),
477 uninitialized_error_reported: Default::default(),
478 regioncx: ®ioncx,
479 used_mut: Default::default(),
480 used_mut_upvars: SmallVec::new(),
481 borrow_set: &borrow_set,
482 upvars: &[],
483 local_names: OnceCell::from(IndexVec::from_elem(None, &promoted_body.local_decls)),
484 region_names: RefCell::default(),
485 next_region_name: RefCell::new(1),
486 polonius_output: None,
487 move_errors: Vec::new(),
488 diags_buffer,
489 polonius_diagnostics: polonius_diagnostics.as_ref(),
490 };
491 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
492 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
493 }
494
495 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
496 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
497 if let Operand::Move(place) = operand {
498 self.ctxt.check_movable_place(location, *place);
499 }
500 }
501 }
502 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
503 promoted_mbcx.report_move_errors();
504 }
505
506 let mut mbcx = MirBorrowckCtxt {
507 root_cx,
508 infcx: &infcx,
509 body,
510 move_data: &move_data,
511 location_table: &location_table,
512 movable_coroutine,
513 fn_self_span_reported: Default::default(),
514 access_place_error_reported: Default::default(),
515 reservation_error_reported: Default::default(),
516 uninitialized_error_reported: Default::default(),
517 regioncx: ®ioncx,
518 used_mut: Default::default(),
519 used_mut_upvars: SmallVec::new(),
520 borrow_set: &borrow_set,
521 upvars: tcx.closure_captures(def),
522 local_names: OnceCell::new(),
523 region_names: RefCell::default(),
524 next_region_name: RefCell::new(1),
525 move_errors: Vec::new(),
526 diags_buffer,
527 polonius_output: polonius_output.as_deref(),
528 polonius_diagnostics: polonius_diagnostics.as_ref(),
529 };
530
531 if nll_errors.is_empty() {
533 mbcx.report_opaque_type_errors(deferred_opaque_type_errors);
534 } else {
535 mbcx.report_region_errors(nll_errors);
536 }
537
538 let flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
539 visit_results(
540 body,
541 traversal::reverse_postorder(body).map(|(bb, _)| bb),
542 &flow_results,
543 &mut mbcx,
544 );
545
546 mbcx.report_move_errors();
547
548 let temporary_used_locals: FxIndexSet<Local> = mbcx
554 .used_mut
555 .iter()
556 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
557 .cloned()
558 .collect();
559 let unused_mut_locals =
563 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
564 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
565
566 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
567 mbcx.lint_unused_mut();
568 if let Some(guar) = mbcx.emit_errors() {
569 mbcx.root_cx.set_tainted_by_errors(guar);
570 }
571
572 let result = PropagatedBorrowCheckResults {
573 closure_requirements: opt_closure_req,
574 used_mut_upvars: mbcx.used_mut_upvars,
575 };
576
577 if let Some(consumer) = &mut root_cx.consumer {
578 consumer.insert_body(
579 def,
580 BodyWithBorrowckFacts {
581 body: body_owned,
582 promoted,
583 borrow_set,
584 region_inference_context: regioncx,
585 location_table: polonius_input.as_ref().map(|_| location_table),
586 input_facts: polonius_input,
587 output_facts: polonius_output,
588 },
589 );
590 }
591
592 debug!("do_mir_borrowck: result = {:#?}", result);
593
594 result
595}
596
597fn get_flow_results<'a, 'tcx>(
598 tcx: TyCtxt<'tcx>,
599 body: &'a Body<'tcx>,
600 move_data: &'a MoveData<'tcx>,
601 borrow_set: &'a BorrowSet<'tcx>,
602 regioncx: &RegionInferenceContext<'tcx>,
603) -> Results<'tcx, Borrowck<'a, 'tcx>> {
604 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
607 tcx,
608 body,
609 Some("borrowck"),
610 );
611 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
612 tcx,
613 body,
614 Some("borrowck"),
615 );
616 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
617 tcx,
618 body,
619 Some("borrowck"),
620 );
621
622 let analysis = Borrowck {
623 borrows: borrows.analysis,
624 uninits: uninits.analysis,
625 ever_inits: ever_inits.analysis,
626 };
627
628 assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
629 assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
630 let entry_states: EntryStates<_> =
631 itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
632 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
633 .collect();
634
635 Results { analysis, entry_states }
636}
637
638pub(crate) struct BorrowckInferCtxt<'tcx> {
639 pub(crate) infcx: InferCtxt<'tcx>,
640 pub(crate) root_def_id: LocalDefId,
641 pub(crate) param_env: ParamEnv<'tcx>,
642 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
643}
644
645impl<'tcx> BorrowckInferCtxt<'tcx> {
646 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self {
647 let typing_mode = if tcx.use_typing_mode_borrowck() {
648 TypingMode::borrowck(tcx, def_id)
649 } else {
650 TypingMode::analysis_in_body(tcx, def_id)
651 };
652 let infcx = tcx.infer_ctxt().build(typing_mode);
653 let param_env = tcx.param_env(def_id);
654 BorrowckInferCtxt {
655 infcx,
656 root_def_id,
657 reg_var_to_origin: RefCell::new(Default::default()),
658 param_env,
659 }
660 }
661
662 pub(crate) fn next_region_var<F>(
663 &self,
664 origin: RegionVariableOrigin,
665 get_ctxt_fn: F,
666 ) -> ty::Region<'tcx>
667 where
668 F: Fn() -> RegionCtxt,
669 {
670 let next_region = self.infcx.next_region_var(origin);
671 let vid = next_region.as_var();
672
673 if cfg!(debug_assertions) {
674 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
675 let ctxt = get_ctxt_fn();
676 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
677 assert_eq!(var_to_origin.insert(vid, ctxt), None);
678 }
679
680 next_region
681 }
682
683 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
684 pub(crate) fn next_nll_region_var<F>(
685 &self,
686 origin: NllRegionVariableOrigin,
687 get_ctxt_fn: F,
688 ) -> ty::Region<'tcx>
689 where
690 F: Fn() -> RegionCtxt,
691 {
692 let next_region = self.infcx.next_nll_region_var(origin);
693 let vid = next_region.as_var();
694
695 if cfg!(debug_assertions) {
696 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
697 let ctxt = get_ctxt_fn();
698 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
699 assert_eq!(var_to_origin.insert(vid, ctxt), None);
700 }
701
702 next_region
703 }
704}
705
706impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
707 type Target = InferCtxt<'tcx>;
708
709 fn deref(&self) -> &Self::Target {
710 &self.infcx
711 }
712}
713
714struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
715 root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
716 infcx: &'infcx BorrowckInferCtxt<'tcx>,
717 body: &'a Body<'tcx>,
718 move_data: &'a MoveData<'tcx>,
719
720 location_table: &'a PoloniusLocationTable,
723
724 movable_coroutine: bool,
725 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
731 reservation_error_reported: FxIndexSet<Place<'tcx>>,
739 fn_self_span_reported: FxIndexSet<Span>,
743 uninitialized_error_reported: FxIndexSet<Local>,
746 used_mut: FxIndexSet<Local>,
749 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
752 regioncx: &'a RegionInferenceContext<'tcx>,
755
756 borrow_set: &'a BorrowSet<'tcx>,
758
759 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
761
762 local_names: OnceCell<IndexVec<Local, Option<Symbol>>>,
764
765 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
768
769 next_region_name: RefCell<usize>,
771
772 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
773 move_errors: Vec<MoveError<'tcx>>,
774
775 polonius_output: Option<&'a PoloniusOutput>,
777 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
779}
780
781impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
787 fn visit_after_early_statement_effect(
788 &mut self,
789 _analysis: &Borrowck<'a, 'tcx>,
790 state: &BorrowckDomain,
791 stmt: &Statement<'tcx>,
792 location: Location,
793 ) {
794 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
795 let span = stmt.source_info.span;
796
797 self.check_activations(location, span, state);
798
799 match &stmt.kind {
800 StatementKind::Assign(box (lhs, rhs)) => {
801 self.consume_rvalue(location, (rhs, span), state);
802
803 self.mutate_place(location, (*lhs, span), Shallow(None), state);
804 }
805 StatementKind::FakeRead(box (_, place)) => {
806 self.check_if_path_or_subpath_is_moved(
817 location,
818 InitializationRequiringAction::Use,
819 (place.as_ref(), span),
820 state,
821 );
822 }
823 StatementKind::Intrinsic(box kind) => match kind {
824 NonDivergingIntrinsic::Assume(op) => {
825 self.consume_operand(location, (op, span), state);
826 }
827 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
828 span,
829 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
830 )
831 }
832 StatementKind::AscribeUserType(..)
834 | StatementKind::PlaceMention(..)
836 | StatementKind::Coverage(..)
838 | StatementKind::ConstEvalCounter
840 | StatementKind::StorageLive(..) => {}
841 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
843 self.check_backward_incompatible_drop(location, **place, state);
844 }
845 StatementKind::StorageDead(local) => {
846 self.access_place(
847 location,
848 (Place::from(*local), span),
849 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
850 LocalMutationIsAllowed::Yes,
851 state,
852 );
853 }
854 StatementKind::Nop
855 | StatementKind::Retag { .. }
856 | StatementKind::SetDiscriminant { .. } => {
857 bug!("Statement not allowed in this MIR phase")
858 }
859 }
860 }
861
862 fn visit_after_early_terminator_effect(
863 &mut self,
864 _analysis: &Borrowck<'a, 'tcx>,
865 state: &BorrowckDomain,
866 term: &Terminator<'tcx>,
867 loc: Location,
868 ) {
869 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
870 let span = term.source_info.span;
871
872 self.check_activations(loc, span, state);
873
874 match &term.kind {
875 TerminatorKind::SwitchInt { discr, targets: _ } => {
876 self.consume_operand(loc, (discr, span), state);
877 }
878 TerminatorKind::Drop {
879 place,
880 target: _,
881 unwind: _,
882 replace,
883 drop: _,
884 async_fut: _,
885 } => {
886 debug!(
887 "visit_terminator_drop \
888 loc: {:?} term: {:?} place: {:?} span: {:?}",
889 loc, term, place, span
890 );
891
892 let write_kind =
893 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
894 self.access_place(
895 loc,
896 (*place, span),
897 (AccessDepth::Drop, Write(write_kind)),
898 LocalMutationIsAllowed::Yes,
899 state,
900 );
901 }
902 TerminatorKind::Call {
903 func,
904 args,
905 destination,
906 target: _,
907 unwind: _,
908 call_source: _,
909 fn_span: _,
910 } => {
911 self.consume_operand(loc, (func, span), state);
912 for arg in args {
913 self.consume_operand(loc, (&arg.node, arg.span), state);
914 }
915 self.mutate_place(loc, (*destination, span), Deep, state);
916 }
917 TerminatorKind::TailCall { func, args, fn_span: _ } => {
918 self.consume_operand(loc, (func, span), state);
919 for arg in args {
920 self.consume_operand(loc, (&arg.node, arg.span), state);
921 }
922 }
923 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
924 self.consume_operand(loc, (cond, span), state);
925 if let AssertKind::BoundsCheck { len, index } = &**msg {
926 self.consume_operand(loc, (len, span), state);
927 self.consume_operand(loc, (index, span), state);
928 }
929 }
930
931 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
932 self.consume_operand(loc, (value, span), state);
933 self.mutate_place(loc, (*resume_arg, span), Deep, state);
934 }
935
936 TerminatorKind::InlineAsm {
937 asm_macro: _,
938 template: _,
939 operands,
940 options: _,
941 line_spans: _,
942 targets: _,
943 unwind: _,
944 } => {
945 for op in operands {
946 match op {
947 InlineAsmOperand::In { reg: _, value } => {
948 self.consume_operand(loc, (value, span), state);
949 }
950 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
951 if let Some(place) = place {
952 self.mutate_place(loc, (*place, span), Shallow(None), state);
953 }
954 }
955 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
956 self.consume_operand(loc, (in_value, span), state);
957 if let &Some(out_place) = out_place {
958 self.mutate_place(loc, (out_place, span), Shallow(None), state);
959 }
960 }
961 InlineAsmOperand::Const { value: _ }
962 | InlineAsmOperand::SymFn { value: _ }
963 | InlineAsmOperand::SymStatic { def_id: _ }
964 | InlineAsmOperand::Label { target_index: _ } => {}
965 }
966 }
967 }
968
969 TerminatorKind::Goto { target: _ }
970 | TerminatorKind::UnwindTerminate(_)
971 | TerminatorKind::Unreachable
972 | TerminatorKind::UnwindResume
973 | TerminatorKind::Return
974 | TerminatorKind::CoroutineDrop
975 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
976 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
977 }
979 }
980 }
981
982 fn visit_after_primary_terminator_effect(
983 &mut self,
984 _analysis: &Borrowck<'a, 'tcx>,
985 state: &BorrowckDomain,
986 term: &Terminator<'tcx>,
987 loc: Location,
988 ) {
989 let span = term.source_info.span;
990
991 match term.kind {
992 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
993 if self.movable_coroutine {
994 for i in state.borrows.iter() {
996 let borrow = &self.borrow_set[i];
997 self.check_for_local_borrow(borrow, span);
998 }
999 }
1000 }
1001
1002 TerminatorKind::UnwindResume
1003 | TerminatorKind::Return
1004 | TerminatorKind::TailCall { .. }
1005 | TerminatorKind::CoroutineDrop => {
1006 match self.borrow_set.locals_state_at_exit() {
1007 LocalsStateAtExit::AllAreInvalidated => {
1008 for i in state.borrows.iter() {
1013 let borrow = &self.borrow_set[i];
1014 self.check_for_invalidation_at_exit(loc, borrow, span);
1015 }
1016 }
1017 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
1020 }
1021 }
1022
1023 TerminatorKind::UnwindTerminate(_)
1024 | TerminatorKind::Assert { .. }
1025 | TerminatorKind::Call { .. }
1026 | TerminatorKind::Drop { .. }
1027 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
1028 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
1029 | TerminatorKind::Goto { .. }
1030 | TerminatorKind::SwitchInt { .. }
1031 | TerminatorKind::Unreachable
1032 | TerminatorKind::InlineAsm { .. } => {}
1033 }
1034 }
1035}
1036
1037use self::AccessDepth::{Deep, Shallow};
1038use self::ReadOrWrite::{Activation, Read, Reservation, Write};
1039
1040#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1041enum ArtificialField {
1042 ArrayLength,
1043 FakeBorrow,
1044}
1045
1046#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1047enum AccessDepth {
1048 Shallow(Option<ArtificialField>),
1054
1055 Deep,
1059
1060 Drop,
1063}
1064
1065#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1068enum ReadOrWrite {
1069 Read(ReadKind),
1072
1073 Write(WriteKind),
1077
1078 Reservation(WriteKind),
1082 Activation(WriteKind, BorrowIndex),
1083}
1084
1085#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1088enum ReadKind {
1089 Borrow(BorrowKind),
1090 Copy,
1091}
1092
1093#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1096enum WriteKind {
1097 StorageDeadOrDrop,
1098 Replace,
1099 MutableBorrow(BorrowKind),
1100 Mutate,
1101 Move,
1102}
1103
1104#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1112enum LocalMutationIsAllowed {
1113 Yes,
1114 ExceptUpvars,
1117 No,
1118}
1119
1120#[derive(Copy, Clone, Debug)]
1121enum InitializationRequiringAction {
1122 Borrow,
1123 MatchOn,
1124 Use,
1125 Assignment,
1126 PartialAssignment,
1127}
1128
1129#[derive(Debug)]
1130struct RootPlace<'tcx> {
1131 place_local: Local,
1132 place_projection: &'tcx [PlaceElem<'tcx>],
1133 is_local_mutation_allowed: LocalMutationIsAllowed,
1134}
1135
1136impl InitializationRequiringAction {
1137 fn as_noun(self) -> &'static str {
1138 match self {
1139 InitializationRequiringAction::Borrow => "borrow",
1140 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
1142 InitializationRequiringAction::Assignment => "assign",
1143 InitializationRequiringAction::PartialAssignment => "assign to part",
1144 }
1145 }
1146
1147 fn as_verb_in_past_tense(self) -> &'static str {
1148 match self {
1149 InitializationRequiringAction::Borrow => "borrowed",
1150 InitializationRequiringAction::MatchOn => "matched on",
1151 InitializationRequiringAction::Use => "used",
1152 InitializationRequiringAction::Assignment => "assigned",
1153 InitializationRequiringAction::PartialAssignment => "partially assigned",
1154 }
1155 }
1156
1157 fn as_general_verb_in_past_tense(self) -> &'static str {
1158 match self {
1159 InitializationRequiringAction::Borrow
1160 | InitializationRequiringAction::MatchOn
1161 | InitializationRequiringAction::Use => "used",
1162 InitializationRequiringAction::Assignment => "assigned",
1163 InitializationRequiringAction::PartialAssignment => "partially assigned",
1164 }
1165 }
1166}
1167
1168impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1169 fn body(&self) -> &'a Body<'tcx> {
1170 self.body
1171 }
1172
1173 fn access_place(
1180 &mut self,
1181 location: Location,
1182 place_span: (Place<'tcx>, Span),
1183 kind: (AccessDepth, ReadOrWrite),
1184 is_local_mutation_allowed: LocalMutationIsAllowed,
1185 state: &BorrowckDomain,
1186 ) {
1187 let (sd, rw) = kind;
1188
1189 if let Activation(_, borrow_index) = rw {
1190 if self.reservation_error_reported.contains(&place_span.0) {
1191 debug!(
1192 "skipping access_place for activation of invalid reservation \
1193 place: {:?} borrow_index: {:?}",
1194 place_span.0, borrow_index
1195 );
1196 return;
1197 }
1198 }
1199
1200 if !self.access_place_error_reported.is_empty()
1203 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1204 {
1205 debug!(
1206 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1207 place_span, kind
1208 );
1209 return;
1210 }
1211
1212 let mutability_error = self.check_access_permissions(
1213 place_span,
1214 rw,
1215 is_local_mutation_allowed,
1216 state,
1217 location,
1218 );
1219 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1220
1221 if conflict_error || mutability_error {
1222 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1223 self.access_place_error_reported.insert((place_span.0, place_span.1));
1224 }
1225 }
1226
1227 fn borrows_in_scope<'s>(
1228 &self,
1229 location: Location,
1230 state: &'s BorrowckDomain,
1231 ) -> Cow<'s, MixedBitSet<BorrowIndex>> {
1232 if let Some(polonius) = &self.polonius_output {
1233 let location = self.location_table.start_index(location);
1235 let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
1236 for &idx in polonius.errors_at(location) {
1237 polonius_output.insert(idx);
1238 }
1239 Cow::Owned(polonius_output)
1240 } else {
1241 Cow::Borrowed(&state.borrows)
1242 }
1243 }
1244
1245 #[instrument(level = "debug", skip(self, state))]
1246 fn check_access_for_conflict(
1247 &mut self,
1248 location: Location,
1249 place_span: (Place<'tcx>, Span),
1250 sd: AccessDepth,
1251 rw: ReadOrWrite,
1252 state: &BorrowckDomain,
1253 ) -> bool {
1254 let mut error_reported = false;
1255
1256 let borrows_in_scope = self.borrows_in_scope(location, state);
1257
1258 each_borrow_involving_path(
1259 self,
1260 self.infcx.tcx,
1261 self.body,
1262 (sd, place_span.0),
1263 self.borrow_set,
1264 |borrow_index| borrows_in_scope.contains(borrow_index),
1265 |this, borrow_index, borrow| match (rw, borrow.kind) {
1266 (Activation(_, activating), _) if activating == borrow_index => {
1273 debug!(
1274 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1275 skipping {:?} b/c activation of same borrow_index",
1276 place_span,
1277 sd,
1278 rw,
1279 (borrow_index, borrow),
1280 );
1281 ControlFlow::Continue(())
1282 }
1283
1284 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1285 | (
1286 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1287 BorrowKind::Mut { .. },
1288 ) => ControlFlow::Continue(()),
1289
1290 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1291 ControlFlow::Continue(())
1294 }
1295
1296 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1297 ControlFlow::Continue(())
1299 }
1300
1301 (Read(kind), BorrowKind::Mut { .. }) => {
1302 if !is_active(this.dominators(), borrow, location) {
1304 assert!(borrow.kind.allows_two_phase_borrow());
1305 return ControlFlow::Continue(());
1306 }
1307
1308 error_reported = true;
1309 match kind {
1310 ReadKind::Copy => {
1311 let err = this
1312 .report_use_while_mutably_borrowed(location, place_span, borrow);
1313 this.buffer_error(err);
1314 }
1315 ReadKind::Borrow(bk) => {
1316 let err =
1317 this.report_conflicting_borrow(location, place_span, bk, borrow);
1318 this.buffer_error(err);
1319 }
1320 }
1321 ControlFlow::Break(())
1322 }
1323
1324 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1325 match rw {
1326 Reservation(..) => {
1327 debug!(
1328 "recording invalid reservation of \
1329 place: {:?}",
1330 place_span.0
1331 );
1332 this.reservation_error_reported.insert(place_span.0);
1333 }
1334 Activation(_, activating) => {
1335 debug!(
1336 "observing check_place for activation of \
1337 borrow_index: {:?}",
1338 activating
1339 );
1340 }
1341 Read(..) | Write(..) => {}
1342 }
1343
1344 error_reported = true;
1345 match kind {
1346 WriteKind::MutableBorrow(bk) => {
1347 let err =
1348 this.report_conflicting_borrow(location, place_span, bk, borrow);
1349 this.buffer_error(err);
1350 }
1351 WriteKind::StorageDeadOrDrop => this
1352 .report_borrowed_value_does_not_live_long_enough(
1353 location,
1354 borrow,
1355 place_span,
1356 Some(WriteKind::StorageDeadOrDrop),
1357 ),
1358 WriteKind::Mutate => {
1359 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1360 }
1361 WriteKind::Move => {
1362 this.report_move_out_while_borrowed(location, place_span, borrow)
1363 }
1364 WriteKind::Replace => {
1365 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1366 }
1367 }
1368 ControlFlow::Break(())
1369 }
1370 },
1371 );
1372
1373 error_reported
1374 }
1375
1376 #[instrument(level = "debug", skip(self, state))]
1379 fn check_backward_incompatible_drop(
1380 &mut self,
1381 location: Location,
1382 place: Place<'tcx>,
1383 state: &BorrowckDomain,
1384 ) {
1385 let tcx = self.infcx.tcx;
1386 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1390 AccessDepth::Drop
1391 } else {
1392 AccessDepth::Shallow(None)
1393 };
1394
1395 let borrows_in_scope = self.borrows_in_scope(location, state);
1396
1397 each_borrow_involving_path(
1400 self,
1401 self.infcx.tcx,
1402 self.body,
1403 (sd, place),
1404 self.borrow_set,
1405 |borrow_index| borrows_in_scope.contains(borrow_index),
1406 |this, _borrow_index, borrow| {
1407 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1408 return ControlFlow::Continue(());
1409 }
1410 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1411 let explain = this.explain_why_borrow_contains_point(
1412 location,
1413 borrow,
1414 Some((WriteKind::StorageDeadOrDrop, place)),
1415 );
1416 this.infcx.tcx.node_span_lint(
1417 TAIL_EXPR_DROP_ORDER,
1418 CRATE_HIR_ID,
1419 borrowed,
1420 |diag| {
1421 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1422 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1423 },
1424 );
1425 ControlFlow::Break(())
1427 },
1428 );
1429 }
1430
1431 fn mutate_place(
1432 &mut self,
1433 location: Location,
1434 place_span: (Place<'tcx>, Span),
1435 kind: AccessDepth,
1436 state: &BorrowckDomain,
1437 ) {
1438 self.check_if_assigned_path_is_moved(location, place_span, state);
1440
1441 self.access_place(
1442 location,
1443 place_span,
1444 (kind, Write(WriteKind::Mutate)),
1445 LocalMutationIsAllowed::No,
1446 state,
1447 );
1448 }
1449
1450 fn consume_rvalue(
1451 &mut self,
1452 location: Location,
1453 (rvalue, span): (&Rvalue<'tcx>, Span),
1454 state: &BorrowckDomain,
1455 ) {
1456 match rvalue {
1457 &Rvalue::Ref(_ , bk, place) => {
1458 let access_kind = match bk {
1459 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1460 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1461 }
1462 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1463 (Deep, Read(ReadKind::Borrow(bk)))
1464 }
1465 BorrowKind::Mut { .. } => {
1466 let wk = WriteKind::MutableBorrow(bk);
1467 if bk.allows_two_phase_borrow() {
1468 (Deep, Reservation(wk))
1469 } else {
1470 (Deep, Write(wk))
1471 }
1472 }
1473 };
1474
1475 self.access_place(
1476 location,
1477 (place, span),
1478 access_kind,
1479 LocalMutationIsAllowed::No,
1480 state,
1481 );
1482
1483 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1484 InitializationRequiringAction::MatchOn
1485 } else {
1486 InitializationRequiringAction::Borrow
1487 };
1488
1489 self.check_if_path_or_subpath_is_moved(
1490 location,
1491 action,
1492 (place.as_ref(), span),
1493 state,
1494 );
1495 }
1496
1497 &Rvalue::RawPtr(kind, place) => {
1498 let access_kind = match kind {
1499 RawPtrKind::Mut => (
1500 Deep,
1501 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1502 kind: MutBorrowKind::Default,
1503 })),
1504 ),
1505 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1506 RawPtrKind::FakeForPtrMetadata => {
1507 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1508 }
1509 };
1510
1511 self.access_place(
1512 location,
1513 (place, span),
1514 access_kind,
1515 LocalMutationIsAllowed::No,
1516 state,
1517 );
1518
1519 self.check_if_path_or_subpath_is_moved(
1520 location,
1521 InitializationRequiringAction::Borrow,
1522 (place.as_ref(), span),
1523 state,
1524 );
1525 }
1526
1527 Rvalue::ThreadLocalRef(_) => {}
1528
1529 Rvalue::Use(operand)
1530 | Rvalue::Repeat(operand, _)
1531 | Rvalue::UnaryOp(_ , operand)
1532 | Rvalue::Cast(_ , operand, _ )
1533 | Rvalue::ShallowInitBox(operand, _ ) => {
1534 self.consume_operand(location, (operand, span), state)
1535 }
1536
1537 &Rvalue::Discriminant(place) => {
1538 let af = match *rvalue {
1539 Rvalue::Discriminant(..) => None,
1540 _ => unreachable!(),
1541 };
1542 self.access_place(
1543 location,
1544 (place, span),
1545 (Shallow(af), Read(ReadKind::Copy)),
1546 LocalMutationIsAllowed::No,
1547 state,
1548 );
1549 self.check_if_path_or_subpath_is_moved(
1550 location,
1551 InitializationRequiringAction::Use,
1552 (place.as_ref(), span),
1553 state,
1554 );
1555 }
1556
1557 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1558 self.consume_operand(location, (operand1, span), state);
1559 self.consume_operand(location, (operand2, span), state);
1560 }
1561
1562 Rvalue::NullaryOp(_op, _ty) => {
1563 }
1565
1566 Rvalue::Aggregate(aggregate_kind, operands) => {
1567 match **aggregate_kind {
1571 AggregateKind::Closure(def_id, _)
1572 | AggregateKind::CoroutineClosure(def_id, _)
1573 | AggregateKind::Coroutine(def_id, _) => {
1574 let def_id = def_id.expect_local();
1575 let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
1576 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1577 for field in used_mut_upvars.clone() {
1581 self.propagate_closure_used_mut_upvar(&operands[field]);
1582 }
1583 }
1584 AggregateKind::Adt(..)
1585 | AggregateKind::Array(..)
1586 | AggregateKind::Tuple { .. }
1587 | AggregateKind::RawPtr(..) => (),
1588 }
1589
1590 for operand in operands {
1591 self.consume_operand(location, (operand, span), state);
1592 }
1593 }
1594
1595 Rvalue::WrapUnsafeBinder(op, _) => {
1596 self.consume_operand(location, (op, span), state);
1597 }
1598
1599 Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"),
1600 }
1601 }
1602
1603 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1604 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1605 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1613 this.used_mut_upvars.push(field);
1614 return;
1615 }
1616
1617 for (place_ref, proj) in place.iter_projections().rev() {
1618 if proj == ProjectionElem::Deref {
1620 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1621 ty::Ref(_, _, hir::Mutability::Mut) => return,
1623
1624 _ => {}
1625 }
1626 }
1627
1628 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1630 this.used_mut_upvars.push(field);
1631 return;
1632 }
1633 }
1634
1635 this.used_mut.insert(place.local);
1637 };
1638
1639 match *operand {
1643 Operand::Move(place) | Operand::Copy(place) => {
1644 match place.as_local() {
1645 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1646 if self.body.local_decls[local].ty.is_mutable_ptr() {
1647 return;
1649 }
1650 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1666 bug!("temporary should be tracked");
1667 };
1668 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1669 &self.move_data.inits[init_index]
1670 } else {
1671 bug!("temporary should be initialized exactly once")
1672 };
1673
1674 let InitLocation::Statement(loc) = init.location else {
1675 bug!("temporary initialized in arguments")
1676 };
1677
1678 let body = self.body;
1679 let bbd = &body[loc.block];
1680 let stmt = &bbd.statements[loc.statement_index];
1681 debug!("temporary assigned in: stmt={:?}", stmt);
1682
1683 match stmt.kind {
1684 StatementKind::Assign(box (
1685 _,
1686 Rvalue::Ref(_, _, source)
1687 | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)),
1688 )) => {
1689 propagate_closure_used_mut_place(self, source);
1690 }
1691 _ => {
1692 bug!(
1693 "closures should only capture user variables \
1694 or references to user variables"
1695 );
1696 }
1697 }
1698 }
1699 _ => propagate_closure_used_mut_place(self, place),
1700 }
1701 }
1702 Operand::Constant(..) => {}
1703 }
1704 }
1705
1706 fn consume_operand(
1707 &mut self,
1708 location: Location,
1709 (operand, span): (&Operand<'tcx>, Span),
1710 state: &BorrowckDomain,
1711 ) {
1712 match *operand {
1713 Operand::Copy(place) => {
1714 self.access_place(
1717 location,
1718 (place, span),
1719 (Deep, Read(ReadKind::Copy)),
1720 LocalMutationIsAllowed::No,
1721 state,
1722 );
1723
1724 self.check_if_path_or_subpath_is_moved(
1726 location,
1727 InitializationRequiringAction::Use,
1728 (place.as_ref(), span),
1729 state,
1730 );
1731 }
1732 Operand::Move(place) => {
1733 self.check_movable_place(location, place);
1735
1736 self.access_place(
1738 location,
1739 (place, span),
1740 (Deep, Write(WriteKind::Move)),
1741 LocalMutationIsAllowed::Yes,
1742 state,
1743 );
1744
1745 self.check_if_path_or_subpath_is_moved(
1747 location,
1748 InitializationRequiringAction::Use,
1749 (place.as_ref(), span),
1750 state,
1751 );
1752 }
1753 Operand::Constant(_) => {}
1754 }
1755 }
1756
1757 #[instrument(level = "debug", skip(self))]
1760 fn check_for_invalidation_at_exit(
1761 &mut self,
1762 location: Location,
1763 borrow: &BorrowData<'tcx>,
1764 span: Span,
1765 ) {
1766 let place = borrow.borrowed_place;
1767 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1768
1769 let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1775 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1779 true
1780 } else {
1781 false
1782 };
1783
1784 let sd = if might_be_alive { Deep } else { Shallow(None) };
1785
1786 if places_conflict::borrow_conflicts_with_place(
1787 self.infcx.tcx,
1788 self.body,
1789 place,
1790 borrow.kind,
1791 root_place,
1792 sd,
1793 places_conflict::PlaceConflictBias::Overlap,
1794 ) {
1795 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1796 let span = self.infcx.tcx.sess.source_map().end_point(span);
1799 self.report_borrowed_value_does_not_live_long_enough(
1800 location,
1801 borrow,
1802 (place, span),
1803 None,
1804 )
1805 }
1806 }
1807
1808 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1811 debug!("check_for_local_borrow({:?})", borrow);
1812
1813 if borrow_of_local_data(borrow.borrowed_place) {
1814 let err = self.cannot_borrow_across_coroutine_yield(
1815 self.retrieve_borrow_spans(borrow).var_or_use(),
1816 yield_span,
1817 );
1818
1819 self.buffer_error(err);
1820 }
1821 }
1822
1823 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1824 for &borrow_index in self.borrow_set.activations_at_location(location) {
1828 let borrow = &self.borrow_set[borrow_index];
1829
1830 assert!(match borrow.kind {
1832 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1833 BorrowKind::Mut { .. } => true,
1834 });
1835
1836 self.access_place(
1837 location,
1838 (borrow.borrowed_place, span),
1839 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1840 LocalMutationIsAllowed::No,
1841 state,
1842 );
1843 }
1847 }
1848
1849 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1850 use IllegalMoveOriginKind::*;
1851
1852 let body = self.body;
1853 let tcx = self.infcx.tcx;
1854 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1855 for (place_ref, elem) in place.iter_projections() {
1856 match elem {
1857 ProjectionElem::Deref => match place_ty.ty.kind() {
1858 ty::Ref(..) | ty::RawPtr(..) => {
1859 self.move_errors.push(MoveError::new(
1860 place,
1861 location,
1862 BorrowedContent {
1863 target_place: place_ref.project_deeper(&[elem], tcx),
1864 },
1865 ));
1866 return;
1867 }
1868 ty::Adt(adt, _) => {
1869 if !adt.is_box() {
1870 bug!("Adt should be a box type when Place is deref");
1871 }
1872 }
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::FnDef(_, _)
1884 | ty::FnPtr(..)
1885 | ty::Dynamic(_, _)
1886 | ty::Closure(_, _)
1887 | ty::CoroutineClosure(_, _)
1888 | ty::Coroutine(_, _)
1889 | ty::CoroutineWitness(..)
1890 | ty::Never
1891 | ty::Tuple(_)
1892 | ty::UnsafeBinder(_)
1893 | ty::Alias(_, _)
1894 | ty::Param(_)
1895 | ty::Bound(_, _)
1896 | ty::Infer(_)
1897 | ty::Error(_)
1898 | ty::Placeholder(_) => {
1899 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1900 }
1901 },
1902 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1903 ty::Adt(adt, _) => {
1904 if adt.has_dtor(tcx) {
1905 self.move_errors.push(MoveError::new(
1906 place,
1907 location,
1908 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1909 ));
1910 return;
1911 }
1912 }
1913 ty::Closure(..)
1914 | ty::CoroutineClosure(..)
1915 | ty::Coroutine(_, _)
1916 | ty::Tuple(_) => (),
1917 ty::Bool
1918 | ty::Char
1919 | ty::Int(_)
1920 | ty::Uint(_)
1921 | ty::Float(_)
1922 | ty::Foreign(_)
1923 | ty::Str
1924 | ty::Array(_, _)
1925 | ty::Pat(_, _)
1926 | ty::Slice(_)
1927 | ty::RawPtr(_, _)
1928 | ty::Ref(_, _, _)
1929 | ty::FnDef(_, _)
1930 | ty::FnPtr(..)
1931 | ty::Dynamic(_, _)
1932 | ty::CoroutineWitness(..)
1933 | ty::Never
1934 | ty::UnsafeBinder(_)
1935 | ty::Alias(_, _)
1936 | ty::Param(_)
1937 | ty::Bound(_, _)
1938 | ty::Infer(_)
1939 | ty::Error(_)
1940 | ty::Placeholder(_) => bug!(
1941 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1942 ),
1943 },
1944 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1945 match place_ty.ty.kind() {
1946 ty::Slice(_) => {
1947 self.move_errors.push(MoveError::new(
1948 place,
1949 location,
1950 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1951 ));
1952 return;
1953 }
1954 ty::Array(_, _) => (),
1955 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1956 }
1957 }
1958 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1959 ty::Array(..) | ty::Slice(..) => {
1960 self.move_errors.push(MoveError::new(
1961 place,
1962 location,
1963 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1964 ));
1965 return;
1966 }
1967 _ => bug!("Unexpected type {place_ty:#?}"),
1968 },
1969 ProjectionElem::OpaqueCast(_)
1973 | ProjectionElem::Downcast(_, _)
1974 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1975 }
1976
1977 place_ty = place_ty.projection_ty(tcx, elem);
1978 }
1979 }
1980
1981 fn check_if_full_path_is_moved(
1982 &mut self,
1983 location: Location,
1984 desired_action: InitializationRequiringAction,
1985 place_span: (PlaceRef<'tcx>, Span),
1986 state: &BorrowckDomain,
1987 ) {
1988 let maybe_uninits = &state.uninits;
1989
1990 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
2026 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
2027 if maybe_uninits.contains(mpi) {
2028 self.report_use_of_moved_or_uninitialized(
2029 location,
2030 desired_action,
2031 (prefix, place_span.0, place_span.1),
2032 mpi,
2033 );
2034 } }
2041
2042 fn check_if_subslice_element_is_moved(
2048 &mut self,
2049 location: Location,
2050 desired_action: InitializationRequiringAction,
2051 place_span: (PlaceRef<'tcx>, Span),
2052 maybe_uninits: &MixedBitSet<MovePathIndex>,
2053 from: u64,
2054 to: u64,
2055 ) {
2056 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2057 let move_paths = &self.move_data.move_paths;
2058
2059 let root_path = &move_paths[mpi];
2060 for (child_mpi, child_move_path) in root_path.children(move_paths) {
2061 let last_proj = child_move_path.place.projection.last().unwrap();
2062 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
2063 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
2064
2065 if (from..to).contains(offset) {
2066 let uninit_child =
2067 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
2068 maybe_uninits.contains(mpi)
2069 });
2070
2071 if let Some(uninit_child) = uninit_child {
2072 self.report_use_of_moved_or_uninitialized(
2073 location,
2074 desired_action,
2075 (place_span.0, place_span.0, place_span.1),
2076 uninit_child,
2077 );
2078 return; }
2080 }
2081 }
2082 }
2083 }
2084 }
2085
2086 fn check_if_path_or_subpath_is_moved(
2087 &mut self,
2088 location: Location,
2089 desired_action: InitializationRequiringAction,
2090 place_span: (PlaceRef<'tcx>, Span),
2091 state: &BorrowckDomain,
2092 ) {
2093 let maybe_uninits = &state.uninits;
2094
2095 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
2111
2112 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
2113 place_span.0.last_projection()
2114 {
2115 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
2116 if let ty::Array(..) = place_ty.ty.kind() {
2117 self.check_if_subslice_element_is_moved(
2118 location,
2119 desired_action,
2120 (place_base, place_span.1),
2121 maybe_uninits,
2122 from,
2123 to,
2124 );
2125 return;
2126 }
2127 }
2128
2129 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
2139 if let Some(mpi) = self.move_path_for_place(place_span.0) {
2140 let uninit_mpi = self
2141 .move_data
2142 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
2143
2144 if let Some(uninit_mpi) = uninit_mpi {
2145 self.report_use_of_moved_or_uninitialized(
2146 location,
2147 desired_action,
2148 (place_span.0, place_span.0, place_span.1),
2149 uninit_mpi,
2150 );
2151 return; }
2153 }
2154 }
2155
2156 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
2167 match self.move_data.rev_lookup.find(place) {
2168 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
2169 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
2170 }
2171 LookupResult::Parent(None) => panic!("should have move path for every Local"),
2172 }
2173 }
2174
2175 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
2176 match self.move_data.rev_lookup.find(place) {
2181 LookupResult::Parent(_) => None,
2182 LookupResult::Exact(mpi) => Some(mpi),
2183 }
2184 }
2185
2186 fn check_if_assigned_path_is_moved(
2187 &mut self,
2188 location: Location,
2189 (place, span): (Place<'tcx>, Span),
2190 state: &BorrowckDomain,
2191 ) {
2192 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2193
2194 for (place_base, elem) in place.iter_projections().rev() {
2196 match elem {
2197 ProjectionElem::Index(_) |
2198 ProjectionElem::OpaqueCast(_) |
2199 ProjectionElem::ConstantIndex { .. } |
2200 ProjectionElem::Downcast(_, _) =>
2202 { }
2206
2207 ProjectionElem::UnwrapUnsafeBinder(_) => {
2208 check_parent_of_field(self, location, place_base, span, state);
2209 }
2210
2211 ProjectionElem::Deref => {
2213 self.check_if_full_path_is_moved(
2214 location, InitializationRequiringAction::Use,
2215 (place_base, span), state);
2216 break;
2219 }
2220
2221 ProjectionElem::Subslice { .. } => {
2222 panic!("we don't allow assignments to subslices, location: {location:?}");
2223 }
2224
2225 ProjectionElem::Field(..) => {
2226 let tcx = self.infcx.tcx;
2230 let base_ty = place_base.ty(self.body(), tcx).ty;
2231 match base_ty.kind() {
2232 ty::Adt(def, _) if def.has_dtor(tcx) => {
2233 self.check_if_path_or_subpath_is_moved(
2234 location, InitializationRequiringAction::Assignment,
2235 (place_base, span), state);
2236
2237 break;
2240 }
2241
2242 ty::Adt(..) | ty::Tuple(..) => {
2245 check_parent_of_field(self, location, place_base, span, state);
2246 }
2247
2248 _ => {}
2249 }
2250 }
2251 }
2252 }
2253
2254 fn check_parent_of_field<'a, 'tcx>(
2255 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2256 location: Location,
2257 base: PlaceRef<'tcx>,
2258 span: Span,
2259 state: &BorrowckDomain,
2260 ) {
2261 let maybe_uninits = &state.uninits;
2293
2294 let mut shortest_uninit_seen = None;
2297 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2298 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2299
2300 if maybe_uninits.contains(mpi) {
2301 debug!(
2302 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2303 shortest_uninit_seen,
2304 Some((prefix, mpi))
2305 );
2306 shortest_uninit_seen = Some((prefix, mpi));
2307 } else {
2308 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2309 }
2310 }
2311
2312 if let Some((prefix, mpi)) = shortest_uninit_seen {
2313 let tcx = this.infcx.tcx;
2319 if base.ty(this.body(), tcx).ty.is_union()
2320 && this.move_data.path_map[mpi].iter().any(|moi| {
2321 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2322 })
2323 {
2324 return;
2325 }
2326
2327 this.report_use_of_moved_or_uninitialized(
2328 location,
2329 InitializationRequiringAction::PartialAssignment,
2330 (prefix, base, span),
2331 mpi,
2332 );
2333
2334 this.used_mut.insert(base.local);
2338 }
2339 }
2340 }
2341
2342 fn check_access_permissions(
2346 &mut self,
2347 (place, span): (Place<'tcx>, Span),
2348 kind: ReadOrWrite,
2349 is_local_mutation_allowed: LocalMutationIsAllowed,
2350 state: &BorrowckDomain,
2351 location: Location,
2352 ) -> bool {
2353 debug!(
2354 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2355 place, kind, is_local_mutation_allowed
2356 );
2357
2358 let error_access;
2359 let the_place_err;
2360
2361 match kind {
2362 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2363 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2364 let is_local_mutation_allowed = match mut_borrow_kind {
2365 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2369 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2370 is_local_mutation_allowed
2371 }
2372 };
2373 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2374 Ok(root_place) => {
2375 self.add_used_mut(root_place, state);
2376 return false;
2377 }
2378 Err(place_err) => {
2379 error_access = AccessKind::MutableBorrow;
2380 the_place_err = place_err;
2381 }
2382 }
2383 }
2384 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2385 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2386 Ok(root_place) => {
2387 self.add_used_mut(root_place, state);
2388 return false;
2389 }
2390 Err(place_err) => {
2391 error_access = AccessKind::Mutate;
2392 the_place_err = place_err;
2393 }
2394 }
2395 }
2396
2397 Reservation(
2398 WriteKind::Move
2399 | WriteKind::Replace
2400 | WriteKind::StorageDeadOrDrop
2401 | WriteKind::MutableBorrow(BorrowKind::Shared)
2402 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2403 )
2404 | Write(
2405 WriteKind::Move
2406 | WriteKind::Replace
2407 | WriteKind::StorageDeadOrDrop
2408 | WriteKind::MutableBorrow(BorrowKind::Shared)
2409 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2410 ) => {
2411 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2412 && !self.has_buffered_diags()
2413 {
2414 self.dcx().span_delayed_bug(
2420 span,
2421 format!(
2422 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2423 ),
2424 );
2425 }
2426 return false;
2427 }
2428 Activation(..) => {
2429 return false;
2431 }
2432 Read(
2433 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2434 | ReadKind::Copy,
2435 ) => {
2436 return false;
2438 }
2439 }
2440
2441 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2446
2447 if let Some(init_index) = previously_initialized {
2449 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2450 let init = &self.move_data.inits[init_index];
2453 let assigned_span = init.span(self.body);
2454 self.report_illegal_reassignment((place, span), assigned_span, place);
2455 } else {
2456 self.report_mutability_error(place, span, the_place_err, error_access, location)
2457 }
2458 true
2459 } else {
2460 false
2461 }
2462 }
2463
2464 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2465 let mpi = self.move_data.rev_lookup.find_local(local)?;
2466 let ii = &self.move_data.init_path_map[mpi];
2467 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2468 }
2469
2470 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2472 match root_place {
2473 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2474 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2478 && self.is_local_ever_initialized(local, state).is_some()
2479 {
2480 self.used_mut.insert(local);
2481 }
2482 }
2483 RootPlace {
2484 place_local: _,
2485 place_projection: _,
2486 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2487 } => {}
2488 RootPlace {
2489 place_local,
2490 place_projection: place_projection @ [.., _],
2491 is_local_mutation_allowed: _,
2492 } => {
2493 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2494 local: place_local,
2495 projection: place_projection,
2496 }) {
2497 self.used_mut_upvars.push(field);
2498 }
2499 }
2500 }
2501 }
2502
2503 fn is_mutable(
2506 &self,
2507 place: PlaceRef<'tcx>,
2508 is_local_mutation_allowed: LocalMutationIsAllowed,
2509 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2510 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2511 match place.last_projection() {
2512 None => {
2513 let local = &self.body.local_decls[place.local];
2514 match local.mutability {
2515 Mutability::Not => match is_local_mutation_allowed {
2516 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2517 place_local: place.local,
2518 place_projection: place.projection,
2519 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2520 }),
2521 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2522 place_local: place.local,
2523 place_projection: place.projection,
2524 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2525 }),
2526 LocalMutationIsAllowed::No => Err(place),
2527 },
2528 Mutability::Mut => Ok(RootPlace {
2529 place_local: place.local,
2530 place_projection: place.projection,
2531 is_local_mutation_allowed,
2532 }),
2533 }
2534 }
2535 Some((place_base, elem)) => {
2536 match elem {
2537 ProjectionElem::Deref => {
2538 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2539
2540 match base_ty.kind() {
2542 ty::Ref(_, _, mutbl) => {
2543 match mutbl {
2544 hir::Mutability::Not => Err(place),
2546 hir::Mutability::Mut => {
2549 let mode = match self.is_upvar_field_projection(place) {
2550 Some(field)
2551 if self.upvars[field.index()].is_by_ref() =>
2552 {
2553 is_local_mutation_allowed
2554 }
2555 _ => LocalMutationIsAllowed::Yes,
2556 };
2557
2558 self.is_mutable(place_base, mode)
2559 }
2560 }
2561 }
2562 ty::RawPtr(_, mutbl) => {
2563 match mutbl {
2564 hir::Mutability::Not => Err(place),
2566 hir::Mutability::Mut => Ok(RootPlace {
2569 place_local: place.local,
2570 place_projection: place.projection,
2571 is_local_mutation_allowed,
2572 }),
2573 }
2574 }
2575 _ if base_ty.is_box() => {
2577 self.is_mutable(place_base, is_local_mutation_allowed)
2578 }
2579 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2581 }
2582 }
2583 ProjectionElem::Field(FieldIdx::ZERO, _)
2586 if let Some(adt) =
2587 place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
2588 && adt.is_pin()
2589 && self.infcx.tcx.features().pin_ergonomics() =>
2590 {
2591 self.is_mutable(place_base, is_local_mutation_allowed)
2592 }
2593 ProjectionElem::Field(..)
2596 | ProjectionElem::Index(..)
2597 | ProjectionElem::ConstantIndex { .. }
2598 | ProjectionElem::Subslice { .. }
2599 | ProjectionElem::OpaqueCast { .. }
2600 | ProjectionElem::Downcast(..)
2601 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2602 let upvar_field_projection = self.is_upvar_field_projection(place);
2603 if let Some(field) = upvar_field_projection {
2604 let upvar = &self.upvars[field.index()];
2605 debug!(
2606 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2607 place={:?}, place_base={:?}",
2608 upvar, is_local_mutation_allowed, place, place_base
2609 );
2610 match (upvar.mutability, is_local_mutation_allowed) {
2611 (
2612 Mutability::Not,
2613 LocalMutationIsAllowed::No
2614 | LocalMutationIsAllowed::ExceptUpvars,
2615 ) => Err(place),
2616 (Mutability::Not, LocalMutationIsAllowed::Yes)
2617 | (Mutability::Mut, _) => {
2618 let _ =
2637 self.is_mutable(place_base, is_local_mutation_allowed)?;
2638 Ok(RootPlace {
2639 place_local: place.local,
2640 place_projection: place.projection,
2641 is_local_mutation_allowed,
2642 })
2643 }
2644 }
2645 } else {
2646 self.is_mutable(place_base, is_local_mutation_allowed)
2647 }
2648 }
2649 }
2650 }
2651 }
2652 }
2653
2654 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2659 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2660 }
2661
2662 fn dominators(&self) -> &Dominators<BasicBlock> {
2663 self.body.basic_blocks.dominators()
2665 }
2666
2667 fn lint_unused_mut(&self) {
2668 let tcx = self.infcx.tcx;
2669 let body = self.body;
2670 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2671 let local_decl = &body.local_decls[local];
2672 let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
2673 body.source_scopes[local_decl.source_info.scope].local_data
2674 else {
2675 continue;
2676 };
2677
2678 if self.local_excluded_from_unused_mut_lint(local) {
2680 continue;
2681 }
2682
2683 let span = local_decl.source_info.span;
2684 if span.desugaring_kind().is_some() {
2685 continue;
2687 }
2688
2689 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2690
2691 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2692 }
2693 }
2694}
2695
2696enum Overlap {
2698 Arbitrary,
2704 EqualOrDisjoint,
2709 Disjoint,
2712}