1use crate::mir::*;
66use crate::ty::CanonicalUserTypeAnnotation;
67
68macro_rules! make_mir_visitor {
69 ($visitor_trait_name:ident, $($mutability:ident)?) => {
70 pub trait $visitor_trait_name<'tcx> {
71 fn visit_body(
75 &mut self,
76 body: &$($mutability)? Body<'tcx>,
77 ) {
78 self.super_body(body);
79 }
80
81 extra_body_methods!($($mutability)?);
82
83 fn visit_basic_block_data(
84 &mut self,
85 block: BasicBlock,
86 data: & $($mutability)? BasicBlockData<'tcx>,
87 ) {
88 self.super_basic_block_data(block, data);
89 }
90
91 fn visit_source_scope_data(
92 &mut self,
93 scope_data: & $($mutability)? SourceScopeData<'tcx>,
94 ) {
95 self.super_source_scope_data(scope_data);
96 }
97
98 fn visit_statement_debuginfo(
99 &mut self,
100 stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
101 location: Location
102 ) {
103 self.super_statement_debuginfo(stmt_debuginfo, location);
104 }
105
106 fn visit_statement(
107 &mut self,
108 statement: & $($mutability)? Statement<'tcx>,
109 location: Location,
110 ) {
111 self.super_statement(statement, location);
112 }
113
114 fn visit_assign(
115 &mut self,
116 place: & $($mutability)? Place<'tcx>,
117 rvalue: & $($mutability)? Rvalue<'tcx>,
118 location: Location,
119 ) {
120 self.super_assign(place, rvalue, location);
121 }
122
123 fn visit_terminator(
124 &mut self,
125 terminator: & $($mutability)? Terminator<'tcx>,
126 location: Location,
127 ) {
128 self.super_terminator(terminator, location);
129 }
130
131 fn visit_assert_message(
132 &mut self,
133 msg: & $($mutability)? AssertMessage<'tcx>,
134 location: Location,
135 ) {
136 self.super_assert_message(msg, location);
137 }
138
139 fn visit_rvalue(
140 &mut self,
141 rvalue: & $($mutability)? Rvalue<'tcx>,
142 location: Location,
143 ) {
144 self.super_rvalue(rvalue, location);
145 }
146
147 fn visit_operand(
148 &mut self,
149 operand: & $($mutability)? Operand<'tcx>,
150 location: Location,
151 ) {
152 self.super_operand(operand, location);
153 }
154
155 fn visit_ascribe_user_ty(
156 &mut self,
157 place: & $($mutability)? Place<'tcx>,
158 variance: $(& $mutability)? ty::Variance,
159 user_ty: & $($mutability)? UserTypeProjection,
160 location: Location,
161 ) {
162 self.super_ascribe_user_ty(place, variance, user_ty, location);
163 }
164
165 fn visit_coverage(
166 &mut self,
167 kind: & $($mutability)? coverage::CoverageKind,
168 location: Location,
169 ) {
170 self.super_coverage(kind, location);
171 }
172
173 fn visit_retag(
174 &mut self,
175 kind: $(& $mutability)? RetagKind,
176 place: & $($mutability)? Place<'tcx>,
177 location: Location,
178 ) {
179 self.super_retag(kind, place, location);
180 }
181
182 fn visit_place(
183 &mut self,
184 place: & $($mutability)? Place<'tcx>,
185 context: PlaceContext,
186 location: Location,
187 ) {
188 self.super_place(place, context, location);
189 }
190
191 visit_place_fns!($($mutability)?);
192
193 fn visit_const_operand(
196 &mut self,
197 constant: & $($mutability)? ConstOperand<'tcx>,
198 location: Location,
199 ) {
200 self.super_const_operand(constant, location);
201 }
202
203 fn visit_ty_const(
204 &mut self,
205 ct: $( & $mutability)? ty::Const<'tcx>,
206 location: Location,
207 ) {
208 self.super_ty_const(ct, location);
209 }
210
211 fn visit_span(
212 &mut self,
213 span: $(& $mutability)? Span,
214 ) {
215 self.super_span(span);
216 }
217
218 fn visit_source_info(
219 &mut self,
220 source_info: & $($mutability)? SourceInfo,
221 ) {
222 self.super_source_info(source_info);
223 }
224
225 fn visit_ty(
226 &mut self,
227 ty: $(& $mutability)? Ty<'tcx>,
228 _: TyContext,
229 ) {
230 self.super_ty(ty);
231 }
232
233 fn visit_user_type_projection(
234 &mut self,
235 ty: & $($mutability)? UserTypeProjection,
236 ) {
237 self.super_user_type_projection(ty);
238 }
239
240 fn visit_user_type_annotation(
241 &mut self,
242 index: UserTypeAnnotationIndex,
243 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
244 ) {
245 self.super_user_type_annotation(index, ty);
246 }
247
248 fn visit_region(
249 &mut self,
250 region: $(& $mutability)? ty::Region<'tcx>,
251 _: Location,
252 ) {
253 self.super_region(region);
254 }
255
256 fn visit_args(
257 &mut self,
258 args: & $($mutability)? GenericArgsRef<'tcx>,
259 _: Location,
260 ) {
261 self.super_args(args);
262 }
263
264 fn visit_local_decl(
265 &mut self,
266 local: Local,
267 local_decl: & $($mutability)? LocalDecl<'tcx>,
268 ) {
269 self.super_local_decl(local, local_decl);
270 }
271
272 fn visit_var_debug_info(
273 &mut self,
274 var_debug_info: & $($mutability)* VarDebugInfo<'tcx>,
275 ) {
276 self.super_var_debug_info(var_debug_info);
277 }
278
279 fn visit_local(
280 &mut self,
281 local: $(& $mutability)? Local,
282 context: PlaceContext,
283 location: Location,
284 ) {
285 self.super_local(local, context, location)
286 }
287
288 fn visit_source_scope(
289 &mut self,
290 scope: $(& $mutability)? SourceScope,
291 ) {
292 self.super_source_scope(scope);
293 }
294
295 fn super_body(
299 &mut self,
300 body: &$($mutability)? Body<'tcx>,
301 ) {
302 super_body!(self, body, $($mutability, true)?);
303 }
304
305 fn super_basic_block_data(
306 &mut self,
307 block: BasicBlock,
308 data: & $($mutability)? BasicBlockData<'tcx>)
309 {
310 let BasicBlockData {
311 statements,
312 after_last_stmt_debuginfos,
313 terminator,
314 is_cleanup: _
315 } = data;
316
317 let mut index = 0;
318 for statement in statements {
319 let location = Location { block, statement_index: index };
320 self.visit_statement(statement, location);
321 index += 1;
322 }
323
324 let location = Location { block, statement_index: index };
325 for debuginfo in after_last_stmt_debuginfos as & $($mutability)? [_] {
326 self.visit_statement_debuginfo(debuginfo, location);
327 }
328 if let Some(terminator) = terminator {
329 self.visit_terminator(terminator, location);
330 }
331 }
332
333 fn super_source_scope_data(
334 &mut self,
335 scope_data: & $($mutability)? SourceScopeData<'tcx>,
336 ) {
337 let SourceScopeData {
338 span,
339 parent_scope,
340 inlined,
341 inlined_parent_scope,
342 local_data: _,
343 } = scope_data;
344
345 self.visit_span($(& $mutability)? *span);
346 if let Some(parent_scope) = parent_scope {
347 self.visit_source_scope($(& $mutability)? *parent_scope);
348 }
349 if let Some((callee, callsite_span)) = inlined {
350 let location = Location::START;
351
352 self.visit_span($(& $mutability)? *callsite_span);
353
354 let ty::Instance { def: callee_def, args: callee_args } = callee;
355 match callee_def {
356 ty::InstanceKind::Item(_def_id) => {}
357
358 ty::InstanceKind::Intrinsic(_def_id)
359 | ty::InstanceKind::VTableShim(_def_id)
360 | ty::InstanceKind::ReifyShim(_def_id, _)
361 | ty::InstanceKind::Virtual(_def_id, _)
362 | ty::InstanceKind::ThreadLocalShim(_def_id)
363 | ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ }
364 | ty::InstanceKind::ConstructCoroutineInClosureShim {
365 coroutine_closure_def_id: _def_id,
366 receiver_by_ref: _,
367 }
368 | ty::InstanceKind::DropGlue(_def_id, None) => {}
369
370 ty::InstanceKind::FnPtrShim(_def_id, ty)
371 | ty::InstanceKind::DropGlue(_def_id, Some(ty))
372 | ty::InstanceKind::CloneShim(_def_id, ty)
373 | ty::InstanceKind::FnPtrAddrShim(_def_id, ty)
374 | ty::InstanceKind::AsyncDropGlue(_def_id, ty)
375 | ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, ty) => {
376 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
378 }
379 ty::InstanceKind::FutureDropPollShim(_def_id, proxy_ty, impl_ty) => {
380 self.visit_ty($(& $mutability)? *proxy_ty, TyContext::Location(location));
381 self.visit_ty($(& $mutability)? *impl_ty, TyContext::Location(location));
382 }
383 }
384 self.visit_args(callee_args, location);
385 }
386 if let Some(inlined_parent_scope) = inlined_parent_scope {
387 self.visit_source_scope($(& $mutability)? *inlined_parent_scope);
388 }
389 }
390
391 fn super_statement_debuginfo(
392 &mut self,
393 stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
394 location: Location
395 ) {
396 match stmt_debuginfo {
397 StmtDebugInfo::AssignRef(local, place) => {
398 self.visit_local(
399 $(& $mutability)? *local,
400 PlaceContext::NonUse(NonUseContext::VarDebugInfo),
401 location
402 );
403 self.visit_place(
404 place,
405 PlaceContext::NonUse(NonUseContext::VarDebugInfo),
406 location
407 );
408 },
409 StmtDebugInfo::InvalidAssign(local) => {
410 self.visit_local(
411 $(& $mutability)? *local,
412 PlaceContext::NonUse(NonUseContext::VarDebugInfo),
413 location
414 );
415 }
416 }
417 }
418
419 fn super_statement(
420 &mut self,
421 statement: & $($mutability)? Statement<'tcx>,
422 location: Location
423 ) {
424 let Statement { source_info, kind, debuginfos } = statement;
425
426 self.visit_source_info(source_info);
427 for debuginfo in debuginfos as & $($mutability)? [_] {
428 self.visit_statement_debuginfo(debuginfo, location);
429 }
430 match kind {
431 StatementKind::Assign(box (place, rvalue)) => {
432 self.visit_assign(place, rvalue, location);
433 }
434 StatementKind::FakeRead(box (_, place)) => {
435 self.visit_place(
436 place,
437 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
438 location
439 );
440 }
441 StatementKind::SetDiscriminant { place, .. } => {
442 self.visit_place(
443 place,
444 PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
445 location
446 );
447 }
448 StatementKind::Deinit(place) => {
449 self.visit_place(
450 place,
451 PlaceContext::MutatingUse(MutatingUseContext::Deinit),
452 location
453 )
454 }
455 StatementKind::StorageLive(local) => {
456 self.visit_local(
457 $(& $mutability)? *local,
458 PlaceContext::NonUse(NonUseContext::StorageLive),
459 location
460 );
461 }
462 StatementKind::StorageDead(local) => {
463 self.visit_local(
464 $(& $mutability)? *local,
465 PlaceContext::NonUse(NonUseContext::StorageDead),
466 location
467 );
468 }
469 StatementKind::Retag(kind, place) => {
470 self.visit_retag($(& $mutability)? *kind, place, location);
471 }
472 StatementKind::PlaceMention(place) => {
473 self.visit_place(
474 place,
475 PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention),
476 location
477 );
478 }
479 StatementKind::AscribeUserType(box (place, user_ty), variance) => {
480 self.visit_ascribe_user_ty(
481 place,
482 $(& $mutability)? *variance,
483 user_ty,
484 location
485 );
486 }
487 StatementKind::Coverage(coverage) => {
488 self.visit_coverage(
489 coverage,
490 location
491 )
492 }
493 StatementKind::Intrinsic(box intrinsic) => {
494 match intrinsic {
495 NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
496 NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
497 src,
498 dst,
499 count
500 }) => {
501 self.visit_operand(src, location);
502 self.visit_operand(dst, location);
503 self.visit_operand(count, location);
504 }
505 }
506 }
507 StatementKind::BackwardIncompatibleDropHint { place, .. } => {
508 self.visit_place(
509 place,
510 PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint),
511 location
512 );
513 }
514 StatementKind::ConstEvalCounter => {}
515 StatementKind::Nop => {}
516 }
517 }
518
519 fn super_assign(
520 &mut self,
521 place: &$($mutability)? Place<'tcx>,
522 rvalue: &$($mutability)? Rvalue<'tcx>,
523 location: Location
524 ) {
525 self.visit_place(
526 place,
527 PlaceContext::MutatingUse(MutatingUseContext::Store),
528 location
529 );
530 self.visit_rvalue(rvalue, location);
531 }
532
533 fn super_terminator(
534 &mut self,
535 terminator: &$($mutability)? Terminator<'tcx>,
536 location: Location
537 ) {
538 let Terminator { source_info, kind } = terminator;
539
540 self.visit_source_info(source_info);
541 match kind {
542 TerminatorKind::Goto { .. }
543 | TerminatorKind::UnwindResume
544 | TerminatorKind::UnwindTerminate(_)
545 | TerminatorKind::CoroutineDrop
546 | TerminatorKind::Unreachable
547 | TerminatorKind::FalseEdge { .. }
548 | TerminatorKind::FalseUnwind { .. } => {}
549
550 TerminatorKind::Return => {
551 let $($mutability)? local = RETURN_PLACE;
554 self.visit_local(
555 $(& $mutability)? local,
556 PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
557 location,
558 );
559
560 assert_eq!(
561 local,
562 RETURN_PLACE,
563 "`MutVisitor` tried to mutate return place of `return` terminator"
564 );
565 }
566
567 TerminatorKind::SwitchInt { discr, targets: _ } => {
568 self.visit_operand(discr, location);
569 }
570
571 TerminatorKind::Drop {
572 place,
573 target: _,
574 unwind: _,
575 replace: _,
576 drop: _,
577 async_fut,
578 } => {
579 self.visit_place(
580 place,
581 PlaceContext::MutatingUse(MutatingUseContext::Drop),
582 location
583 );
584 if let Some(async_fut) = async_fut {
585 self.visit_local(
586 $(&$mutability)? *async_fut,
587 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
588 location
589 );
590 }
591 }
592
593 TerminatorKind::Call {
594 func,
595 args,
596 destination,
597 target: _,
598 unwind: _,
599 call_source: _,
600 fn_span,
601 } => {
602 self.visit_span($(& $mutability)? *fn_span);
603 self.visit_operand(func, location);
604 for arg in args {
605 self.visit_operand(&$($mutability)? arg.node, location);
606 }
607 self.visit_place(
608 destination,
609 PlaceContext::MutatingUse(MutatingUseContext::Call),
610 location
611 );
612 }
613
614 TerminatorKind::TailCall { func, args, fn_span } => {
615 self.visit_span($(& $mutability)? *fn_span);
616 self.visit_operand(func, location);
617 for arg in args {
618 self.visit_operand(&$($mutability)? arg.node, location);
619 }
620 },
621
622 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
623 self.visit_operand(cond, location);
624 self.visit_assert_message(msg, location);
625 }
626
627 TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
628 self.visit_operand(value, location);
629 self.visit_place(
630 resume_arg,
631 PlaceContext::MutatingUse(MutatingUseContext::Yield),
632 location,
633 );
634 }
635
636 TerminatorKind::InlineAsm {
637 asm_macro: _,
638 template: _,
639 operands,
640 options: _,
641 line_spans: _,
642 targets: _,
643 unwind: _,
644 } => {
645 for op in operands {
646 match op {
647 InlineAsmOperand::In { value, .. } => {
648 self.visit_operand(value, location);
649 }
650 InlineAsmOperand::Out { place: Some(place), .. } => {
651 self.visit_place(
652 place,
653 PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
654 location,
655 );
656 }
657 InlineAsmOperand::InOut { in_value, out_place, .. } => {
658 self.visit_operand(in_value, location);
659 if let Some(out_place) = out_place {
660 self.visit_place(
661 out_place,
662 PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
663 location,
664 );
665 }
666 }
667 InlineAsmOperand::Const { value }
668 | InlineAsmOperand::SymFn { value } => {
669 self.visit_const_operand(value, location);
670 }
671 InlineAsmOperand::Out { place: None, .. }
672 | InlineAsmOperand::SymStatic { def_id: _ }
673 | InlineAsmOperand::Label { target_index: _ } => {}
674 }
675 }
676 }
677 }
678 }
679
680 fn super_assert_message(
681 &mut self,
682 msg: & $($mutability)? AssertMessage<'tcx>,
683 location: Location
684 ) {
685 use crate::mir::AssertKind::*;
686 match msg {
687 BoundsCheck { len, index } => {
688 self.visit_operand(len, location);
689 self.visit_operand(index, location);
690 }
691 Overflow(_, l, r) => {
692 self.visit_operand(l, location);
693 self.visit_operand(r, location);
694 }
695 OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) | InvalidEnumConstruction(op) => {
696 self.visit_operand(op, location);
697 }
698 ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference | ResumedAfterDrop(_) => {
699 }
701 MisalignedPointerDereference { required, found } => {
702 self.visit_operand(required, location);
703 self.visit_operand(found, location);
704 }
705 }
706 }
707
708 fn super_rvalue(
709 &mut self,
710 rvalue: & $($mutability)? Rvalue<'tcx>,
711 location: Location
712 ) {
713 match rvalue {
714 Rvalue::Use(operand) => {
715 self.visit_operand(operand, location);
716 }
717
718 Rvalue::Repeat(value, ct) => {
719 self.visit_operand(value, location);
720 self.visit_ty_const($(&$mutability)? *ct, location);
721 }
722
723 Rvalue::ThreadLocalRef(_) => {}
724
725 Rvalue::Ref(r, bk, path) => {
726 self.visit_region($(& $mutability)? *r, location);
727 let ctx = match bk {
728 BorrowKind::Shared => PlaceContext::NonMutatingUse(
729 NonMutatingUseContext::SharedBorrow
730 ),
731 BorrowKind::Fake(_) => PlaceContext::NonMutatingUse(
732 NonMutatingUseContext::FakeBorrow
733 ),
734 BorrowKind::Mut { .. } =>
735 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
736 };
737 self.visit_place(path, ctx, location);
738 }
739
740 Rvalue::CopyForDeref(place) => {
741 self.visit_place(
742 place,
743 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
744 location
745 );
746 }
747
748 Rvalue::RawPtr(m, path) => {
749 let ctx = match m {
750 RawPtrKind::Mut => PlaceContext::MutatingUse(
751 MutatingUseContext::RawBorrow
752 ),
753 RawPtrKind::Const => PlaceContext::NonMutatingUse(
754 NonMutatingUseContext::RawBorrow
755 ),
756 RawPtrKind::FakeForPtrMetadata => PlaceContext::NonMutatingUse(
757 NonMutatingUseContext::Inspect
758 ),
759 };
760 self.visit_place(path, ctx, location);
761 }
762
763 Rvalue::Cast(_cast_kind, operand, ty) => {
764 self.visit_operand(operand, location);
765 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
766 }
767
768 Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) => {
769 self.visit_operand(lhs, location);
770 self.visit_operand(rhs, location);
771 }
772
773 Rvalue::UnaryOp(_un_op, op) => {
774 self.visit_operand(op, location);
775 }
776
777 Rvalue::Discriminant(place) => {
778 self.visit_place(
779 place,
780 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
781 location
782 );
783 }
784
785 Rvalue::NullaryOp(_op, ty) => {
786 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
787 }
788
789 Rvalue::Aggregate(kind, operands) => {
790 let kind = &$($mutability)? **kind;
791 match kind {
792 AggregateKind::Array(ty) => {
793 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
794 }
795 AggregateKind::Tuple => {}
796 AggregateKind::Adt(
797 _adt_def,
798 _variant_index,
799 args,
800 _user_args,
801 _active_field_index
802 ) => {
803 self.visit_args(args, location);
804 }
805 AggregateKind::Closure(_, closure_args) => {
806 self.visit_args(closure_args, location);
807 }
808 AggregateKind::Coroutine(_, coroutine_args) => {
809 self.visit_args(coroutine_args, location);
810 }
811 AggregateKind::CoroutineClosure(_, coroutine_closure_args) => {
812 self.visit_args(coroutine_closure_args, location);
813 }
814 AggregateKind::RawPtr(ty, _) => {
815 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
816 }
817 }
818
819 for operand in operands {
820 self.visit_operand(operand, location);
821 }
822 }
823
824 Rvalue::ShallowInitBox(operand, ty) => {
825 self.visit_operand(operand, location);
826 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
827 }
828
829 Rvalue::WrapUnsafeBinder(op, ty) => {
830 self.visit_operand(op, location);
831 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
832 }
833 }
834 }
835
836 fn super_operand(
837 &mut self,
838 operand: & $($mutability)? Operand<'tcx>,
839 location: Location
840 ) {
841 match operand {
842 Operand::Copy(place) => {
843 self.visit_place(
844 place,
845 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
846 location
847 );
848 }
849 Operand::Move(place) => {
850 self.visit_place(
851 place,
852 PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
853 location
854 );
855 }
856 Operand::Constant(constant) => {
857 self.visit_const_operand(constant, location);
858 }
859 }
860 }
861
862 fn super_ascribe_user_ty(
863 &mut self,
864 place: & $($mutability)? Place<'tcx>,
865 variance: $(& $mutability)? ty::Variance,
866 user_ty: & $($mutability)? UserTypeProjection,
867 location: Location)
868 {
869 self.visit_place(
870 place,
871 PlaceContext::NonUse(
872 NonUseContext::AscribeUserTy($(* &$mutability *)? variance)
873 ),
874 location
875 );
876 self.visit_user_type_projection(user_ty);
877 }
878
879 fn super_coverage(
880 &mut self,
881 _kind: & $($mutability)? coverage::CoverageKind,
882 _location: Location
883 ) {
884 }
885
886 fn super_retag(
887 &mut self,
888 _kind: $(& $mutability)? RetagKind,
889 place: & $($mutability)? Place<'tcx>,
890 location: Location
891 ) {
892 self.visit_place(
893 place,
894 PlaceContext::MutatingUse(MutatingUseContext::Retag),
895 location,
896 );
897 }
898
899 fn super_local_decl(
900 &mut self,
901 local: Local,
902 local_decl: & $($mutability)? LocalDecl<'tcx>
903 ) {
904 let LocalDecl {
905 mutability: _,
906 ty,
907 user_ty,
908 source_info,
909 local_info: _,
910 } = local_decl;
911
912 self.visit_source_info(source_info);
913
914 self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
915 local,
916 source_info: *source_info,
917 });
918 if let Some(user_ty) = user_ty {
919 for user_ty in & $($mutability)? user_ty.contents {
920 self.visit_user_type_projection(user_ty);
921 }
922 }
923 }
924
925 fn super_local(
926 &mut self,
927 _local: $(& $mutability)? Local,
928 _context: PlaceContext,
929 _location: Location,
930 ) {
931 }
932
933 fn super_var_debug_info(
934 &mut self,
935 var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
936 ) {
937 let VarDebugInfo {
938 name: _,
939 source_info,
940 composite,
941 value,
942 argument_index: _,
943 } = var_debug_info;
944
945 self.visit_source_info(source_info);
946 let location = Location::START;
947 if let Some(box VarDebugInfoFragment {
948 ty,
949 projection
950 }) = composite {
951 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
952 for elem in projection {
953 let ProjectionElem::Field(_, ty) = elem else { bug!() };
954 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
955 }
956 }
957 match value {
958 VarDebugInfoContents::Const(c) => self.visit_const_operand(c, location),
959 VarDebugInfoContents::Place(place) =>
960 self.visit_place(
961 place,
962 PlaceContext::NonUse(NonUseContext::VarDebugInfo),
963 location
964 ),
965 }
966 }
967
968 fn super_source_scope(&mut self, _scope: $(& $mutability)? SourceScope) {}
969
970 fn super_const_operand(
971 &mut self,
972 constant: & $($mutability)? ConstOperand<'tcx>,
973 location: Location
974 ) {
975 let ConstOperand {
976 span,
977 user_ty: _, const_,
979 } = constant;
980
981 self.visit_span($(& $mutability)? *span);
982 match const_ {
983 Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location),
984 Const::Val(_, ty) => {
985 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
986 }
987 Const::Unevaluated(_, ty) => {
988 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
989 }
990 }
991 }
992
993 fn super_ty_const(
994 &mut self,
995 _ct: $(& $mutability)? ty::Const<'tcx>,
996 _location: Location,
997 ) {
998 }
999
1000 fn super_span(&mut self, _span: $(& $mutability)? Span) {}
1001
1002 fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
1003 let SourceInfo { span, scope } = source_info;
1004
1005 self.visit_span($(& $mutability)? *span);
1006 self.visit_source_scope($(& $mutability)? *scope);
1007 }
1008
1009 fn super_user_type_projection(&mut self, _ty: & $($mutability)? UserTypeProjection) {}
1010
1011 fn super_user_type_annotation(
1012 &mut self,
1013 _index: UserTypeAnnotationIndex,
1014 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
1015 ) {
1016 self.visit_span($(& $mutability)? ty.span);
1017 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
1018 }
1019
1020 fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {}
1021
1022 fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {}
1023
1024 fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) {}
1025
1026 fn visit_location(
1029 &mut self,
1030 body: &$($mutability)? Body<'tcx>,
1031 location: Location
1032 ) {
1033 let basic_block =
1034 & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
1035 if basic_block.statements.len() == location.statement_index {
1036 if let Some(ref $($mutability)? terminator) = basic_block.terminator {
1037 self.visit_terminator(terminator, location)
1038 }
1039 } else {
1040 let statement = & $($mutability)?
1041 basic_block.statements[location.statement_index];
1042 self.visit_statement(statement, location)
1043 }
1044 }
1045 }
1046 }
1047}
1048
1049macro_rules! basic_blocks {
1050 ($body:ident, mut, true) => {
1051 $body.basic_blocks.as_mut()
1052 };
1053 ($body:ident, mut, false) => {
1054 $body.basic_blocks.as_mut_preserves_cfg()
1055 };
1056 ($body:ident,) => {
1057 $body.basic_blocks
1058 };
1059}
1060
1061macro_rules! basic_blocks_iter {
1062 ($body:ident, mut, $invalidate:tt) => {
1063 basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
1064 };
1065 ($body:ident,) => {
1066 basic_blocks!($body,).iter_enumerated()
1067 };
1068}
1069
1070macro_rules! extra_body_methods {
1071 (mut) => {
1072 fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
1073 self.super_body_preserves_cfg(body);
1074 }
1075
1076 fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
1077 super_body!(self, body, mut, false);
1078 }
1079 };
1080 () => {};
1081}
1082
1083macro_rules! super_body {
1084 ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
1085 let span = $body.span;
1086 if let Some(coroutine) = &$($mutability)? $body.coroutine {
1087 if let Some(yield_ty) = $(& $mutability)? coroutine.yield_ty {
1088 $self.visit_ty(
1089 yield_ty,
1090 TyContext::YieldTy(SourceInfo::outermost(span))
1091 );
1092 }
1093 if let Some(resume_ty) = $(& $mutability)? coroutine.resume_ty {
1094 $self.visit_ty(
1095 resume_ty,
1096 TyContext::ResumeTy(SourceInfo::outermost(span))
1097 );
1098 }
1099 }
1100
1101 for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
1102 $self.visit_basic_block_data(bb, data);
1103 }
1104
1105 for scope in &$($mutability)? $body.source_scopes {
1106 $self.visit_source_scope_data(scope);
1107 }
1108
1109 $self.visit_ty(
1110 $(& $mutability)? $body.return_ty(),
1111 TyContext::ReturnTy(SourceInfo::outermost($body.span))
1112 );
1113
1114 for local in $body.local_decls.indices() {
1115 $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
1116 }
1117
1118 #[allow(unused_macro_rules)]
1119 macro_rules! type_annotations {
1120 (mut) => ($body.user_type_annotations.iter_enumerated_mut());
1121 () => ($body.user_type_annotations.iter_enumerated());
1122 }
1123
1124 for (index, annotation) in type_annotations!($($mutability)?) {
1125 $self.visit_user_type_annotation(
1126 index, annotation
1127 );
1128 }
1129
1130 for var_debug_info in &$($mutability)? $body.var_debug_info {
1131 $self.visit_var_debug_info(var_debug_info);
1132 }
1133
1134 $self.visit_span($(& $mutability)? $body.span);
1135
1136 if let Some(required_consts) = &$($mutability)? $body.required_consts {
1137 for const_ in required_consts {
1138 let location = Location::START;
1139 $self.visit_const_operand(const_, location);
1140 }
1141 }
1142 }
1143}
1144
1145macro_rules! visit_place_fns {
1146 (mut) => {
1147 fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
1148
1149 fn super_place(
1150 &mut self,
1151 place: &mut Place<'tcx>,
1152 context: PlaceContext,
1153 location: Location,
1154 ) {
1155 self.visit_local(&mut place.local, context, location);
1156
1157 if let Some(new_projection) = self.process_projection(&place.projection, location) {
1158 place.projection = self.tcx().mk_place_elems(&new_projection);
1159 }
1160 }
1161
1162 fn process_projection<'a>(
1163 &mut self,
1164 projection: &'a [PlaceElem<'tcx>],
1165 location: Location,
1166 ) -> Option<Vec<PlaceElem<'tcx>>> {
1167 let mut projection = Cow::Borrowed(projection);
1168
1169 for i in 0..projection.len() {
1170 if let Some(&elem) = projection.get(i) {
1171 if let Some(elem) = self.process_projection_elem(elem, location) {
1172 let vec = projection.to_mut();
1175 vec[i] = elem;
1176 }
1177 }
1178 }
1179
1180 match projection {
1181 Cow::Borrowed(_) => None,
1182 Cow::Owned(vec) => Some(vec),
1183 }
1184 }
1185
1186 fn process_projection_elem(
1187 &mut self,
1188 elem: PlaceElem<'tcx>,
1189 location: Location,
1190 ) -> Option<PlaceElem<'tcx>> {
1191 match elem {
1192 PlaceElem::Index(local) => {
1193 let mut new_local = local;
1194 self.visit_local(
1195 &mut new_local,
1196 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
1197 location,
1198 );
1199
1200 if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
1201 }
1202 PlaceElem::Field(field, ty) => {
1203 let mut new_ty = ty;
1204 self.visit_ty(&mut new_ty, TyContext::Location(location));
1205 if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
1206 }
1207 PlaceElem::OpaqueCast(ty) => {
1208 let mut new_ty = ty;
1209 self.visit_ty(&mut new_ty, TyContext::Location(location));
1210 if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
1211 }
1212 PlaceElem::UnwrapUnsafeBinder(ty) => {
1213 let mut new_ty = ty;
1214 self.visit_ty(&mut new_ty, TyContext::Location(location));
1215 if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
1216 }
1217 PlaceElem::Deref
1218 | PlaceElem::ConstantIndex { .. }
1219 | PlaceElem::Subslice { .. }
1220 | PlaceElem::Downcast(..) => None,
1221 }
1222 }
1223 };
1224
1225 () => {
1226 fn visit_projection(
1227 &mut self,
1228 place_ref: PlaceRef<'tcx>,
1229 context: PlaceContext,
1230 location: Location,
1231 ) {
1232 self.super_projection(place_ref, context, location);
1233 }
1234
1235 fn visit_projection_elem(
1236 &mut self,
1237 place_ref: PlaceRef<'tcx>,
1238 elem: PlaceElem<'tcx>,
1239 context: PlaceContext,
1240 location: Location,
1241 ) {
1242 self.super_projection_elem(place_ref, elem, context, location);
1243 }
1244
1245 fn super_place(
1246 &mut self,
1247 place: &Place<'tcx>,
1248 mut context: PlaceContext,
1249 location: Location,
1250 ) {
1251 if !place.projection.is_empty() && context.is_use() {
1252 context = if context.is_mutating_use() {
1254 PlaceContext::MutatingUse(MutatingUseContext::Projection)
1255 } else {
1256 PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
1257 };
1258 }
1259
1260 self.visit_local(place.local, context, location);
1261
1262 self.visit_projection(place.as_ref(), context, location);
1263 }
1264
1265 fn super_projection(
1266 &mut self,
1267 place_ref: PlaceRef<'tcx>,
1268 context: PlaceContext,
1269 location: Location,
1270 ) {
1271 for (base, elem) in place_ref.iter_projections().rev() {
1272 self.visit_projection_elem(base, elem, context, location);
1273 }
1274 }
1275
1276 fn super_projection_elem(
1277 &mut self,
1278 _place_ref: PlaceRef<'tcx>,
1279 elem: PlaceElem<'tcx>,
1280 context: PlaceContext,
1281 location: Location,
1282 ) {
1283 match elem {
1284 ProjectionElem::OpaqueCast(ty)
1285 | ProjectionElem::Field(_, ty)
1286 | ProjectionElem::UnwrapUnsafeBinder(ty) => {
1287 self.visit_ty(ty, TyContext::Location(location));
1288 }
1289 ProjectionElem::Index(local) => {
1290 self.visit_local(
1291 local,
1292 if context.is_use() {
1293 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy)
1295 } else {
1296 context
1297 },
1298 location,
1299 );
1300 }
1301 ProjectionElem::Deref
1302 | ProjectionElem::Subslice { from: _, to: _, from_end: _ }
1303 | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
1304 | ProjectionElem::Downcast(_, _) => {}
1305 }
1306 }
1307 };
1308}
1309
1310make_mir_visitor!(Visitor,);
1311make_mir_visitor!(MutVisitor, mut);
1312
1313#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1316pub enum TyContext {
1317 LocalDecl {
1318 local: Local,
1320
1321 source_info: SourceInfo,
1323 },
1324
1325 UserTy(Span),
1327
1328 ReturnTy(SourceInfo),
1330
1331 YieldTy(SourceInfo),
1332
1333 ResumeTy(SourceInfo),
1334
1335 Location(Location),
1337}
1338
1339#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1340pub enum NonMutatingUseContext {
1341 Inspect,
1343 Copy,
1345 Move,
1347 SharedBorrow,
1349 FakeBorrow,
1353 RawBorrow,
1355 PlaceMention,
1360 Projection,
1367}
1368
1369#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1370pub enum MutatingUseContext {
1371 Store,
1373 SetDiscriminant,
1375 Deinit,
1377 AsmOutput,
1379 Call,
1381 Yield,
1383 Drop,
1385 Borrow,
1387 RawBorrow,
1389 Projection,
1396 Retag,
1398}
1399
1400#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1401pub enum NonUseContext {
1402 StorageLive,
1404 StorageDead,
1406 AscribeUserTy(ty::Variance),
1408 VarDebugInfo,
1410 BackwardIncompatibleDropHint,
1412}
1413
1414#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1415pub enum PlaceContext {
1416 NonMutatingUse(NonMutatingUseContext),
1417 MutatingUse(MutatingUseContext),
1418 NonUse(NonUseContext),
1419}
1420
1421impl PlaceContext {
1422 #[inline]
1424 pub fn is_drop(self) -> bool {
1425 matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
1426 }
1427
1428 pub fn is_borrow(self) -> bool {
1431 matches!(
1432 self,
1433 PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
1434 | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
1435 )
1436 }
1437
1438 pub fn is_address_of(self) -> bool {
1440 matches!(
1441 self,
1442 PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow)
1443 | PlaceContext::MutatingUse(MutatingUseContext::RawBorrow)
1444 )
1445 }
1446
1447 #[inline]
1449 pub fn may_observe_address(self) -> bool {
1450 matches!(
1451 self,
1452 PlaceContext::NonMutatingUse(
1453 NonMutatingUseContext::SharedBorrow
1454 | NonMutatingUseContext::RawBorrow
1455 | NonMutatingUseContext::FakeBorrow
1456 ) | PlaceContext::MutatingUse(
1457 MutatingUseContext::Drop
1458 | MutatingUseContext::Borrow
1459 | MutatingUseContext::RawBorrow
1460 | MutatingUseContext::AsmOutput
1461 )
1462 )
1463 }
1464
1465 #[inline]
1467 pub fn is_storage_marker(self) -> bool {
1468 matches!(
1469 self,
1470 PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
1471 )
1472 }
1473
1474 #[inline]
1476 pub fn is_mutating_use(self) -> bool {
1477 matches!(self, PlaceContext::MutatingUse(..))
1478 }
1479
1480 #[inline]
1482 pub fn is_use(self) -> bool {
1483 !matches!(self, PlaceContext::NonUse(..))
1484 }
1485
1486 pub fn is_place_assignment(self) -> bool {
1488 matches!(
1489 self,
1490 PlaceContext::MutatingUse(
1491 MutatingUseContext::Store
1492 | MutatingUseContext::Call
1493 | MutatingUseContext::AsmOutput,
1494 )
1495 )
1496 }
1497
1498 pub fn ambient_variance(self) -> ty::Variance {
1500 use NonMutatingUseContext::*;
1501 use NonUseContext::*;
1502 match self {
1503 PlaceContext::MutatingUse(_) => ty::Invariant,
1504 PlaceContext::NonUse(
1505 StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint,
1506 ) => ty::Invariant,
1507 PlaceContext::NonMutatingUse(
1508 Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow
1509 | Projection,
1510 ) => ty::Covariant,
1511 PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
1512 }
1513 }
1514}
1515
1516pub struct VisitPlacesWith<F>(pub F);
1518
1519impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
1520where
1521 F: FnMut(Place<'tcx>, PlaceContext),
1522{
1523 fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
1524 (self.0)(local.into(), ctxt);
1525 }
1526
1527 fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
1528 (self.0)(*place, ctxt);
1529 self.visit_projection(place.as_ref(), ctxt, location);
1530 }
1531}