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