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(let_chains)]
11#![feature(never_type)]
12#![feature(rustc_attrs)]
13#![feature(rustdoc_internals)]
14#![feature(stmt_expr_attributes)]
15#![feature(try_blocks)]
16#![warn(unreachable_pub)]
17use std::borrow::Cow;
20use std::cell::RefCell;
21use std::marker::PhantomData;
22use std::ops::{ControlFlow, Deref};
23
24use rustc_abi::FieldIdx;
25use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
26use rustc_data_structures::graph::dominators::Dominators;
27use rustc_errors::LintDiagnostic;
28use rustc_hir as hir;
29use rustc_hir::CRATE_HIR_ID;
30use rustc_hir::def_id::LocalDefId;
31use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
32use rustc_index::{IndexSlice, IndexVec};
33use rustc_infer::infer::{
34 InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
35};
36use rustc_middle::mir::tcx::PlaceTy;
37use rustc_middle::mir::*;
38use rustc_middle::query::Providers;
39use rustc_middle::ty::fold::fold_regions;
40use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
41use rustc_middle::{bug, span_bug};
42use rustc_mir_dataflow::impls::{
43 EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
44};
45use rustc_mir_dataflow::move_paths::{
46 InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
47};
48use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
49use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
50use rustc_span::{Span, Symbol};
51use smallvec::SmallVec;
52use tracing::{debug, instrument};
53
54use crate::borrow_set::{BorrowData, BorrowSet};
55use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
56use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
57use crate::diagnostics::{
58 AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
59};
60use crate::path_utils::*;
61use crate::place_ext::PlaceExt;
62use crate::places_conflict::{PlaceConflictBias, places_conflict};
63use crate::polonius::PoloniusDiagnosticsContext;
64use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
65use crate::prefixes::PrefixSet;
66use crate::region_infer::RegionInferenceContext;
67use crate::renumber::RegionCtxt;
68use crate::session_diagnostics::VarNeedNotMut;
69
70mod borrow_set;
71mod borrowck_errors;
72mod constraints;
73mod dataflow;
74mod def_use;
75mod diagnostics;
76mod member_constraints;
77mod nll;
78mod path_utils;
79mod place_ext;
80mod places_conflict;
81mod polonius;
82mod prefixes;
83mod region_infer;
84mod renumber;
85mod session_diagnostics;
86mod type_check;
87mod universal_regions;
88mod used_muts;
89
90pub mod consumers;
92
93rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
94
95struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
97
98impl<'tcx> TyCtxtConsts<'tcx> {
99 const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
100}
101
102pub fn provide(providers: &mut Providers) {
103 *providers = Providers { mir_borrowck, ..*providers };
104}
105
106fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
107 let (input_body, promoted) = tcx.mir_promoted(def);
108 debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
109
110 let input_body: &Body<'_> = &input_body.borrow();
111
112 if input_body.should_skip() || input_body.tainted_by_errors.is_some() {
113 debug!("Skipping borrowck because of injected body or tainted body");
114 let result = BorrowCheckResult {
116 concrete_opaque_types: FxIndexMap::default(),
117 closure_requirements: None,
118 used_mut_upvars: SmallVec::new(),
119 tainted_by_errors: input_body.tainted_by_errors,
120 };
121 return tcx.arena.alloc(result);
122 }
123
124 let borrowck_result = do_mir_borrowck(tcx, input_body, &*promoted.borrow(), None).0;
125 debug!("mir_borrowck done");
126
127 tcx.arena.alloc(borrowck_result)
128}
129
130#[instrument(skip(tcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")]
136fn do_mir_borrowck<'tcx>(
137 tcx: TyCtxt<'tcx>,
138 input_body: &Body<'tcx>,
139 input_promoted: &IndexSlice<Promoted, Body<'tcx>>,
140 consumer_options: Option<ConsumerOptions>,
141) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
142 let def = input_body.source.def_id().expect_local();
143 let infcx = BorrowckInferCtxt::new(tcx, def);
144 if let Some(e) = input_body.tainted_by_errors {
145 infcx.set_tainted_by_errors(e);
146 }
147
148 let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
149 for var_debug_info in &input_body.var_debug_info {
150 if let VarDebugInfoContents::Place(place) = var_debug_info.value {
151 if let Some(local) = place.as_local() {
152 if let Some(prev_name) = local_names[local]
153 && var_debug_info.name != prev_name
154 {
155 span_bug!(
156 var_debug_info.source_info.span,
157 "local {:?} has many names (`{}` vs `{}`)",
158 local,
159 prev_name,
160 var_debug_info.name
161 );
162 }
163 local_names[local] = Some(var_debug_info.name);
164 }
165 }
166 }
167
168 let mut body_owned = input_body.clone();
173 let mut promoted = input_promoted.to_owned();
174 let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
175 let body = &body_owned; if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
180 infcx.register_predefined_opaques_for_next_solver(def);
181 }
182
183 let location_table = PoloniusLocationTable::new(body);
184
185 let move_data = MoveData::gather_moves(body, tcx, |_| true);
186
187 let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
188 .iterate_to_fixpoint(tcx, body, Some("borrowck"))
189 .into_results_cursor(body);
190
191 let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
192 let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
193
194 let nll::NllOutput {
196 regioncx,
197 opaque_type_values,
198 polonius_input,
199 polonius_output,
200 opt_closure_req,
201 nll_errors,
202 polonius_diagnostics,
203 } = nll::compute_regions(
204 &infcx,
205 free_regions,
206 body,
207 &promoted,
208 &location_table,
209 flow_inits,
210 &move_data,
211 &borrow_set,
212 consumer_options,
213 );
214
215 nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
218
219 let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
222 nll::dump_annotation(
223 &infcx,
224 body,
225 ®ioncx,
226 &opt_closure_req,
227 &opaque_type_values,
228 diags_buffer,
229 );
230
231 let movable_coroutine =
232 if let Some(local) = body.local_decls.raw.get(1)
234 && let ty::Coroutine(def_id, _) = *local.ty.kind()
236 && tcx.coroutine_movability(def_id) == hir::Movability::Movable
237 {
238 true
239 } else {
240 false
241 };
242
243 for promoted_body in &promoted {
246 use rustc_middle::mir::visit::Visitor;
247 let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
251 let mut promoted_mbcx = MirBorrowckCtxt {
252 infcx: &infcx,
253 body: promoted_body,
254 move_data: &move_data,
255 location_table: &location_table,
257 movable_coroutine,
258 fn_self_span_reported: Default::default(),
259 locals_are_invalidated_at_exit,
260 access_place_error_reported: Default::default(),
261 reservation_error_reported: Default::default(),
262 uninitialized_error_reported: Default::default(),
263 regioncx: ®ioncx,
264 used_mut: Default::default(),
265 used_mut_upvars: SmallVec::new(),
266 borrow_set: &borrow_set,
267 upvars: &[],
268 local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
269 region_names: RefCell::default(),
270 next_region_name: RefCell::new(1),
271 polonius_output: None,
272 move_errors: Vec::new(),
273 diags_buffer,
274 polonius_diagnostics: polonius_diagnostics.as_ref(),
275 };
276 struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
277 ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
278 }
279
280 impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx> {
281 fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
282 if let Operand::Move(place) = operand {
283 self.ctxt.check_movable_place(location, *place);
284 }
285 }
286 }
287 MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
288 promoted_mbcx.report_move_errors();
289 }
290
291 let mut mbcx = MirBorrowckCtxt {
292 infcx: &infcx,
293 body,
294 move_data: &move_data,
295 location_table: &location_table,
296 movable_coroutine,
297 locals_are_invalidated_at_exit,
298 fn_self_span_reported: Default::default(),
299 access_place_error_reported: Default::default(),
300 reservation_error_reported: Default::default(),
301 uninitialized_error_reported: Default::default(),
302 regioncx: ®ioncx,
303 used_mut: Default::default(),
304 used_mut_upvars: SmallVec::new(),
305 borrow_set: &borrow_set,
306 upvars: tcx.closure_captures(def),
307 local_names,
308 region_names: RefCell::default(),
309 next_region_name: RefCell::new(1),
310 polonius_output,
311 move_errors: Vec::new(),
312 diags_buffer,
313 polonius_diagnostics: polonius_diagnostics.as_ref(),
314 };
315
316 mbcx.report_region_errors(nll_errors);
318
319 let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
320 visit_results(
321 body,
322 traversal::reverse_postorder(body).map(|(bb, _)| bb),
323 &mut flow_results,
324 &mut mbcx,
325 );
326
327 mbcx.report_move_errors();
328
329 polonius::dump_polonius_mir(
331 &infcx,
332 body,
333 ®ioncx,
334 &borrow_set,
335 polonius_diagnostics.as_ref(),
336 &opt_closure_req,
337 );
338
339 let temporary_used_locals: FxIndexSet<Local> = mbcx
345 .used_mut
346 .iter()
347 .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
348 .cloned()
349 .collect();
350 let unused_mut_locals =
354 mbcx.body.mut_vars_iter().filter(|local| !mbcx.used_mut.contains(local)).collect();
355 mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
356
357 debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
358 mbcx.lint_unused_mut();
359 let tainted_by_errors = mbcx.emit_errors();
360
361 let result = BorrowCheckResult {
362 concrete_opaque_types: opaque_type_values,
363 closure_requirements: opt_closure_req,
364 used_mut_upvars: mbcx.used_mut_upvars,
365 tainted_by_errors,
366 };
367
368 let body_with_facts = if consumer_options.is_some() {
369 let output_facts = mbcx.polonius_output;
370 Some(Box::new(BodyWithBorrowckFacts {
371 body: body_owned,
372 promoted,
373 borrow_set,
374 region_inference_context: regioncx,
375 location_table: polonius_input.as_ref().map(|_| location_table),
376 input_facts: polonius_input,
377 output_facts,
378 }))
379 } else {
380 None
381 };
382
383 debug!("do_mir_borrowck: result = {:#?}", result);
384
385 (result, body_with_facts)
386}
387
388fn get_flow_results<'a, 'tcx>(
389 tcx: TyCtxt<'tcx>,
390 body: &'a Body<'tcx>,
391 move_data: &'a MoveData<'tcx>,
392 borrow_set: &'a BorrowSet<'tcx>,
393 regioncx: &RegionInferenceContext<'tcx>,
394) -> Results<'tcx, Borrowck<'a, 'tcx>> {
395 let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
398 tcx,
399 body,
400 Some("borrowck"),
401 );
402 let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
403 tcx,
404 body,
405 Some("borrowck"),
406 );
407 let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
408 tcx,
409 body,
410 Some("borrowck"),
411 );
412
413 let analysis = Borrowck {
414 borrows: borrows.analysis,
415 uninits: uninits.analysis,
416 ever_inits: ever_inits.analysis,
417 };
418
419 assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
420 assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
421 let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
422 itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
423 .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
424 .collect();
425
426 Results { analysis, entry_states }
427}
428
429pub(crate) struct BorrowckInferCtxt<'tcx> {
430 pub(crate) infcx: InferCtxt<'tcx>,
431 pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
432 pub(crate) param_env: ParamEnv<'tcx>,
433}
434
435impl<'tcx> BorrowckInferCtxt<'tcx> {
436 pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
437 let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
438 let param_env = tcx.param_env(def_id);
439 BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
440 }
441
442 pub(crate) fn next_region_var<F>(
443 &self,
444 origin: RegionVariableOrigin,
445 get_ctxt_fn: F,
446 ) -> ty::Region<'tcx>
447 where
448 F: Fn() -> RegionCtxt,
449 {
450 let next_region = self.infcx.next_region_var(origin);
451 let vid = next_region.as_var();
452
453 if cfg!(debug_assertions) {
454 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
455 let ctxt = get_ctxt_fn();
456 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
457 assert_eq!(var_to_origin.insert(vid, ctxt), None);
458 }
459
460 next_region
461 }
462
463 #[instrument(skip(self, get_ctxt_fn), level = "debug")]
464 pub(crate) fn next_nll_region_var<F>(
465 &self,
466 origin: NllRegionVariableOrigin,
467 get_ctxt_fn: F,
468 ) -> ty::Region<'tcx>
469 where
470 F: Fn() -> RegionCtxt,
471 {
472 let next_region = self.infcx.next_nll_region_var(origin);
473 let vid = next_region.as_var();
474
475 if cfg!(debug_assertions) {
476 debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
477 let ctxt = get_ctxt_fn();
478 let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
479 assert_eq!(var_to_origin.insert(vid, ctxt), None);
480 }
481
482 next_region
483 }
484
485 fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) {
490 let tcx = self.tcx;
491 for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
494 let (key, hidden_ty) = fold_regions(tcx, data, |_, _| {
497 self.next_nll_region_var_in_universe(
498 NllRegionVariableOrigin::Existential { from_forall: false },
499 ty::UniverseIndex::ROOT,
500 )
501 });
502
503 self.inject_new_hidden_type_unchecked(key, hidden_ty);
504 }
505 }
506}
507
508impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
509 type Target = InferCtxt<'tcx>;
510
511 fn deref(&self) -> &Self::Target {
512 &self.infcx
513 }
514}
515
516struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
517 infcx: &'infcx BorrowckInferCtxt<'tcx>,
518 body: &'a Body<'tcx>,
519 move_data: &'a MoveData<'tcx>,
520
521 location_table: &'a PoloniusLocationTable,
524
525 movable_coroutine: bool,
526 locals_are_invalidated_at_exit: bool,
533 access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
539 reservation_error_reported: FxIndexSet<Place<'tcx>>,
547 fn_self_span_reported: FxIndexSet<Span>,
551 uninitialized_error_reported: FxIndexSet<Local>,
554 used_mut: FxIndexSet<Local>,
557 used_mut_upvars: SmallVec<[FieldIdx; 8]>,
560 regioncx: &'a RegionInferenceContext<'tcx>,
563
564 borrow_set: &'a BorrowSet<'tcx>,
566
567 upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
569
570 local_names: IndexVec<Local, Option<Symbol>>,
572
573 region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
576
577 next_region_name: RefCell<usize>,
579
580 polonius_output: Option<Box<PoloniusOutput>>,
582
583 diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
584 move_errors: Vec<MoveError<'tcx>>,
585
586 polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
588}
589
590impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
596 fn visit_after_early_statement_effect(
597 &mut self,
598 _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
599 state: &BorrowckDomain,
600 stmt: &'a Statement<'tcx>,
601 location: Location,
602 ) {
603 debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
604 let span = stmt.source_info.span;
605
606 self.check_activations(location, span, state);
607
608 match &stmt.kind {
609 StatementKind::Assign(box (lhs, rhs)) => {
610 self.consume_rvalue(location, (rhs, span), state);
611
612 self.mutate_place(location, (*lhs, span), Shallow(None), state);
613 }
614 StatementKind::FakeRead(box (_, place)) => {
615 self.check_if_path_or_subpath_is_moved(
626 location,
627 InitializationRequiringAction::Use,
628 (place.as_ref(), span),
629 state,
630 );
631 }
632 StatementKind::Intrinsic(box kind) => match kind {
633 NonDivergingIntrinsic::Assume(op) => {
634 self.consume_operand(location, (op, span), state);
635 }
636 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
637 span,
638 "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
639 )
640 }
641 StatementKind::AscribeUserType(..)
643 | StatementKind::PlaceMention(..)
645 | StatementKind::Coverage(..)
647 | StatementKind::ConstEvalCounter
649 | StatementKind::StorageLive(..) => {}
650 StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
652 self.check_backward_incompatible_drop(location, (**place, span), state);
653 }
654 StatementKind::StorageDead(local) => {
655 self.access_place(
656 location,
657 (Place::from(*local), span),
658 (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
659 LocalMutationIsAllowed::Yes,
660 state,
661 );
662 }
663 StatementKind::Nop
664 | StatementKind::Retag { .. }
665 | StatementKind::Deinit(..)
666 | StatementKind::SetDiscriminant { .. } => {
667 bug!("Statement not allowed in this MIR phase")
668 }
669 }
670 }
671
672 fn visit_after_early_terminator_effect(
673 &mut self,
674 _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
675 state: &BorrowckDomain,
676 term: &'a Terminator<'tcx>,
677 loc: Location,
678 ) {
679 debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
680 let span = term.source_info.span;
681
682 self.check_activations(loc, span, state);
683
684 match &term.kind {
685 TerminatorKind::SwitchInt { discr, targets: _ } => {
686 self.consume_operand(loc, (discr, span), state);
687 }
688 TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
689 debug!(
690 "visit_terminator_drop \
691 loc: {:?} term: {:?} place: {:?} span: {:?}",
692 loc, term, place, span
693 );
694
695 let write_kind =
696 if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
697 self.access_place(
698 loc,
699 (*place, span),
700 (AccessDepth::Drop, Write(write_kind)),
701 LocalMutationIsAllowed::Yes,
702 state,
703 );
704 }
705 TerminatorKind::Call {
706 func,
707 args,
708 destination,
709 target: _,
710 unwind: _,
711 call_source: _,
712 fn_span: _,
713 } => {
714 self.consume_operand(loc, (func, span), state);
715 for arg in args {
716 self.consume_operand(loc, (&arg.node, arg.span), state);
717 }
718 self.mutate_place(loc, (*destination, span), Deep, state);
719 }
720 TerminatorKind::TailCall { func, args, fn_span: _ } => {
721 self.consume_operand(loc, (func, span), state);
722 for arg in args {
723 self.consume_operand(loc, (&arg.node, arg.span), state);
724 }
725 }
726 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
727 self.consume_operand(loc, (cond, span), state);
728 if let AssertKind::BoundsCheck { len, index } = &**msg {
729 self.consume_operand(loc, (len, span), state);
730 self.consume_operand(loc, (index, span), state);
731 }
732 }
733
734 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
735 self.consume_operand(loc, (value, span), state);
736 self.mutate_place(loc, (*resume_arg, span), Deep, state);
737 }
738
739 TerminatorKind::InlineAsm {
740 asm_macro: _,
741 template: _,
742 operands,
743 options: _,
744 line_spans: _,
745 targets: _,
746 unwind: _,
747 } => {
748 for op in operands {
749 match op {
750 InlineAsmOperand::In { reg: _, value } => {
751 self.consume_operand(loc, (value, span), state);
752 }
753 InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
754 if let Some(place) = place {
755 self.mutate_place(loc, (*place, span), Shallow(None), state);
756 }
757 }
758 InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
759 self.consume_operand(loc, (in_value, span), state);
760 if let &Some(out_place) = out_place {
761 self.mutate_place(loc, (out_place, span), Shallow(None), state);
762 }
763 }
764 InlineAsmOperand::Const { value: _ }
765 | InlineAsmOperand::SymFn { value: _ }
766 | InlineAsmOperand::SymStatic { def_id: _ }
767 | InlineAsmOperand::Label { target_index: _ } => {}
768 }
769 }
770 }
771
772 TerminatorKind::Goto { target: _ }
773 | TerminatorKind::UnwindTerminate(_)
774 | TerminatorKind::Unreachable
775 | TerminatorKind::UnwindResume
776 | TerminatorKind::Return
777 | TerminatorKind::CoroutineDrop
778 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
779 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
780 }
782 }
783 }
784
785 fn visit_after_primary_terminator_effect(
786 &mut self,
787 _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
788 state: &BorrowckDomain,
789 term: &'a Terminator<'tcx>,
790 loc: Location,
791 ) {
792 let span = term.source_info.span;
793
794 match term.kind {
795 TerminatorKind::Yield { value: _, resume: _, resume_arg: _, drop: _ } => {
796 if self.movable_coroutine {
797 for i in state.borrows.iter() {
799 let borrow = &self.borrow_set[i];
800 self.check_for_local_borrow(borrow, span);
801 }
802 }
803 }
804
805 TerminatorKind::UnwindResume
806 | TerminatorKind::Return
807 | TerminatorKind::TailCall { .. }
808 | TerminatorKind::CoroutineDrop => {
809 for i in state.borrows.iter() {
814 let borrow = &self.borrow_set[i];
815 self.check_for_invalidation_at_exit(loc, borrow, span);
816 }
817 }
818
819 TerminatorKind::UnwindTerminate(_)
820 | TerminatorKind::Assert { .. }
821 | TerminatorKind::Call { .. }
822 | TerminatorKind::Drop { .. }
823 | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
824 | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
825 | TerminatorKind::Goto { .. }
826 | TerminatorKind::SwitchInt { .. }
827 | TerminatorKind::Unreachable
828 | TerminatorKind::InlineAsm { .. } => {}
829 }
830 }
831}
832
833use self::AccessDepth::{Deep, Shallow};
834use self::ReadOrWrite::{Activation, Read, Reservation, Write};
835
836#[derive(Copy, Clone, PartialEq, Eq, Debug)]
837enum ArtificialField {
838 ArrayLength,
839 FakeBorrow,
840}
841
842#[derive(Copy, Clone, PartialEq, Eq, Debug)]
843enum AccessDepth {
844 Shallow(Option<ArtificialField>),
850
851 Deep,
855
856 Drop,
859}
860
861#[derive(Copy, Clone, PartialEq, Eq, Debug)]
864enum ReadOrWrite {
865 Read(ReadKind),
868
869 Write(WriteKind),
873
874 Reservation(WriteKind),
878 Activation(WriteKind, BorrowIndex),
879}
880
881#[derive(Copy, Clone, PartialEq, Eq, Debug)]
884enum ReadKind {
885 Borrow(BorrowKind),
886 Copy,
887}
888
889#[derive(Copy, Clone, PartialEq, Eq, Debug)]
892enum WriteKind {
893 StorageDeadOrDrop,
894 Replace,
895 MutableBorrow(BorrowKind),
896 Mutate,
897 Move,
898}
899
900#[derive(Copy, Clone, PartialEq, Eq, Debug)]
908enum LocalMutationIsAllowed {
909 Yes,
910 ExceptUpvars,
913 No,
914}
915
916#[derive(Copy, Clone, Debug)]
917enum InitializationRequiringAction {
918 Borrow,
919 MatchOn,
920 Use,
921 Assignment,
922 PartialAssignment,
923}
924
925#[derive(Debug)]
926struct RootPlace<'tcx> {
927 place_local: Local,
928 place_projection: &'tcx [PlaceElem<'tcx>],
929 is_local_mutation_allowed: LocalMutationIsAllowed,
930}
931
932impl InitializationRequiringAction {
933 fn as_noun(self) -> &'static str {
934 match self {
935 InitializationRequiringAction::Borrow => "borrow",
936 InitializationRequiringAction::MatchOn => "use", InitializationRequiringAction::Use => "use",
938 InitializationRequiringAction::Assignment => "assign",
939 InitializationRequiringAction::PartialAssignment => "assign to part",
940 }
941 }
942
943 fn as_verb_in_past_tense(self) -> &'static str {
944 match self {
945 InitializationRequiringAction::Borrow => "borrowed",
946 InitializationRequiringAction::MatchOn => "matched on",
947 InitializationRequiringAction::Use => "used",
948 InitializationRequiringAction::Assignment => "assigned",
949 InitializationRequiringAction::PartialAssignment => "partially assigned",
950 }
951 }
952
953 fn as_general_verb_in_past_tense(self) -> &'static str {
954 match self {
955 InitializationRequiringAction::Borrow
956 | InitializationRequiringAction::MatchOn
957 | InitializationRequiringAction::Use => "used",
958 InitializationRequiringAction::Assignment => "assigned",
959 InitializationRequiringAction::PartialAssignment => "partially assigned",
960 }
961 }
962}
963
964impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
965 fn body(&self) -> &'a Body<'tcx> {
966 self.body
967 }
968
969 fn access_place(
976 &mut self,
977 location: Location,
978 place_span: (Place<'tcx>, Span),
979 kind: (AccessDepth, ReadOrWrite),
980 is_local_mutation_allowed: LocalMutationIsAllowed,
981 state: &BorrowckDomain,
982 ) {
983 let (sd, rw) = kind;
984
985 if let Activation(_, borrow_index) = rw {
986 if self.reservation_error_reported.contains(&place_span.0) {
987 debug!(
988 "skipping access_place for activation of invalid reservation \
989 place: {:?} borrow_index: {:?}",
990 place_span.0, borrow_index
991 );
992 return;
993 }
994 }
995
996 if !self.access_place_error_reported.is_empty()
999 && self.access_place_error_reported.contains(&(place_span.0, place_span.1))
1000 {
1001 debug!(
1002 "access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
1003 place_span, kind
1004 );
1005 return;
1006 }
1007
1008 let mutability_error = self.check_access_permissions(
1009 place_span,
1010 rw,
1011 is_local_mutation_allowed,
1012 state,
1013 location,
1014 );
1015 let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
1016
1017 if conflict_error || mutability_error {
1018 debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
1019 self.access_place_error_reported.insert((place_span.0, place_span.1));
1020 }
1021 }
1022
1023 fn borrows_in_scope<'s>(
1024 &self,
1025 location: Location,
1026 state: &'s BorrowckDomain,
1027 ) -> Cow<'s, DenseBitSet<BorrowIndex>> {
1028 if let Some(polonius) = &self.polonius_output {
1029 let location = self.location_table.start_index(location);
1031 let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
1032 for &idx in polonius.errors_at(location) {
1033 polonius_output.insert(idx);
1034 }
1035 Cow::Owned(polonius_output)
1036 } else {
1037 Cow::Borrowed(&state.borrows)
1038 }
1039 }
1040
1041 #[instrument(level = "debug", skip(self, state))]
1042 fn check_access_for_conflict(
1043 &mut self,
1044 location: Location,
1045 place_span: (Place<'tcx>, Span),
1046 sd: AccessDepth,
1047 rw: ReadOrWrite,
1048 state: &BorrowckDomain,
1049 ) -> bool {
1050 let mut error_reported = false;
1051
1052 let borrows_in_scope = self.borrows_in_scope(location, state);
1053
1054 each_borrow_involving_path(
1055 self,
1056 self.infcx.tcx,
1057 self.body,
1058 (sd, place_span.0),
1059 self.borrow_set,
1060 |borrow_index| borrows_in_scope.contains(borrow_index),
1061 |this, borrow_index, borrow| match (rw, borrow.kind) {
1062 (Activation(_, activating), _) if activating == borrow_index => {
1069 debug!(
1070 "check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
1071 skipping {:?} b/c activation of same borrow_index",
1072 place_span,
1073 sd,
1074 rw,
1075 (borrow_index, borrow),
1076 );
1077 ControlFlow::Continue(())
1078 }
1079
1080 (Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
1081 | (
1082 Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
1083 BorrowKind::Mut { .. },
1084 ) => ControlFlow::Continue(()),
1085
1086 (Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
1087 ControlFlow::Continue(())
1090 }
1091
1092 (Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
1093 ControlFlow::Continue(())
1095 }
1096
1097 (Read(kind), BorrowKind::Mut { .. }) => {
1098 if !is_active(this.dominators(), borrow, location) {
1100 assert!(borrow.kind.allows_two_phase_borrow());
1101 return ControlFlow::Continue(());
1102 }
1103
1104 error_reported = true;
1105 match kind {
1106 ReadKind::Copy => {
1107 let err = this
1108 .report_use_while_mutably_borrowed(location, place_span, borrow);
1109 this.buffer_error(err);
1110 }
1111 ReadKind::Borrow(bk) => {
1112 let err =
1113 this.report_conflicting_borrow(location, place_span, bk, borrow);
1114 this.buffer_error(err);
1115 }
1116 }
1117 ControlFlow::Break(())
1118 }
1119
1120 (Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
1121 match rw {
1122 Reservation(..) => {
1123 debug!(
1124 "recording invalid reservation of \
1125 place: {:?}",
1126 place_span.0
1127 );
1128 this.reservation_error_reported.insert(place_span.0);
1129 }
1130 Activation(_, activating) => {
1131 debug!(
1132 "observing check_place for activation of \
1133 borrow_index: {:?}",
1134 activating
1135 );
1136 }
1137 Read(..) | Write(..) => {}
1138 }
1139
1140 error_reported = true;
1141 match kind {
1142 WriteKind::MutableBorrow(bk) => {
1143 let err =
1144 this.report_conflicting_borrow(location, place_span, bk, borrow);
1145 this.buffer_error(err);
1146 }
1147 WriteKind::StorageDeadOrDrop => this
1148 .report_borrowed_value_does_not_live_long_enough(
1149 location,
1150 borrow,
1151 place_span,
1152 Some(WriteKind::StorageDeadOrDrop),
1153 ),
1154 WriteKind::Mutate => {
1155 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1156 }
1157 WriteKind::Move => {
1158 this.report_move_out_while_borrowed(location, place_span, borrow)
1159 }
1160 WriteKind::Replace => {
1161 this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
1162 }
1163 }
1164 ControlFlow::Break(())
1165 }
1166 },
1167 );
1168
1169 error_reported
1170 }
1171
1172 #[instrument(level = "debug", skip(self, state))]
1175 fn check_backward_incompatible_drop(
1176 &mut self,
1177 location: Location,
1178 (place, place_span): (Place<'tcx>, Span),
1179 state: &BorrowckDomain,
1180 ) {
1181 let tcx = self.infcx.tcx;
1182 let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
1186 AccessDepth::Drop
1187 } else {
1188 AccessDepth::Shallow(None)
1189 };
1190
1191 let borrows_in_scope = self.borrows_in_scope(location, state);
1192
1193 each_borrow_involving_path(
1196 self,
1197 self.infcx.tcx,
1198 self.body,
1199 (sd, place),
1200 self.borrow_set,
1201 |borrow_index| borrows_in_scope.contains(borrow_index),
1202 |this, _borrow_index, borrow| {
1203 if matches!(borrow.kind, BorrowKind::Fake(_)) {
1204 return ControlFlow::Continue(());
1205 }
1206 let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
1207 let explain = this.explain_why_borrow_contains_point(
1208 location,
1209 borrow,
1210 Some((WriteKind::StorageDeadOrDrop, place)),
1211 );
1212 this.infcx.tcx.node_span_lint(
1213 TAIL_EXPR_DROP_ORDER,
1214 CRATE_HIR_ID,
1215 borrowed,
1216 |diag| {
1217 session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
1218 explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
1219 },
1220 );
1221 ControlFlow::Break(())
1223 },
1224 );
1225 }
1226
1227 fn mutate_place(
1228 &mut self,
1229 location: Location,
1230 place_span: (Place<'tcx>, Span),
1231 kind: AccessDepth,
1232 state: &BorrowckDomain,
1233 ) {
1234 self.check_if_assigned_path_is_moved(location, place_span, state);
1236
1237 self.access_place(
1238 location,
1239 place_span,
1240 (kind, Write(WriteKind::Mutate)),
1241 LocalMutationIsAllowed::No,
1242 state,
1243 );
1244 }
1245
1246 fn consume_rvalue(
1247 &mut self,
1248 location: Location,
1249 (rvalue, span): (&'a Rvalue<'tcx>, Span),
1250 state: &BorrowckDomain,
1251 ) {
1252 match rvalue {
1253 &Rvalue::Ref(_ , bk, place) => {
1254 let access_kind = match bk {
1255 BorrowKind::Fake(FakeBorrowKind::Shallow) => {
1256 (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk)))
1257 }
1258 BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => {
1259 (Deep, Read(ReadKind::Borrow(bk)))
1260 }
1261 BorrowKind::Mut { .. } => {
1262 let wk = WriteKind::MutableBorrow(bk);
1263 if bk.allows_two_phase_borrow() {
1264 (Deep, Reservation(wk))
1265 } else {
1266 (Deep, Write(wk))
1267 }
1268 }
1269 };
1270
1271 self.access_place(
1272 location,
1273 (place, span),
1274 access_kind,
1275 LocalMutationIsAllowed::No,
1276 state,
1277 );
1278
1279 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
1280 InitializationRequiringAction::MatchOn
1281 } else {
1282 InitializationRequiringAction::Borrow
1283 };
1284
1285 self.check_if_path_or_subpath_is_moved(
1286 location,
1287 action,
1288 (place.as_ref(), span),
1289 state,
1290 );
1291 }
1292
1293 &Rvalue::RawPtr(kind, place) => {
1294 let access_kind = match kind {
1295 RawPtrKind::Mut => (
1296 Deep,
1297 Write(WriteKind::MutableBorrow(BorrowKind::Mut {
1298 kind: MutBorrowKind::Default,
1299 })),
1300 ),
1301 RawPtrKind::Const => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
1302 RawPtrKind::FakeForPtrMetadata => {
1303 (Shallow(Some(ArtificialField::ArrayLength)), Read(ReadKind::Copy))
1304 }
1305 };
1306
1307 self.access_place(
1308 location,
1309 (place, span),
1310 access_kind,
1311 LocalMutationIsAllowed::No,
1312 state,
1313 );
1314
1315 self.check_if_path_or_subpath_is_moved(
1316 location,
1317 InitializationRequiringAction::Borrow,
1318 (place.as_ref(), span),
1319 state,
1320 );
1321 }
1322
1323 Rvalue::ThreadLocalRef(_) => {}
1324
1325 Rvalue::Use(operand)
1326 | Rvalue::Repeat(operand, _)
1327 | Rvalue::UnaryOp(_ , operand)
1328 | Rvalue::Cast(_ , operand, _ )
1329 | Rvalue::ShallowInitBox(operand, _ ) => {
1330 self.consume_operand(location, (operand, span), state)
1331 }
1332
1333 &Rvalue::CopyForDeref(place) => {
1334 self.access_place(
1335 location,
1336 (place, span),
1337 (Deep, Read(ReadKind::Copy)),
1338 LocalMutationIsAllowed::No,
1339 state,
1340 );
1341
1342 self.check_if_path_or_subpath_is_moved(
1344 location,
1345 InitializationRequiringAction::Use,
1346 (place.as_ref(), span),
1347 state,
1348 );
1349 }
1350
1351 &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
1352 let af = match *rvalue {
1353 Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
1354 Rvalue::Discriminant(..) => None,
1355 _ => unreachable!(),
1356 };
1357 self.access_place(
1358 location,
1359 (place, span),
1360 (Shallow(af), Read(ReadKind::Copy)),
1361 LocalMutationIsAllowed::No,
1362 state,
1363 );
1364 self.check_if_path_or_subpath_is_moved(
1365 location,
1366 InitializationRequiringAction::Use,
1367 (place.as_ref(), span),
1368 state,
1369 );
1370 }
1371
1372 Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
1373 self.consume_operand(location, (operand1, span), state);
1374 self.consume_operand(location, (operand2, span), state);
1375 }
1376
1377 Rvalue::NullaryOp(_op, _ty) => {
1378 }
1380
1381 Rvalue::Aggregate(aggregate_kind, operands) => {
1382 match **aggregate_kind {
1386 AggregateKind::Closure(def_id, _)
1387 | AggregateKind::CoroutineClosure(def_id, _)
1388 | AggregateKind::Coroutine(def_id, _) => {
1389 let def_id = def_id.expect_local();
1390 let BorrowCheckResult { used_mut_upvars, .. } =
1391 self.infcx.tcx.mir_borrowck(def_id);
1392 debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1393 for field in used_mut_upvars {
1394 self.propagate_closure_used_mut_upvar(&operands[*field]);
1395 }
1396 }
1397 AggregateKind::Adt(..)
1398 | AggregateKind::Array(..)
1399 | AggregateKind::Tuple { .. }
1400 | AggregateKind::RawPtr(..) => (),
1401 }
1402
1403 for operand in operands {
1404 self.consume_operand(location, (operand, span), state);
1405 }
1406 }
1407
1408 Rvalue::WrapUnsafeBinder(op, _) => {
1409 self.consume_operand(location, (op, span), state);
1410 }
1411 }
1412 }
1413
1414 fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
1415 let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
1416 if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
1424 this.used_mut_upvars.push(field);
1425 return;
1426 }
1427
1428 for (place_ref, proj) in place.iter_projections().rev() {
1429 if proj == ProjectionElem::Deref {
1431 match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
1432 ty::Ref(_, _, hir::Mutability::Mut) => return,
1434
1435 _ => {}
1436 }
1437 }
1438
1439 if let Some(field) = this.is_upvar_field_projection(place_ref) {
1441 this.used_mut_upvars.push(field);
1442 return;
1443 }
1444 }
1445
1446 this.used_mut.insert(place.local);
1448 };
1449
1450 match *operand {
1454 Operand::Move(place) | Operand::Copy(place) => {
1455 match place.as_local() {
1456 Some(local) if !self.body.local_decls[local].is_user_variable() => {
1457 if self.body.local_decls[local].ty.is_mutable_ptr() {
1458 return;
1460 }
1461 let Some(temp_mpi) = self.move_data.rev_lookup.find_local(local) else {
1477 bug!("temporary should be tracked");
1478 };
1479 let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] {
1480 &self.move_data.inits[init_index]
1481 } else {
1482 bug!("temporary should be initialized exactly once")
1483 };
1484
1485 let InitLocation::Statement(loc) = init.location else {
1486 bug!("temporary initialized in arguments")
1487 };
1488
1489 let body = self.body;
1490 let bbd = &body[loc.block];
1491 let stmt = &bbd.statements[loc.statement_index];
1492 debug!("temporary assigned in: stmt={:?}", stmt);
1493
1494 if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind
1495 {
1496 propagate_closure_used_mut_place(self, source);
1497 } else {
1498 bug!(
1499 "closures should only capture user variables \
1500 or references to user variables"
1501 );
1502 }
1503 }
1504 _ => propagate_closure_used_mut_place(self, place),
1505 }
1506 }
1507 Operand::Constant(..) => {}
1508 }
1509 }
1510
1511 fn consume_operand(
1512 &mut self,
1513 location: Location,
1514 (operand, span): (&'a Operand<'tcx>, Span),
1515 state: &BorrowckDomain,
1516 ) {
1517 match *operand {
1518 Operand::Copy(place) => {
1519 self.access_place(
1522 location,
1523 (place, span),
1524 (Deep, Read(ReadKind::Copy)),
1525 LocalMutationIsAllowed::No,
1526 state,
1527 );
1528
1529 self.check_if_path_or_subpath_is_moved(
1531 location,
1532 InitializationRequiringAction::Use,
1533 (place.as_ref(), span),
1534 state,
1535 );
1536 }
1537 Operand::Move(place) => {
1538 self.check_movable_place(location, place);
1540
1541 self.access_place(
1543 location,
1544 (place, span),
1545 (Deep, Write(WriteKind::Move)),
1546 LocalMutationIsAllowed::Yes,
1547 state,
1548 );
1549
1550 self.check_if_path_or_subpath_is_moved(
1552 location,
1553 InitializationRequiringAction::Use,
1554 (place.as_ref(), span),
1555 state,
1556 );
1557 }
1558 Operand::Constant(_) => {}
1559 }
1560 }
1561
1562 #[instrument(level = "debug", skip(self))]
1565 fn check_for_invalidation_at_exit(
1566 &mut self,
1567 location: Location,
1568 borrow: &BorrowData<'tcx>,
1569 span: Span,
1570 ) {
1571 let place = borrow.borrowed_place;
1572 let mut root_place = PlaceRef { local: place.local, projection: &[] };
1573
1574 let (might_be_alive, will_be_dropped) =
1581 if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
1582 root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
1586 (true, true)
1587 } else {
1588 (false, self.locals_are_invalidated_at_exit)
1589 };
1590
1591 if !will_be_dropped {
1592 debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
1593 return;
1594 }
1595
1596 let sd = if might_be_alive { Deep } else { Shallow(None) };
1597
1598 if places_conflict::borrow_conflicts_with_place(
1599 self.infcx.tcx,
1600 self.body,
1601 place,
1602 borrow.kind,
1603 root_place,
1604 sd,
1605 places_conflict::PlaceConflictBias::Overlap,
1606 ) {
1607 debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
1608 let span = self.infcx.tcx.sess.source_map().end_point(span);
1611 self.report_borrowed_value_does_not_live_long_enough(
1612 location,
1613 borrow,
1614 (place, span),
1615 None,
1616 )
1617 }
1618 }
1619
1620 fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
1623 debug!("check_for_local_borrow({:?})", borrow);
1624
1625 if borrow_of_local_data(borrow.borrowed_place) {
1626 let err = self.cannot_borrow_across_coroutine_yield(
1627 self.retrieve_borrow_spans(borrow).var_or_use(),
1628 yield_span,
1629 );
1630
1631 self.buffer_error(err);
1632 }
1633 }
1634
1635 fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
1636 for &borrow_index in self.borrow_set.activations_at_location(location) {
1640 let borrow = &self.borrow_set[borrow_index];
1641
1642 assert!(match borrow.kind {
1644 BorrowKind::Shared | BorrowKind::Fake(_) => false,
1645 BorrowKind::Mut { .. } => true,
1646 });
1647
1648 self.access_place(
1649 location,
1650 (borrow.borrowed_place, span),
1651 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
1652 LocalMutationIsAllowed::No,
1653 state,
1654 );
1655 }
1659 }
1660
1661 fn check_movable_place(&mut self, location: Location, place: Place<'tcx>) {
1662 use IllegalMoveOriginKind::*;
1663
1664 let body = self.body;
1665 let tcx = self.infcx.tcx;
1666 let mut place_ty = PlaceTy::from_ty(body.local_decls[place.local].ty);
1667 for (place_ref, elem) in place.iter_projections() {
1668 match elem {
1669 ProjectionElem::Deref => match place_ty.ty.kind() {
1670 ty::Ref(..) | ty::RawPtr(..) => {
1671 self.move_errors.push(MoveError::new(
1672 place,
1673 location,
1674 BorrowedContent {
1675 target_place: place_ref.project_deeper(&[elem], tcx),
1676 },
1677 ));
1678 return;
1679 }
1680 ty::Adt(adt, _) => {
1681 if !adt.is_box() {
1682 bug!("Adt should be a box type when Place is deref");
1683 }
1684 }
1685 ty::Bool
1686 | ty::Char
1687 | ty::Int(_)
1688 | ty::Uint(_)
1689 | ty::Float(_)
1690 | ty::Foreign(_)
1691 | ty::Str
1692 | ty::Array(_, _)
1693 | ty::Pat(_, _)
1694 | ty::Slice(_)
1695 | ty::FnDef(_, _)
1696 | ty::FnPtr(..)
1697 | ty::Dynamic(_, _, _)
1698 | ty::Closure(_, _)
1699 | ty::CoroutineClosure(_, _)
1700 | ty::Coroutine(_, _)
1701 | ty::CoroutineWitness(..)
1702 | ty::Never
1703 | ty::Tuple(_)
1704 | ty::UnsafeBinder(_)
1705 | ty::Alias(_, _)
1706 | ty::Param(_)
1707 | ty::Bound(_, _)
1708 | ty::Infer(_)
1709 | ty::Error(_)
1710 | ty::Placeholder(_) => {
1711 bug!("When Place is Deref it's type shouldn't be {place_ty:#?}")
1712 }
1713 },
1714 ProjectionElem::Field(_, _) => match place_ty.ty.kind() {
1715 ty::Adt(adt, _) => {
1716 if adt.has_dtor(tcx) {
1717 self.move_errors.push(MoveError::new(
1718 place,
1719 location,
1720 InteriorOfTypeWithDestructor { container_ty: place_ty.ty },
1721 ));
1722 return;
1723 }
1724 }
1725 ty::Closure(..)
1726 | ty::CoroutineClosure(..)
1727 | ty::Coroutine(_, _)
1728 | ty::Tuple(_) => (),
1729 ty::Bool
1730 | ty::Char
1731 | ty::Int(_)
1732 | ty::Uint(_)
1733 | ty::Float(_)
1734 | ty::Foreign(_)
1735 | ty::Str
1736 | ty::Array(_, _)
1737 | ty::Pat(_, _)
1738 | ty::Slice(_)
1739 | ty::RawPtr(_, _)
1740 | ty::Ref(_, _, _)
1741 | ty::FnDef(_, _)
1742 | ty::FnPtr(..)
1743 | ty::Dynamic(_, _, _)
1744 | ty::CoroutineWitness(..)
1745 | ty::Never
1746 | ty::UnsafeBinder(_)
1747 | ty::Alias(_, _)
1748 | ty::Param(_)
1749 | ty::Bound(_, _)
1750 | ty::Infer(_)
1751 | ty::Error(_)
1752 | ty::Placeholder(_) => bug!(
1753 "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
1754 ),
1755 },
1756 ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
1757 match place_ty.ty.kind() {
1758 ty::Slice(_) => {
1759 self.move_errors.push(MoveError::new(
1760 place,
1761 location,
1762 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: false },
1763 ));
1764 return;
1765 }
1766 ty::Array(_, _) => (),
1767 _ => bug!("Unexpected type {:#?}", place_ty.ty),
1768 }
1769 }
1770 ProjectionElem::Index(_) => match place_ty.ty.kind() {
1771 ty::Array(..) | ty::Slice(..) => {
1772 self.move_errors.push(MoveError::new(
1773 place,
1774 location,
1775 InteriorOfSliceOrArray { ty: place_ty.ty, is_index: true },
1776 ));
1777 return;
1778 }
1779 _ => bug!("Unexpected type {place_ty:#?}"),
1780 },
1781 ProjectionElem::OpaqueCast(_)
1786 | ProjectionElem::Subtype(_)
1787 | ProjectionElem::Downcast(_, _)
1788 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
1789 }
1790
1791 place_ty = place_ty.projection_ty(tcx, elem);
1792 }
1793 }
1794
1795 fn check_if_full_path_is_moved(
1796 &mut self,
1797 location: Location,
1798 desired_action: InitializationRequiringAction,
1799 place_span: (PlaceRef<'tcx>, Span),
1800 state: &BorrowckDomain,
1801 ) {
1802 let maybe_uninits = &state.uninits;
1803
1804 debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
1840 let (prefix, mpi) = self.move_path_closest_to(place_span.0);
1841 if maybe_uninits.contains(mpi) {
1842 self.report_use_of_moved_or_uninitialized(
1843 location,
1844 desired_action,
1845 (prefix, place_span.0, place_span.1),
1846 mpi,
1847 );
1848 } }
1855
1856 fn check_if_subslice_element_is_moved(
1862 &mut self,
1863 location: Location,
1864 desired_action: InitializationRequiringAction,
1865 place_span: (PlaceRef<'tcx>, Span),
1866 maybe_uninits: &MixedBitSet<MovePathIndex>,
1867 from: u64,
1868 to: u64,
1869 ) {
1870 if let Some(mpi) = self.move_path_for_place(place_span.0) {
1871 let move_paths = &self.move_data.move_paths;
1872
1873 let root_path = &move_paths[mpi];
1874 for (child_mpi, child_move_path) in root_path.children(move_paths) {
1875 let last_proj = child_move_path.place.projection.last().unwrap();
1876 if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
1877 debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
1878
1879 if (from..to).contains(offset) {
1880 let uninit_child =
1881 self.move_data.find_in_move_path_or_its_descendants(child_mpi, |mpi| {
1882 maybe_uninits.contains(mpi)
1883 });
1884
1885 if let Some(uninit_child) = uninit_child {
1886 self.report_use_of_moved_or_uninitialized(
1887 location,
1888 desired_action,
1889 (place_span.0, place_span.0, place_span.1),
1890 uninit_child,
1891 );
1892 return; }
1894 }
1895 }
1896 }
1897 }
1898 }
1899
1900 fn check_if_path_or_subpath_is_moved(
1901 &mut self,
1902 location: Location,
1903 desired_action: InitializationRequiringAction,
1904 place_span: (PlaceRef<'tcx>, Span),
1905 state: &BorrowckDomain,
1906 ) {
1907 let maybe_uninits = &state.uninits;
1908
1909 self.check_if_full_path_is_moved(location, desired_action, place_span, state);
1925
1926 if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
1927 place_span.0.last_projection()
1928 {
1929 let place_ty = place_base.ty(self.body(), self.infcx.tcx);
1930 if let ty::Array(..) = place_ty.ty.kind() {
1931 self.check_if_subslice_element_is_moved(
1932 location,
1933 desired_action,
1934 (place_base, place_span.1),
1935 maybe_uninits,
1936 from,
1937 to,
1938 );
1939 return;
1940 }
1941 }
1942
1943 debug!("check_if_path_or_subpath_is_moved place: {:?}", place_span.0);
1953 if let Some(mpi) = self.move_path_for_place(place_span.0) {
1954 let uninit_mpi = self
1955 .move_data
1956 .find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi));
1957
1958 if let Some(uninit_mpi) = uninit_mpi {
1959 self.report_use_of_moved_or_uninitialized(
1960 location,
1961 desired_action,
1962 (place_span.0, place_span.0, place_span.1),
1963 uninit_mpi,
1964 );
1965 return; }
1967 }
1968 }
1969
1970 fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
1981 match self.move_data.rev_lookup.find(place) {
1982 LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
1983 (self.move_data.move_paths[mpi].place.as_ref(), mpi)
1984 }
1985 LookupResult::Parent(None) => panic!("should have move path for every Local"),
1986 }
1987 }
1988
1989 fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
1990 match self.move_data.rev_lookup.find(place) {
1995 LookupResult::Parent(_) => None,
1996 LookupResult::Exact(mpi) => Some(mpi),
1997 }
1998 }
1999
2000 fn check_if_assigned_path_is_moved(
2001 &mut self,
2002 location: Location,
2003 (place, span): (Place<'tcx>, Span),
2004 state: &BorrowckDomain,
2005 ) {
2006 debug!("check_if_assigned_path_is_moved place: {:?}", place);
2007
2008 for (place_base, elem) in place.iter_projections().rev() {
2010 match elem {
2011 ProjectionElem::Index(_) |
2012 ProjectionElem::Subtype(_) |
2013 ProjectionElem::OpaqueCast(_) |
2014 ProjectionElem::ConstantIndex { .. } |
2015 ProjectionElem::Downcast(_, _) =>
2017 { }
2021
2022 ProjectionElem::UnwrapUnsafeBinder(_) => {
2023 check_parent_of_field(self, location, place_base, span, state);
2024 }
2025
2026 ProjectionElem::Deref => {
2028 self.check_if_full_path_is_moved(
2029 location, InitializationRequiringAction::Use,
2030 (place_base, span), state);
2031 break;
2034 }
2035
2036 ProjectionElem::Subslice { .. } => {
2037 panic!("we don't allow assignments to subslices, location: {location:?}");
2038 }
2039
2040 ProjectionElem::Field(..) => {
2041 let tcx = self.infcx.tcx;
2045 let base_ty = place_base.ty(self.body(), tcx).ty;
2046 match base_ty.kind() {
2047 ty::Adt(def, _) if def.has_dtor(tcx) => {
2048 self.check_if_path_or_subpath_is_moved(
2049 location, InitializationRequiringAction::Assignment,
2050 (place_base, span), state);
2051
2052 break;
2055 }
2056
2057 ty::Adt(..) | ty::Tuple(..) => {
2060 check_parent_of_field(self, location, place_base, span, state);
2061 }
2062
2063 _ => {}
2064 }
2065 }
2066 }
2067 }
2068
2069 fn check_parent_of_field<'a, 'tcx>(
2070 this: &mut MirBorrowckCtxt<'a, '_, 'tcx>,
2071 location: Location,
2072 base: PlaceRef<'tcx>,
2073 span: Span,
2074 state: &BorrowckDomain,
2075 ) {
2076 let maybe_uninits = &state.uninits;
2108
2109 let mut shortest_uninit_seen = None;
2112 for prefix in this.prefixes(base, PrefixSet::Shallow) {
2113 let Some(mpi) = this.move_path_for_place(prefix) else { continue };
2114
2115 if maybe_uninits.contains(mpi) {
2116 debug!(
2117 "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}",
2118 shortest_uninit_seen,
2119 Some((prefix, mpi))
2120 );
2121 shortest_uninit_seen = Some((prefix, mpi));
2122 } else {
2123 debug!("check_parent_of_field {:?} is definitely initialized", (prefix, mpi));
2124 }
2125 }
2126
2127 if let Some((prefix, mpi)) = shortest_uninit_seen {
2128 let tcx = this.infcx.tcx;
2134 if base.ty(this.body(), tcx).ty.is_union()
2135 && this.move_data.path_map[mpi].iter().any(|moi| {
2136 this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
2137 })
2138 {
2139 return;
2140 }
2141
2142 this.report_use_of_moved_or_uninitialized(
2143 location,
2144 InitializationRequiringAction::PartialAssignment,
2145 (prefix, base, span),
2146 mpi,
2147 );
2148
2149 this.used_mut.insert(base.local);
2153 }
2154 }
2155 }
2156
2157 fn check_access_permissions(
2161 &mut self,
2162 (place, span): (Place<'tcx>, Span),
2163 kind: ReadOrWrite,
2164 is_local_mutation_allowed: LocalMutationIsAllowed,
2165 state: &BorrowckDomain,
2166 location: Location,
2167 ) -> bool {
2168 debug!(
2169 "check_access_permissions({:?}, {:?}, is_local_mutation_allowed: {:?})",
2170 place, kind, is_local_mutation_allowed
2171 );
2172
2173 let error_access;
2174 let the_place_err;
2175
2176 match kind {
2177 Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
2178 | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
2179 let is_local_mutation_allowed = match mut_borrow_kind {
2180 MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
2184 MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
2185 is_local_mutation_allowed
2186 }
2187 };
2188 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2189 Ok(root_place) => {
2190 self.add_used_mut(root_place, state);
2191 return false;
2192 }
2193 Err(place_err) => {
2194 error_access = AccessKind::MutableBorrow;
2195 the_place_err = place_err;
2196 }
2197 }
2198 }
2199 Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
2200 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
2201 Ok(root_place) => {
2202 self.add_used_mut(root_place, state);
2203 return false;
2204 }
2205 Err(place_err) => {
2206 error_access = AccessKind::Mutate;
2207 the_place_err = place_err;
2208 }
2209 }
2210 }
2211
2212 Reservation(
2213 WriteKind::Move
2214 | WriteKind::Replace
2215 | WriteKind::StorageDeadOrDrop
2216 | WriteKind::MutableBorrow(BorrowKind::Shared)
2217 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2218 )
2219 | Write(
2220 WriteKind::Move
2221 | WriteKind::Replace
2222 | WriteKind::StorageDeadOrDrop
2223 | WriteKind::MutableBorrow(BorrowKind::Shared)
2224 | WriteKind::MutableBorrow(BorrowKind::Fake(_)),
2225 ) => {
2226 if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
2227 && !self.has_buffered_diags()
2228 {
2229 self.dcx().span_delayed_bug(
2235 span,
2236 format!(
2237 "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
2238 ),
2239 );
2240 }
2241 return false;
2242 }
2243 Activation(..) => {
2244 return false;
2246 }
2247 Read(
2248 ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_))
2249 | ReadKind::Copy,
2250 ) => {
2251 return false;
2253 }
2254 }
2255
2256 let previously_initialized = self.is_local_ever_initialized(place.local, state);
2261
2262 if let Some(init_index) = previously_initialized {
2264 if let (AccessKind::Mutate, Some(_)) = (error_access, place.as_local()) {
2265 let init = &self.move_data.inits[init_index];
2268 let assigned_span = init.span(self.body);
2269 self.report_illegal_reassignment((place, span), assigned_span, place);
2270 } else {
2271 self.report_mutability_error(place, span, the_place_err, error_access, location)
2272 }
2273 true
2274 } else {
2275 false
2276 }
2277 }
2278
2279 fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
2280 let mpi = self.move_data.rev_lookup.find_local(local)?;
2281 let ii = &self.move_data.init_path_map[mpi];
2282 ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
2283 }
2284
2285 fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
2287 match root_place {
2288 RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
2289 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
2293 && self.is_local_ever_initialized(local, state).is_some()
2294 {
2295 self.used_mut.insert(local);
2296 }
2297 }
2298 RootPlace {
2299 place_local: _,
2300 place_projection: _,
2301 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2302 } => {}
2303 RootPlace {
2304 place_local,
2305 place_projection: place_projection @ [.., _],
2306 is_local_mutation_allowed: _,
2307 } => {
2308 if let Some(field) = self.is_upvar_field_projection(PlaceRef {
2309 local: place_local,
2310 projection: place_projection,
2311 }) {
2312 self.used_mut_upvars.push(field);
2313 }
2314 }
2315 }
2316 }
2317
2318 fn is_mutable(
2321 &self,
2322 place: PlaceRef<'tcx>,
2323 is_local_mutation_allowed: LocalMutationIsAllowed,
2324 ) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
2325 debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
2326 match place.last_projection() {
2327 None => {
2328 let local = &self.body.local_decls[place.local];
2329 match local.mutability {
2330 Mutability::Not => match is_local_mutation_allowed {
2331 LocalMutationIsAllowed::Yes => Ok(RootPlace {
2332 place_local: place.local,
2333 place_projection: place.projection,
2334 is_local_mutation_allowed: LocalMutationIsAllowed::Yes,
2335 }),
2336 LocalMutationIsAllowed::ExceptUpvars => Ok(RootPlace {
2337 place_local: place.local,
2338 place_projection: place.projection,
2339 is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars,
2340 }),
2341 LocalMutationIsAllowed::No => Err(place),
2342 },
2343 Mutability::Mut => Ok(RootPlace {
2344 place_local: place.local,
2345 place_projection: place.projection,
2346 is_local_mutation_allowed,
2347 }),
2348 }
2349 }
2350 Some((place_base, elem)) => {
2351 match elem {
2352 ProjectionElem::Deref => {
2353 let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
2354
2355 match base_ty.kind() {
2357 ty::Ref(_, _, mutbl) => {
2358 match mutbl {
2359 hir::Mutability::Not => Err(place),
2361 hir::Mutability::Mut => {
2364 let mode = match self.is_upvar_field_projection(place) {
2365 Some(field)
2366 if self.upvars[field.index()].is_by_ref() =>
2367 {
2368 is_local_mutation_allowed
2369 }
2370 _ => LocalMutationIsAllowed::Yes,
2371 };
2372
2373 self.is_mutable(place_base, mode)
2374 }
2375 }
2376 }
2377 ty::RawPtr(_, mutbl) => {
2378 match mutbl {
2379 hir::Mutability::Not => Err(place),
2381 hir::Mutability::Mut => Ok(RootPlace {
2384 place_local: place.local,
2385 place_projection: place.projection,
2386 is_local_mutation_allowed,
2387 }),
2388 }
2389 }
2390 _ if base_ty.is_box() => {
2392 self.is_mutable(place_base, is_local_mutation_allowed)
2393 }
2394 _ => bug!("Deref of unexpected type: {:?}", base_ty),
2396 }
2397 }
2398 ProjectionElem::Field(..)
2401 | ProjectionElem::Index(..)
2402 | ProjectionElem::ConstantIndex { .. }
2403 | ProjectionElem::Subslice { .. }
2404 | ProjectionElem::Subtype(..)
2405 | ProjectionElem::OpaqueCast { .. }
2406 | ProjectionElem::Downcast(..)
2407 | ProjectionElem::UnwrapUnsafeBinder(_) => {
2408 let upvar_field_projection = self.is_upvar_field_projection(place);
2409 if let Some(field) = upvar_field_projection {
2410 let upvar = &self.upvars[field.index()];
2411 debug!(
2412 "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
2413 place={:?}, place_base={:?}",
2414 upvar, is_local_mutation_allowed, place, place_base
2415 );
2416 match (upvar.mutability, is_local_mutation_allowed) {
2417 (
2418 Mutability::Not,
2419 LocalMutationIsAllowed::No
2420 | LocalMutationIsAllowed::ExceptUpvars,
2421 ) => Err(place),
2422 (Mutability::Not, LocalMutationIsAllowed::Yes)
2423 | (Mutability::Mut, _) => {
2424 let _ =
2443 self.is_mutable(place_base, is_local_mutation_allowed)?;
2444 Ok(RootPlace {
2445 place_local: place.local,
2446 place_projection: place.projection,
2447 is_local_mutation_allowed,
2448 })
2449 }
2450 }
2451 } else {
2452 self.is_mutable(place_base, is_local_mutation_allowed)
2453 }
2454 }
2455 }
2456 }
2457 }
2458 }
2459
2460 fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<FieldIdx> {
2465 path_utils::is_upvar_field_projection(self.infcx.tcx, &self.upvars, place_ref, self.body())
2466 }
2467
2468 fn dominators(&self) -> &Dominators<BasicBlock> {
2469 self.body.basic_blocks.dominators()
2471 }
2472
2473 fn lint_unused_mut(&self) {
2474 let tcx = self.infcx.tcx;
2475 let body = self.body;
2476 for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
2477 let local_decl = &body.local_decls[local];
2478 let lint_root = match &body.source_scopes[local_decl.source_info.scope].local_data {
2479 ClearCrossCrate::Set(data) => data.lint_root,
2480 _ => continue,
2481 };
2482
2483 match self.local_names[local] {
2485 Some(name) => {
2486 if name.as_str().starts_with('_') {
2487 continue;
2488 }
2489 }
2490 None => continue,
2491 }
2492
2493 let span = local_decl.source_info.span;
2494 if span.desugaring_kind().is_some() {
2495 continue;
2497 }
2498
2499 let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
2500
2501 tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span })
2502 }
2503 }
2504}
2505
2506enum Overlap {
2508 Arbitrary,
2514 EqualOrDisjoint,
2519 Disjoint,
2522}