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