rustc_middle/mir/
visit.rs

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