1 //! # The MIR Visitor 2 //! 3 //! ## Overview 4 //! 5 //! There are two visitors, one for immutable and one for mutable references, 6 //! but both are generated by the `make_mir_visitor` macro. 7 //! The code is written according to the following conventions: 8 //! 9 //! - introduce a `visit_foo` and a `super_foo` method for every MIR type 10 //! - `visit_foo`, by default, calls `super_foo` 11 //! - `super_foo`, by default, destructures the `foo` and calls `visit_foo` 12 //! 13 //! This allows you to override `visit_foo` for types you are 14 //! interested in, and invoke (within that method call) 15 //! `self.super_foo` to get the default behavior. Just as in an OO 16 //! language, you should never call `super` methods ordinarily except 17 //! in that circumstance. 18 //! 19 //! For the most part, we do not destructure things external to the 20 //! MIR, e.g., types, spans, etc, but simply visit them and stop. This 21 //! avoids duplication with other visitors like `TypeFoldable`. 22 //! 23 //! ## Updating 24 //! 25 //! The code is written in a very deliberate style intended to minimize 26 //! the chance of things being overlooked. You'll notice that we always 27 //! use pattern matching to reference fields and we ensure that all 28 //! matches are exhaustive. 29 //! 30 //! For example, the `super_basic_block_data` method begins like this: 31 //! 32 //! ```ignore (pseudo-rust) 33 //! fn super_basic_block_data( 34 //! &mut self, 35 //! block: BasicBlock, 36 //! data: & $($mutability)? BasicBlockData<'tcx> 37 //! ) { 38 //! let BasicBlockData { 39 //! statements, 40 //! terminator, 41 //! is_cleanup: _ 42 //! } = *data; 43 //! 44 //! for statement in statements { 45 //! self.visit_statement(block, statement); 46 //! } 47 //! 48 //! ... 49 //! } 50 //! ``` 51 //! 52 //! Here we used `let BasicBlockData { <fields> } = *data` deliberately, 53 //! rather than writing `data.statements` in the body. This is because if one 54 //! adds a new field to `BasicBlockData`, one will be forced to revise this code, 55 //! and hence one will (hopefully) invoke the correct visit methods (if any). 56 //! 57 //! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. 58 //! That means you never write `..` to skip over fields, nor do you write `_` 59 //! to skip over variants in a `match`. 60 //! 61 //! The only place that `_` is acceptable is to match a field (or 62 //! variant argument) that does not require visiting, as in 63 //! `is_cleanup` above. 64 65 use crate::mir::*; 66 use crate::ty::subst::SubstsRef; 67 use crate::ty::{self, CanonicalUserTypeAnnotation, Ty}; 68 use rustc_span::Span; 69 70 macro_rules! make_mir_visitor { 71 ($visitor_trait_name:ident, $($mutability:ident)?) => { 72 pub trait $visitor_trait_name<'tcx> { 73 // Override these, and call `self.super_xxx` to revert back to the 74 // default behavior. 75 76 fn visit_body( 77 &mut self, 78 body: &$($mutability)? Body<'tcx>, 79 ) { 80 self.super_body(body); 81 } 82 83 extra_body_methods!($($mutability)?); 84 85 fn visit_basic_block_data( 86 &mut self, 87 block: BasicBlock, 88 data: & $($mutability)? BasicBlockData<'tcx>, 89 ) { 90 self.super_basic_block_data(block, data); 91 } 92 93 fn visit_source_scope_data( 94 &mut self, 95 scope_data: & $($mutability)? SourceScopeData<'tcx>, 96 ) { 97 self.super_source_scope_data(scope_data); 98 } 99 100 fn visit_statement( 101 &mut self, 102 statement: & $($mutability)? Statement<'tcx>, 103 location: Location, 104 ) { 105 self.super_statement(statement, location); 106 } 107 108 fn visit_assign( 109 &mut self, 110 place: & $($mutability)? Place<'tcx>, 111 rvalue: & $($mutability)? Rvalue<'tcx>, 112 location: Location, 113 ) { 114 self.super_assign(place, rvalue, location); 115 } 116 117 fn visit_terminator( 118 &mut self, 119 terminator: & $($mutability)? Terminator<'tcx>, 120 location: Location, 121 ) { 122 self.super_terminator(terminator, location); 123 } 124 125 fn visit_assert_message( 126 &mut self, 127 msg: & $($mutability)? AssertMessage<'tcx>, 128 location: Location, 129 ) { 130 self.super_assert_message(msg, location); 131 } 132 133 fn visit_rvalue( 134 &mut self, 135 rvalue: & $($mutability)? Rvalue<'tcx>, 136 location: Location, 137 ) { 138 self.super_rvalue(rvalue, location); 139 } 140 141 fn visit_operand( 142 &mut self, 143 operand: & $($mutability)? Operand<'tcx>, 144 location: Location, 145 ) { 146 self.super_operand(operand, location); 147 } 148 149 fn visit_ascribe_user_ty( 150 &mut self, 151 place: & $($mutability)? Place<'tcx>, 152 variance: $(& $mutability)? ty::Variance, 153 user_ty: & $($mutability)? UserTypeProjection, 154 location: Location, 155 ) { 156 self.super_ascribe_user_ty(place, variance, user_ty, location); 157 } 158 159 fn visit_coverage( 160 &mut self, 161 coverage: & $($mutability)? Coverage, 162 location: Location, 163 ) { 164 self.super_coverage(coverage, location); 165 } 166 167 fn visit_retag( 168 &mut self, 169 kind: $(& $mutability)? RetagKind, 170 place: & $($mutability)? Place<'tcx>, 171 location: Location, 172 ) { 173 self.super_retag(kind, place, location); 174 } 175 176 fn visit_place( 177 &mut self, 178 place: & $($mutability)? Place<'tcx>, 179 context: PlaceContext, 180 location: Location, 181 ) { 182 self.super_place(place, context, location); 183 } 184 185 visit_place_fns!($($mutability)?); 186 187 fn visit_constant( 188 &mut self, 189 constant: & $($mutability)? Constant<'tcx>, 190 location: Location, 191 ) { 192 self.super_constant(constant, location); 193 } 194 195 fn visit_ty_const( 196 &mut self, 197 ct: $( & $mutability)? ty::Const<'tcx>, 198 location: Location, 199 ) { 200 self.super_ty_const(ct, location); 201 } 202 203 fn visit_span( 204 &mut self, 205 span: $(& $mutability)? Span, 206 ) { 207 self.super_span(span); 208 } 209 210 fn visit_source_info( 211 &mut self, 212 source_info: & $($mutability)? SourceInfo, 213 ) { 214 self.super_source_info(source_info); 215 } 216 217 fn visit_ty( 218 &mut self, 219 ty: $(& $mutability)? Ty<'tcx>, 220 _: TyContext, 221 ) { 222 self.super_ty(ty); 223 } 224 225 fn visit_user_type_projection( 226 &mut self, 227 ty: & $($mutability)? UserTypeProjection, 228 ) { 229 self.super_user_type_projection(ty); 230 } 231 232 fn visit_user_type_annotation( 233 &mut self, 234 index: UserTypeAnnotationIndex, 235 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, 236 ) { 237 self.super_user_type_annotation(index, ty); 238 } 239 240 fn visit_region( 241 &mut self, 242 region: $(& $mutability)? ty::Region<'tcx>, 243 _: Location, 244 ) { 245 self.super_region(region); 246 } 247 248 fn visit_substs( 249 &mut self, 250 substs: & $($mutability)? SubstsRef<'tcx>, 251 _: Location, 252 ) { 253 self.super_substs(substs); 254 } 255 256 fn visit_local_decl( 257 &mut self, 258 local: Local, 259 local_decl: & $($mutability)? LocalDecl<'tcx>, 260 ) { 261 self.super_local_decl(local, local_decl); 262 } 263 264 fn visit_var_debug_info( 265 &mut self, 266 var_debug_info: & $($mutability)* VarDebugInfo<'tcx>, 267 ) { 268 self.super_var_debug_info(var_debug_info); 269 } 270 271 fn visit_local( 272 &mut self, 273 _local: $(& $mutability)? Local, 274 _context: PlaceContext, 275 _location: Location, 276 ) {} 277 278 fn visit_source_scope( 279 &mut self, 280 scope: $(& $mutability)? SourceScope, 281 ) { 282 self.super_source_scope(scope); 283 } 284 285 // The `super_xxx` methods comprise the default behavior and are 286 // not meant to be overridden. 287 288 fn super_body( 289 &mut self, 290 body: &$($mutability)? Body<'tcx>, 291 ) { 292 super_body!(self, body, $($mutability, true)?); 293 } 294 295 fn super_basic_block_data(&mut self, 296 block: BasicBlock, 297 data: & $($mutability)? BasicBlockData<'tcx>) { 298 let BasicBlockData { 299 statements, 300 terminator, 301 is_cleanup: _ 302 } = data; 303 304 let mut index = 0; 305 for statement in statements { 306 let location = Location { block, statement_index: index }; 307 self.visit_statement(statement, location); 308 index += 1; 309 } 310 311 if let Some(terminator) = terminator { 312 let location = Location { block, statement_index: index }; 313 self.visit_terminator(terminator, location); 314 } 315 } 316 317 fn super_source_scope_data( 318 &mut self, 319 scope_data: & $($mutability)? SourceScopeData<'tcx>, 320 ) { 321 let SourceScopeData { 322 span, 323 parent_scope, 324 inlined, 325 inlined_parent_scope, 326 local_data: _, 327 } = scope_data; 328 329 self.visit_span($(& $mutability)? *span); 330 if let Some(parent_scope) = parent_scope { 331 self.visit_source_scope($(& $mutability)? *parent_scope); 332 } 333 if let Some((callee, callsite_span)) = inlined { 334 let location = Location::START; 335 336 self.visit_span($(& $mutability)? *callsite_span); 337 338 let ty::Instance { def: callee_def, substs: callee_substs } = callee; 339 match callee_def { 340 ty::InstanceDef::Item(_def_id) => {} 341 342 ty::InstanceDef::Intrinsic(_def_id) | 343 ty::InstanceDef::VTableShim(_def_id) | 344 ty::InstanceDef::ReifyShim(_def_id) | 345 ty::InstanceDef::Virtual(_def_id, _) | 346 ty::InstanceDef::ThreadLocalShim(_def_id) | 347 ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | 348 ty::InstanceDef::DropGlue(_def_id, None) => {} 349 350 ty::InstanceDef::FnPtrShim(_def_id, ty) | 351 ty::InstanceDef::DropGlue(_def_id, Some(ty)) | 352 ty::InstanceDef::CloneShim(_def_id, ty) | 353 ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => { 354 // FIXME(eddyb) use a better `TyContext` here. 355 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 356 } 357 } 358 self.visit_substs(callee_substs, location); 359 } 360 if let Some(inlined_parent_scope) = inlined_parent_scope { 361 self.visit_source_scope($(& $mutability)? *inlined_parent_scope); 362 } 363 } 364 365 fn super_statement(&mut self, 366 statement: & $($mutability)? Statement<'tcx>, 367 location: Location) { 368 let Statement { 369 source_info, 370 kind, 371 } = statement; 372 373 self.visit_source_info(source_info); 374 match kind { 375 StatementKind::Assign( 376 box (place, rvalue) 377 ) => { 378 self.visit_assign(place, rvalue, location); 379 } 380 StatementKind::FakeRead(box (_, place)) => { 381 self.visit_place( 382 place, 383 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), 384 location 385 ); 386 } 387 StatementKind::SetDiscriminant { place, .. } => { 388 self.visit_place( 389 place, 390 PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant), 391 location 392 ); 393 } 394 StatementKind::Deinit(place) => { 395 self.visit_place( 396 place, 397 PlaceContext::MutatingUse(MutatingUseContext::Deinit), 398 location 399 ) 400 } 401 StatementKind::StorageLive(local) => { 402 self.visit_local( 403 $(& $mutability)? *local, 404 PlaceContext::NonUse(NonUseContext::StorageLive), 405 location 406 ); 407 } 408 StatementKind::StorageDead(local) => { 409 self.visit_local( 410 $(& $mutability)? *local, 411 PlaceContext::NonUse(NonUseContext::StorageDead), 412 location 413 ); 414 } 415 StatementKind::Retag(kind, place) => { 416 self.visit_retag($(& $mutability)? *kind, place, location); 417 } 418 StatementKind::PlaceMention(place) => { 419 self.visit_place( 420 place, 421 PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention), 422 location 423 ); 424 } 425 StatementKind::AscribeUserType( 426 box (place, user_ty), 427 variance 428 ) => { 429 self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location); 430 } 431 StatementKind::Coverage(coverage) => { 432 self.visit_coverage( 433 coverage, 434 location 435 ) 436 } 437 StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { 438 match intrinsic { 439 NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), 440 NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { 441 self.visit_operand(src, location); 442 self.visit_operand(dst, location); 443 self.visit_operand(count, location); 444 } 445 } 446 } 447 StatementKind::ConstEvalCounter => {} 448 StatementKind::Nop => {} 449 } 450 } 451 452 fn super_assign(&mut self, 453 place: &$($mutability)? Place<'tcx>, 454 rvalue: &$($mutability)? Rvalue<'tcx>, 455 location: Location) { 456 self.visit_place( 457 place, 458 PlaceContext::MutatingUse(MutatingUseContext::Store), 459 location 460 ); 461 self.visit_rvalue(rvalue, location); 462 } 463 464 fn super_terminator(&mut self, 465 terminator: &$($mutability)? Terminator<'tcx>, 466 location: Location) { 467 let Terminator { source_info, kind } = terminator; 468 469 self.visit_source_info(source_info); 470 match kind { 471 TerminatorKind::Goto { .. } | 472 TerminatorKind::Resume | 473 TerminatorKind::Terminate | 474 TerminatorKind::GeneratorDrop | 475 TerminatorKind::Unreachable | 476 TerminatorKind::FalseEdge { .. } | 477 TerminatorKind::FalseUnwind { .. } => {} 478 479 TerminatorKind::Return => { 480 // `return` logically moves from the return place `_0`. Note that the place 481 // cannot be changed by any visitor, though. 482 let $($mutability)? local = RETURN_PLACE; 483 self.visit_local( 484 $(& $mutability)? local, 485 PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), 486 location, 487 ); 488 489 assert_eq!( 490 local, 491 RETURN_PLACE, 492 "`MutVisitor` tried to mutate return place of `return` terminator" 493 ); 494 } 495 496 TerminatorKind::SwitchInt { 497 discr, 498 targets: _ 499 } => { 500 self.visit_operand(discr, location); 501 } 502 503 TerminatorKind::Drop { 504 place, 505 target: _, 506 unwind: _, 507 replace: _, 508 } => { 509 self.visit_place( 510 place, 511 PlaceContext::MutatingUse(MutatingUseContext::Drop), 512 location 513 ); 514 } 515 516 TerminatorKind::Call { 517 func, 518 args, 519 destination, 520 target: _, 521 unwind: _, 522 call_source: _, 523 fn_span: _ 524 } => { 525 self.visit_operand(func, location); 526 for arg in args { 527 self.visit_operand(arg, location); 528 } 529 self.visit_place( 530 destination, 531 PlaceContext::MutatingUse(MutatingUseContext::Call), 532 location 533 ); 534 } 535 536 TerminatorKind::Assert { 537 cond, 538 expected: _, 539 msg, 540 target: _, 541 unwind: _, 542 } => { 543 self.visit_operand(cond, location); 544 self.visit_assert_message(msg, location); 545 } 546 547 TerminatorKind::Yield { 548 value, 549 resume: _, 550 resume_arg, 551 drop: _, 552 } => { 553 self.visit_operand(value, location); 554 self.visit_place( 555 resume_arg, 556 PlaceContext::MutatingUse(MutatingUseContext::Yield), 557 location, 558 ); 559 } 560 561 TerminatorKind::InlineAsm { 562 template: _, 563 operands, 564 options: _, 565 line_spans: _, 566 destination: _, 567 unwind: _, 568 } => { 569 for op in operands { 570 match op { 571 InlineAsmOperand::In { value, .. } => { 572 self.visit_operand(value, location); 573 } 574 InlineAsmOperand::Out { place: Some(place), .. } => { 575 self.visit_place( 576 place, 577 PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), 578 location, 579 ); 580 } 581 InlineAsmOperand::InOut { in_value, out_place, .. } => { 582 self.visit_operand(in_value, location); 583 if let Some(out_place) = out_place { 584 self.visit_place( 585 out_place, 586 PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), 587 location, 588 ); 589 } 590 } 591 InlineAsmOperand::Const { value } 592 | InlineAsmOperand::SymFn { value } => { 593 self.visit_constant(value, location); 594 } 595 InlineAsmOperand::Out { place: None, .. } 596 | InlineAsmOperand::SymStatic { def_id: _ } => {} 597 } 598 } 599 } 600 } 601 } 602 603 fn super_assert_message(&mut self, 604 msg: & $($mutability)? AssertMessage<'tcx>, 605 location: Location) { 606 use crate::mir::AssertKind::*; 607 match msg { 608 BoundsCheck { len, index } => { 609 self.visit_operand(len, location); 610 self.visit_operand(index, location); 611 } 612 Overflow(_, l, r) => { 613 self.visit_operand(l, location); 614 self.visit_operand(r, location); 615 } 616 OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { 617 self.visit_operand(op, location); 618 } 619 ResumedAfterReturn(_) | ResumedAfterPanic(_) => { 620 // Nothing to visit 621 } 622 MisalignedPointerDereference { required, found } => { 623 self.visit_operand(required, location); 624 self.visit_operand(found, location); 625 } 626 } 627 } 628 629 fn super_rvalue(&mut self, 630 rvalue: & $($mutability)? Rvalue<'tcx>, 631 location: Location) { 632 match rvalue { 633 Rvalue::Use(operand) => { 634 self.visit_operand(operand, location); 635 } 636 637 Rvalue::Repeat(value, ct) => { 638 self.visit_operand(value, location); 639 self.visit_ty_const($(&$mutability)? *ct, location); 640 } 641 642 Rvalue::ThreadLocalRef(_) => {} 643 644 Rvalue::Ref(r, bk, path) => { 645 self.visit_region($(& $mutability)? *r, location); 646 let ctx = match bk { 647 BorrowKind::Shared => PlaceContext::NonMutatingUse( 648 NonMutatingUseContext::SharedBorrow 649 ), 650 BorrowKind::Shallow => PlaceContext::NonMutatingUse( 651 NonMutatingUseContext::ShallowBorrow 652 ), 653 BorrowKind::Mut { .. } => 654 PlaceContext::MutatingUse(MutatingUseContext::Borrow), 655 }; 656 self.visit_place(path, ctx, location); 657 } 658 Rvalue::CopyForDeref(place) => { 659 self.visit_place( 660 place, 661 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), 662 location 663 ); 664 } 665 666 Rvalue::AddressOf(m, path) => { 667 let ctx = match m { 668 Mutability::Mut => PlaceContext::MutatingUse( 669 MutatingUseContext::AddressOf 670 ), 671 Mutability::Not => PlaceContext::NonMutatingUse( 672 NonMutatingUseContext::AddressOf 673 ), 674 }; 675 self.visit_place(path, ctx, location); 676 } 677 678 Rvalue::Len(path) => { 679 self.visit_place( 680 path, 681 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), 682 location 683 ); 684 } 685 686 Rvalue::Cast(_cast_kind, operand, ty) => { 687 self.visit_operand(operand, location); 688 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 689 } 690 691 Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) 692 | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => { 693 self.visit_operand(lhs, location); 694 self.visit_operand(rhs, location); 695 } 696 697 Rvalue::UnaryOp(_un_op, op) => { 698 self.visit_operand(op, location); 699 } 700 701 Rvalue::Discriminant(place) => { 702 self.visit_place( 703 place, 704 PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), 705 location 706 ); 707 } 708 709 Rvalue::NullaryOp(_op, ty) => { 710 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 711 } 712 713 Rvalue::Aggregate(kind, operands) => { 714 let kind = &$($mutability)? **kind; 715 match kind { 716 AggregateKind::Array(ty) => { 717 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 718 } 719 AggregateKind::Tuple => { 720 } 721 AggregateKind::Adt( 722 _adt_def, 723 _variant_index, 724 substs, 725 _user_substs, 726 _active_field_index 727 ) => { 728 self.visit_substs(substs, location); 729 } 730 AggregateKind::Closure( 731 _, 732 closure_substs 733 ) => { 734 self.visit_substs(closure_substs, location); 735 } 736 AggregateKind::Generator( 737 _, 738 generator_substs, 739 _movability, 740 ) => { 741 self.visit_substs(generator_substs, location); 742 } 743 } 744 745 for operand in operands { 746 self.visit_operand(operand, location); 747 } 748 } 749 750 Rvalue::ShallowInitBox(operand, ty) => { 751 self.visit_operand(operand, location); 752 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 753 } 754 } 755 } 756 757 fn super_operand(&mut self, 758 operand: & $($mutability)? Operand<'tcx>, 759 location: Location) { 760 match operand { 761 Operand::Copy(place) => { 762 self.visit_place( 763 place, 764 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), 765 location 766 ); 767 } 768 Operand::Move(place) => { 769 self.visit_place( 770 place, 771 PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), 772 location 773 ); 774 } 775 Operand::Constant(constant) => { 776 self.visit_constant(constant, location); 777 } 778 } 779 } 780 781 fn super_ascribe_user_ty(&mut self, 782 place: & $($mutability)? Place<'tcx>, 783 variance: $(& $mutability)? ty::Variance, 784 user_ty: & $($mutability)? UserTypeProjection, 785 location: Location) { 786 self.visit_place( 787 place, 788 PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)), 789 location 790 ); 791 self.visit_user_type_projection(user_ty); 792 } 793 794 fn super_coverage(&mut self, 795 _coverage: & $($mutability)? Coverage, 796 _location: Location) { 797 } 798 799 fn super_retag(&mut self, 800 _kind: $(& $mutability)? RetagKind, 801 place: & $($mutability)? Place<'tcx>, 802 location: Location) { 803 self.visit_place( 804 place, 805 PlaceContext::MutatingUse(MutatingUseContext::Retag), 806 location, 807 ); 808 } 809 810 fn super_local_decl(&mut self, 811 local: Local, 812 local_decl: & $($mutability)? LocalDecl<'tcx>) { 813 let LocalDecl { 814 mutability: _, 815 ty, 816 user_ty, 817 source_info, 818 internal: _, 819 local_info: _, 820 } = local_decl; 821 822 self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { 823 local, 824 source_info: *source_info, 825 }); 826 if let Some(user_ty) = user_ty { 827 for (user_ty, _) in & $($mutability)? user_ty.contents { 828 self.visit_user_type_projection(user_ty); 829 } 830 } 831 self.visit_source_info(source_info); 832 } 833 834 fn super_var_debug_info( 835 &mut self, 836 var_debug_info: & $($mutability)? VarDebugInfo<'tcx> 837 ) { 838 let VarDebugInfo { 839 name: _, 840 source_info, 841 value, 842 argument_index: _, 843 references: _, 844 } = var_debug_info; 845 846 self.visit_source_info(source_info); 847 let location = Location::START; 848 match value { 849 VarDebugInfoContents::Const(c) => self.visit_constant(c, location), 850 VarDebugInfoContents::Place(place) => 851 self.visit_place( 852 place, 853 PlaceContext::NonUse(NonUseContext::VarDebugInfo), 854 location 855 ), 856 VarDebugInfoContents::Composite { ty, fragments } => { 857 // FIXME(eddyb) use a better `TyContext` here. 858 self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); 859 for VarDebugInfoFragment { projection: _, contents } in fragments { 860 self.visit_place( 861 contents, 862 PlaceContext::NonUse(NonUseContext::VarDebugInfo), 863 location, 864 ); 865 } 866 } 867 } 868 } 869 870 fn super_source_scope( 871 &mut self, 872 _scope: $(& $mutability)? SourceScope 873 ) {} 874 875 fn super_constant( 876 &mut self, 877 constant: & $($mutability)? Constant<'tcx>, 878 location: Location 879 ) { 880 let Constant { 881 span, 882 user_ty: _, // no visit method for this 883 literal, 884 } = constant; 885 886 self.visit_span($(& $mutability)? *span); 887 match literal { 888 ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), 889 ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), 890 ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), 891 } 892 } 893 894 fn super_ty_const( 895 &mut self, 896 _ct: $(& $mutability)? ty::Const<'tcx>, 897 _location: Location, 898 ) { 899 900 } 901 902 fn super_span(&mut self, _span: $(& $mutability)? Span) { 903 } 904 905 fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) { 906 let SourceInfo { 907 span, 908 scope, 909 } = source_info; 910 911 self.visit_span($(& $mutability)? *span); 912 self.visit_source_scope($(& $mutability)? *scope); 913 } 914 915 fn super_user_type_projection( 916 &mut self, 917 _ty: & $($mutability)? UserTypeProjection, 918 ) { 919 } 920 921 fn super_user_type_annotation( 922 &mut self, 923 _index: UserTypeAnnotationIndex, 924 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, 925 ) { 926 self.visit_span($(& $mutability)? ty.span); 927 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); 928 } 929 930 fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { 931 } 932 933 fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) { 934 } 935 936 fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { 937 } 938 939 // Convenience methods 940 941 fn visit_location( 942 &mut self, 943 body: &$($mutability)? Body<'tcx>, 944 location: Location 945 ) { 946 let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; 947 if basic_block.statements.len() == location.statement_index { 948 if let Some(ref $($mutability)? terminator) = basic_block.terminator { 949 self.visit_terminator(terminator, location) 950 } 951 } else { 952 let statement = & $($mutability)? 953 basic_block.statements[location.statement_index]; 954 self.visit_statement(statement, location) 955 } 956 } 957 } 958 } 959 } 960 961 macro_rules! basic_blocks { 962 ($body:ident, mut, true) => { 963 $body.basic_blocks.as_mut() 964 }; 965 ($body:ident, mut, false) => { 966 $body.basic_blocks.as_mut_preserves_cfg() 967 }; 968 ($body:ident,) => { 969 $body.basic_blocks 970 }; 971 } 972 973 macro_rules! basic_blocks_iter { 974 ($body:ident, mut, $invalidate:tt) => { 975 basic_blocks!($body, mut, $invalidate).iter_enumerated_mut() 976 }; 977 ($body:ident,) => { 978 basic_blocks!($body,).iter_enumerated() 979 }; 980 } 981 982 macro_rules! extra_body_methods { 983 (mut) => { 984 fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { 985 self.super_body_preserves_cfg(body); 986 } 987 988 fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { 989 super_body!(self, body, mut, false); 990 } 991 }; 992 () => {}; 993 } 994 995 macro_rules! super_body { 996 ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => { 997 let span = $body.span; 998 if let Some(gen) = &$($mutability)? $body.generator { 999 if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { 1000 $self.visit_ty( 1001 yield_ty, 1002 TyContext::YieldTy(SourceInfo::outermost(span)) 1003 ); 1004 } 1005 } 1006 1007 for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) { 1008 $self.visit_basic_block_data(bb, data); 1009 } 1010 1011 for scope in &$($mutability)? $body.source_scopes { 1012 $self.visit_source_scope_data(scope); 1013 } 1014 1015 $self.visit_ty( 1016 $(& $mutability)? $body.return_ty(), 1017 TyContext::ReturnTy(SourceInfo::outermost($body.span)) 1018 ); 1019 1020 for local in $body.local_decls.indices() { 1021 $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]); 1022 } 1023 1024 #[allow(unused_macro_rules)] 1025 macro_rules! type_annotations { 1026 (mut) => ($body.user_type_annotations.iter_enumerated_mut()); 1027 () => ($body.user_type_annotations.iter_enumerated()); 1028 } 1029 1030 for (index, annotation) in type_annotations!($($mutability)?) { 1031 $self.visit_user_type_annotation( 1032 index, annotation 1033 ); 1034 } 1035 1036 for var_debug_info in &$($mutability)? $body.var_debug_info { 1037 $self.visit_var_debug_info(var_debug_info); 1038 } 1039 1040 $self.visit_span($(& $mutability)? $body.span); 1041 1042 for const_ in &$($mutability)? $body.required_consts { 1043 let location = Location::START; 1044 $self.visit_constant(const_, location); 1045 } 1046 } 1047 } 1048 1049 macro_rules! visit_place_fns { 1050 (mut) => { 1051 fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; 1052 1053 fn super_place( 1054 &mut self, 1055 place: &mut Place<'tcx>, 1056 context: PlaceContext, 1057 location: Location, 1058 ) { 1059 self.visit_local(&mut place.local, context, location); 1060 1061 if let Some(new_projection) = self.process_projection(&place.projection, location) { 1062 place.projection = self.tcx().mk_place_elems(&new_projection); 1063 } 1064 } 1065 1066 fn process_projection<'a>( 1067 &mut self, 1068 projection: &'a [PlaceElem<'tcx>], 1069 location: Location, 1070 ) -> Option<Vec<PlaceElem<'tcx>>> { 1071 let mut projection = Cow::Borrowed(projection); 1072 1073 for i in 0..projection.len() { 1074 if let Some(&elem) = projection.get(i) { 1075 if let Some(elem) = self.process_projection_elem(elem, location) { 1076 // This converts the borrowed projection into `Cow::Owned(_)` and returns a 1077 // clone of the projection so we can mutate and reintern later. 1078 let vec = projection.to_mut(); 1079 vec[i] = elem; 1080 } 1081 } 1082 } 1083 1084 match projection { 1085 Cow::Borrowed(_) => None, 1086 Cow::Owned(vec) => Some(vec), 1087 } 1088 } 1089 1090 fn process_projection_elem( 1091 &mut self, 1092 elem: PlaceElem<'tcx>, 1093 location: Location, 1094 ) -> Option<PlaceElem<'tcx>> { 1095 match elem { 1096 PlaceElem::Index(local) => { 1097 let mut new_local = local; 1098 self.visit_local( 1099 &mut new_local, 1100 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), 1101 location, 1102 ); 1103 1104 if new_local == local { None } else { Some(PlaceElem::Index(new_local)) } 1105 } 1106 PlaceElem::Field(field, ty) => { 1107 let mut new_ty = ty; 1108 self.visit_ty(&mut new_ty, TyContext::Location(location)); 1109 if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } 1110 } 1111 PlaceElem::OpaqueCast(ty) => { 1112 let mut new_ty = ty; 1113 self.visit_ty(&mut new_ty, TyContext::Location(location)); 1114 if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } 1115 } 1116 PlaceElem::Deref 1117 | PlaceElem::ConstantIndex { .. } 1118 | PlaceElem::Subslice { .. } 1119 | PlaceElem::Downcast(..) => None, 1120 } 1121 } 1122 }; 1123 1124 () => { 1125 fn visit_projection( 1126 &mut self, 1127 place_ref: PlaceRef<'tcx>, 1128 context: PlaceContext, 1129 location: Location, 1130 ) { 1131 self.super_projection(place_ref, context, location); 1132 } 1133 1134 fn visit_projection_elem( 1135 &mut self, 1136 place_ref: PlaceRef<'tcx>, 1137 elem: PlaceElem<'tcx>, 1138 context: PlaceContext, 1139 location: Location, 1140 ) { 1141 self.super_projection_elem(place_ref, elem, context, location); 1142 } 1143 1144 fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { 1145 let mut context = context; 1146 1147 if !place.projection.is_empty() { 1148 if context.is_use() { 1149 // ^ Only change the context if it is a real use, not a "use" in debuginfo. 1150 context = if context.is_mutating_use() { 1151 PlaceContext::MutatingUse(MutatingUseContext::Projection) 1152 } else { 1153 PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) 1154 }; 1155 } 1156 } 1157 1158 self.visit_local(place.local, context, location); 1159 1160 self.visit_projection(place.as_ref(), context, location); 1161 } 1162 1163 fn super_projection( 1164 &mut self, 1165 place_ref: PlaceRef<'tcx>, 1166 context: PlaceContext, 1167 location: Location, 1168 ) { 1169 for (base, elem) in place_ref.iter_projections().rev() { 1170 self.visit_projection_elem(base, elem, context, location); 1171 } 1172 } 1173 1174 fn super_projection_elem( 1175 &mut self, 1176 _place_ref: PlaceRef<'tcx>, 1177 elem: PlaceElem<'tcx>, 1178 _context: PlaceContext, 1179 location: Location, 1180 ) { 1181 match elem { 1182 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { 1183 self.visit_ty(ty, TyContext::Location(location)); 1184 } 1185 ProjectionElem::Index(local) => { 1186 self.visit_local( 1187 local, 1188 PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), 1189 location, 1190 ); 1191 } 1192 ProjectionElem::Deref 1193 | ProjectionElem::Subslice { from: _, to: _, from_end: _ } 1194 | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } 1195 | ProjectionElem::Downcast(_, _) => {} 1196 } 1197 } 1198 }; 1199 } 1200 1201 make_mir_visitor!(Visitor,); 1202 make_mir_visitor!(MutVisitor, mut); 1203 1204 pub trait MirVisitable<'tcx> { apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)1205 fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>); 1206 } 1207 1208 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> { apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)1209 fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { 1210 visitor.visit_statement(self, location) 1211 } 1212 } 1213 1214 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> { apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)1215 fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { 1216 visitor.visit_terminator(self, location) 1217 } 1218 } 1219 1220 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> { apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)1221 fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) { 1222 visitor.visit_terminator(self.as_ref().unwrap(), location) 1223 } 1224 } 1225 1226 /// Extra information passed to `visit_ty` and friends to give context 1227 /// about where the type etc appears. 1228 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] 1229 pub enum TyContext { 1230 LocalDecl { 1231 /// The index of the local variable we are visiting. 1232 local: Local, 1233 1234 /// The source location where this local variable was declared. 1235 source_info: SourceInfo, 1236 }, 1237 1238 /// The inferred type of a user type annotation. 1239 UserTy(Span), 1240 1241 /// The return type of the function. 1242 ReturnTy(SourceInfo), 1243 1244 YieldTy(SourceInfo), 1245 1246 /// A type found at some location. 1247 Location(Location), 1248 } 1249 1250 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1251 pub enum NonMutatingUseContext { 1252 /// Being inspected in some way, like loading a len. 1253 Inspect, 1254 /// Consumed as part of an operand. 1255 Copy, 1256 /// Consumed as part of an operand. 1257 Move, 1258 /// Shared borrow. 1259 SharedBorrow, 1260 /// Shallow borrow. 1261 ShallowBorrow, 1262 /// AddressOf for *const pointer. 1263 AddressOf, 1264 /// PlaceMention statement. 1265 /// 1266 /// This statement is executed as a check that the `Place` is live without reading from it, 1267 /// so it must be considered as a non-mutating use. 1268 PlaceMention, 1269 /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place. 1270 /// For example, the projection `x.y` is not marked as a mutation in these cases: 1271 /// ```ignore (illustrative) 1272 /// z = x.y; 1273 /// f(&x.y); 1274 /// ``` 1275 Projection, 1276 } 1277 1278 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1279 pub enum MutatingUseContext { 1280 /// Appears as LHS of an assignment. 1281 Store, 1282 /// Appears on `SetDiscriminant` 1283 SetDiscriminant, 1284 /// Appears on `Deinit` 1285 Deinit, 1286 /// Output operand of an inline assembly block. 1287 AsmOutput, 1288 /// Destination of a call. 1289 Call, 1290 /// Destination of a yield. 1291 Yield, 1292 /// Being dropped. 1293 Drop, 1294 /// Mutable borrow. 1295 Borrow, 1296 /// AddressOf for *mut pointer. 1297 AddressOf, 1298 /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place. 1299 /// For example, the projection `x.y` is marked as a mutation in these cases: 1300 /// ```ignore (illustrative) 1301 /// x.y = ...; 1302 /// f(&mut x.y); 1303 /// ``` 1304 Projection, 1305 /// Retagging, a "Stacked Borrows" shadow state operation 1306 Retag, 1307 } 1308 1309 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1310 pub enum NonUseContext { 1311 /// Starting a storage live range. 1312 StorageLive, 1313 /// Ending a storage live range. 1314 StorageDead, 1315 /// User type annotation assertions for NLL. 1316 AscribeUserTy(ty::Variance), 1317 /// The data of a user variable, for debug info. 1318 VarDebugInfo, 1319 } 1320 1321 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 1322 pub enum PlaceContext { 1323 NonMutatingUse(NonMutatingUseContext), 1324 MutatingUse(MutatingUseContext), 1325 NonUse(NonUseContext), 1326 } 1327 1328 impl PlaceContext { 1329 /// Returns `true` if this place context represents a drop. 1330 #[inline] is_drop(&self) -> bool1331 pub fn is_drop(&self) -> bool { 1332 matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop)) 1333 } 1334 1335 /// Returns `true` if this place context represents a borrow. is_borrow(&self) -> bool1336 pub fn is_borrow(&self) -> bool { 1337 matches!( 1338 self, 1339 PlaceContext::NonMutatingUse( 1340 NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow 1341 ) | PlaceContext::MutatingUse(MutatingUseContext::Borrow) 1342 ) 1343 } 1344 1345 /// Returns `true` if this place context represents an address-of. is_address_of(&self) -> bool1346 pub fn is_address_of(&self) -> bool { 1347 matches!( 1348 self, 1349 PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) 1350 | PlaceContext::MutatingUse(MutatingUseContext::AddressOf) 1351 ) 1352 } 1353 1354 /// Returns `true` if this place context represents a storage live or storage dead marker. 1355 #[inline] is_storage_marker(&self) -> bool1356 pub fn is_storage_marker(&self) -> bool { 1357 matches!( 1358 self, 1359 PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) 1360 ) 1361 } 1362 1363 /// Returns `true` if this place context represents a use that potentially changes the value. 1364 #[inline] is_mutating_use(&self) -> bool1365 pub fn is_mutating_use(&self) -> bool { 1366 matches!(self, PlaceContext::MutatingUse(..)) 1367 } 1368 1369 /// Returns `true` if this place context represents a use. 1370 #[inline] is_use(&self) -> bool1371 pub fn is_use(&self) -> bool { 1372 !matches!(self, PlaceContext::NonUse(..)) 1373 } 1374 1375 /// Returns `true` if this place context represents an assignment statement. is_place_assignment(&self) -> bool1376 pub fn is_place_assignment(&self) -> bool { 1377 matches!( 1378 self, 1379 PlaceContext::MutatingUse( 1380 MutatingUseContext::Store 1381 | MutatingUseContext::Call 1382 | MutatingUseContext::AsmOutput, 1383 ) 1384 ) 1385 } 1386 } 1387