Skip to main content

rustc_public/mir/
visit.rs

1//! # The rustc_public's IR Visitor
2//!
3//! ## Overview
4//!
5//! We currently only support an immutable visitor.
6//! The structure of this visitor is similar to the ones internal to `rustc`,
7//! and it follows the following conventions:
8//!
9//! For every mir item, the trait has a `visit_<item>` and a `super_<item>` method.
10//! - `visit_<item>`, by default, calls `super_<item>`
11//! - `super_<item>`, by default, destructures the `<item>` and calls `visit_<sub_item>` for
12//!   all sub-items that compose the original item.
13//!
14//! In order to implement a visitor, override the `visit_*` methods for the types you are
15//! interested in analyzing, and invoke (within that method call)
16//! `self.super_*` to continue to the traverse.
17//! Avoid calling `super` methods in other circumstances.
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.
21//! This 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.
27//!
28//! Use pattern matching to reference fields and ensure that all
29//! matches are exhaustive.
30//!
31//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
32//! That means you never write `..` to skip over fields, nor do you write `_`
33//! to skip over variants in a `match`.
34//!
35//! The only place that `_` is acceptable is to match a field (or
36//! variant argument) that does not require visiting.
37
38use crate::mir::*;
39use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst};
40use crate::{Error, Opaque, Span};
41
42macro_rules! make_mir_visitor {
43    ($visitor_trait_name:ident, $($mutability:ident)?) => {
44        pub trait $visitor_trait_name {
45            fn visit_body(&mut self, body: &$($mutability)? Body) {
46                self.super_body(body)
47            }
48
49            fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) {
50                self.super_basic_block(bb)
51            }
52
53            fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
54                self.super_ret_decl(local, decl)
55            }
56
57            fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
58                self.super_arg_decl(local, decl)
59            }
60
61            fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
62                self.super_local_decl(local, decl)
63            }
64
65            fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) {
66                self.super_statement(stmt, location)
67            }
68
69            fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) {
70                self.super_terminator(term, location)
71            }
72
73            fn visit_span(&mut self, span: &$($mutability)? Span) {
74                self.super_span(span)
75            }
76
77            fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) {
78                self.super_place(place, ptx, location)
79            }
80
81            visit_place_fns!($($mutability)?);
82
83            fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) {
84                let _ = (local, ptx, location);
85            }
86
87            fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) {
88                self.super_rvalue(rvalue, location)
89            }
90
91            fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
92                self.super_operand(operand, location)
93            }
94
95            fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
96                self.super_user_type_projection(projection)
97            }
98
99            fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) {
100                let _ = location;
101                self.super_ty(ty)
102            }
103
104            fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
105                self.super_const_operand(constant, location)
106            }
107
108            fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
109                self.super_mir_const(constant, location)
110            }
111
112            fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) {
113                let _ = location;
114                self.super_ty_const(constant)
115            }
116
117            fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) {
118                let _ = location;
119                self.super_region(region)
120            }
121
122            fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) {
123                let _ = location;
124                self.super_args(args)
125            }
126
127            fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
128                self.super_assert_msg(msg, location)
129            }
130
131            fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
132                self.super_var_debug_info(var_debug_info);
133            }
134
135            fn super_body(&mut self, body: &$($mutability)? Body) {
136                super_body!(self, body, $($mutability)?);
137            }
138
139            fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) {
140                let BasicBlock { statements, terminator } = bb;
141                for stmt in statements {
142                    self.visit_statement(stmt, Location(stmt.span));
143                }
144                self.visit_terminator(terminator, Location(terminator.span));
145            }
146
147            fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
148                let _ = local;
149                let LocalDecl { ty, span, .. } = decl;
150                self.visit_ty(ty, Location(*span));
151            }
152
153            fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
154                self.super_local_decl(local, decl)
155            }
156
157            fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
158                self.super_local_decl(local, decl)
159            }
160
161            fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) {
162                let Statement { kind, span } = stmt;
163                self.visit_span(span);
164                match kind {
165                    StatementKind::Assign(place, rvalue) => {
166                        self.visit_place(place, PlaceContext::MUTATING, location);
167                        self.visit_rvalue(rvalue, location);
168                    }
169                    StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => {
170                        self.visit_place(place, PlaceContext::NON_MUTATING, location);
171                    }
172                    StatementKind::SetDiscriminant { place, .. } => {
173                        self.visit_place(place, PlaceContext::MUTATING, location);
174                    }
175                    StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
176                        self.visit_local(local, PlaceContext::NON_USE, location);
177                    }
178                    StatementKind::AscribeUserType { place, projections, variance: _ } => {
179                        self.visit_place(place, PlaceContext::NON_USE, location);
180                        self.visit_user_type_projection(projections);
181                    }
182                    StatementKind::Coverage(coverage) => visit_opaque(coverage),
183                    StatementKind::Intrinsic(intrinsic) => match intrinsic {
184                        NonDivergingIntrinsic::Assume(operand) => {
185                            self.visit_operand(operand, location);
186                        }
187                        NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
188                            src,
189                            dst,
190                            count,
191                        }) => {
192                            self.visit_operand(src, location);
193                            self.visit_operand(dst, location);
194                            self.visit_operand(count, location);
195                        }
196                    },
197                    StatementKind::ConstEvalCounter | StatementKind::Nop => {}
198                }
199            }
200
201            fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) {
202                let Terminator { kind, span } = term;
203                self.visit_span(span);
204                match kind {
205                    TerminatorKind::Goto { .. }
206                    | TerminatorKind::Resume
207                    | TerminatorKind::Abort
208                    | TerminatorKind::Unreachable => {}
209                    TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
210                        self.visit_operand(cond, location);
211                        self.visit_assert_msg(msg, location);
212                    }
213                    TerminatorKind::Drop { place, target: _, unwind: _ } => {
214                        self.visit_place(place, PlaceContext::MUTATING, location);
215                    }
216                    TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
217                        self.visit_operand(func, location);
218                        for arg in args {
219                            self.visit_operand(arg, location);
220                        }
221                        self.visit_place(destination, PlaceContext::MUTATING, location);
222                    }
223                    TerminatorKind::InlineAsm { operands, .. } => {
224                        for op in operands {
225                            let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
226                            if let Some(input) = in_value {
227                                self.visit_operand(input, location);
228                            }
229                            if let Some(output) = out_place {
230                                self.visit_place(output, PlaceContext::MUTATING, location);
231                            }
232                        }
233                    }
234                    TerminatorKind::Return => {
235                        let $($mutability)? local = RETURN_LOCAL;
236                        self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location);
237                    }
238                    TerminatorKind::SwitchInt { discr, targets: _ } => {
239                        self.visit_operand(discr, location);
240                    }
241                }
242            }
243
244            fn super_span(&mut self, span: &$($mutability)? Span) {
245                let _ = span;
246            }
247
248            fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) {
249                match rvalue {
250                    Rvalue::AddressOf(mutability, place) => {
251                        let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
252                        self.visit_place(place, pcx, location);
253                    }
254                    Rvalue::Aggregate(_, operands) => {
255                        for op in operands {
256                            self.visit_operand(op, location);
257                        }
258                    }
259                    Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
260                        self.visit_operand(lhs, location);
261                        self.visit_operand(rhs, location);
262                    }
263                    Rvalue::Cast(_, op, ty) => {
264                        self.visit_operand(op, location);
265                        self.visit_ty(ty, location);
266                    }
267                    Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
268                        self.visit_place(place, PlaceContext::NON_MUTATING, location);
269                    }
270                    Rvalue::Ref(region, kind, place) => {
271                        self.visit_region(region, location);
272                        let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
273                        self.visit_place(place, pcx, location);
274                    }
275                    Rvalue::Repeat(op, constant) => {
276                        self.visit_operand(op, location);
277                        self.visit_ty_const(constant, location);
278                    }
279                    Rvalue::ThreadLocalRef(_) => {}
280                    Rvalue::UnaryOp(_, op) | Rvalue::Use(op, _) => {
281                        self.visit_operand(op, location);
282                    }
283                }
284            }
285
286            fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
287                match operand {
288                    Operand::Copy(place) | Operand::Move(place) => {
289                        self.visit_place(place, PlaceContext::NON_MUTATING, location)
290                    }
291                    Operand::Constant(constant) => {
292                        self.visit_const_operand(constant, location);
293                    }
294                    Operand::RuntimeChecks(_) => {}
295                }
296            }
297
298            fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
299                // This is a no-op on mir::Visitor.
300                let _ = projection;
301            }
302
303            fn super_ty(&mut self, ty: &$($mutability)? Ty) {
304                let _ = ty;
305            }
306
307            fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
308                let ConstOperand { span, user_ty: _, const_ } = constant;
309                self.visit_span(span);
310                self.visit_mir_const(const_, location);
311            }
312
313            fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
314                let MirConst { kind: _, ty, id: _ } = constant;
315                self.visit_ty(ty, location);
316            }
317
318            fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) {
319                let _ = constant;
320            }
321
322            fn super_region(&mut self, region: &$($mutability)? Region) {
323                let _ = region;
324            }
325
326            fn super_args(&mut self, args: &$($mutability)? GenericArgs) {
327                let _ = args;
328            }
329
330            fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
331                let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
332                    var_debug_info;
333                self.visit_span(&$($mutability)? source_info.span);
334                let location = Location(source_info.span);
335                if let Some(composite) = composite {
336                    self.visit_ty(&$($mutability)? composite.ty, location);
337                }
338                match value {
339                    VarDebugInfoContents::Place(place) => {
340                        self.visit_place(place, PlaceContext::NON_USE, location);
341                    }
342                    VarDebugInfoContents::Const(constant) => {
343                        self.visit_mir_const(&$($mutability)? constant.const_, location);
344                    }
345                }
346            }
347
348            fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
349                match msg {
350                    AssertMessage::BoundsCheck { len, index } => {
351                        self.visit_operand(len, location);
352                        self.visit_operand(index, location);
353                    }
354                    AssertMessage::Overflow(_, left, right) => {
355                        self.visit_operand(left, location);
356                        self.visit_operand(right, location);
357                    }
358                    AssertMessage::OverflowNeg(op)
359                    | AssertMessage::DivisionByZero(op)
360                    | AssertMessage::RemainderByZero(op)
361                    | AssertMessage::InvalidEnumConstruction(op) => {
362                        self.visit_operand(op, location);
363                    }
364                    AssertMessage::ResumedAfterReturn(_)
365                    | AssertMessage::ResumedAfterPanic(_)
366                    | AssertMessage::NullPointerDereference
367                    | AssertMessage::ResumedAfterDrop(_) => {
368                        //nothing to visit
369                    }
370                    AssertMessage::MisalignedPointerDereference { required, found } => {
371                        self.visit_operand(required, location);
372                        self.visit_operand(found, location);
373                    }
374                }
375            }
376        }
377    };
378}
379
380macro_rules! super_body {
381    ($self:ident, $body:ident, mut) => {
382        for bb in $body.blocks.iter_mut() {
383            $self.visit_basic_block(bb);
384        }
385
386        $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut());
387
388        for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() {
389            $self.visit_arg_decl(idx + 1, arg)
390        }
391
392        let local_start = $body.arg_count + 1;
393        for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() {
394            $self.visit_local_decl(idx + local_start, arg)
395        }
396
397        for info in $body.var_debug_info.iter_mut() {
398            $self.visit_var_debug_info(info);
399        }
400
401        $self.visit_span(&mut $body.span)
402    };
403
404    ($self:ident, $body:ident, ) => {
405        let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body;
406
407        for bb in blocks {
408            $self.visit_basic_block(bb);
409        }
410
411        $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local());
412
413        for (idx, arg) in $body.arg_locals().iter().enumerate() {
414            $self.visit_arg_decl(idx + 1, arg)
415        }
416
417        let local_start = arg_count + 1;
418        for (idx, arg) in $body.inner_locals().iter().enumerate() {
419            $self.visit_local_decl(idx + local_start, arg)
420        }
421
422        for info in var_debug_info.iter() {
423            $self.visit_var_debug_info(info);
424        }
425
426        $self.visit_span(span)
427    };
428}
429
430macro_rules! visit_place_fns {
431    (mut) => {
432        fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) {
433            self.visit_local(&mut place.local, ptx, location);
434
435            for elem in place.projection.iter_mut() {
436                self.visit_projection_elem(elem, ptx, location);
437            }
438        }
439
440        // We don't have to replicate the `process_projection()` like we did in
441        // `rustc_middle::mir::visit.rs` here because the `projection` field in `Place`
442        // of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR.
443        fn visit_projection_elem(
444            &mut self,
445            elem: &mut ProjectionElem,
446            ptx: PlaceContext,
447            location: Location,
448        ) {
449            self.super_projection_elem(elem, ptx, location)
450        }
451
452        fn super_projection_elem(
453            &mut self,
454            elem: &mut ProjectionElem,
455            ptx: PlaceContext,
456            location: Location,
457        ) {
458            match elem {
459                ProjectionElem::Deref => {}
460                ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
461                ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
462                ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
463                ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
464                ProjectionElem::Downcast(_idx) => {}
465                ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
466            }
467        }
468    };
469
470    () => {
471        fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
472            self.visit_local(&place.local, ptx, location);
473
474            for (idx, elem) in place.projection.iter().enumerate() {
475                let place_ref =
476                    PlaceRef { local: place.local, projection: &place.projection[..idx] };
477                self.visit_projection_elem(place_ref, elem, ptx, location);
478            }
479        }
480
481        fn visit_projection_elem<'a>(
482            &mut self,
483            place_ref: PlaceRef<'a>,
484            elem: &ProjectionElem,
485            ptx: PlaceContext,
486            location: Location,
487        ) {
488            let _ = place_ref;
489            self.super_projection_elem(elem, ptx, location);
490        }
491
492        fn super_projection_elem(
493            &mut self,
494            elem: &ProjectionElem,
495            ptx: PlaceContext,
496            location: Location,
497        ) {
498            match elem {
499                ProjectionElem::Deref => {}
500                ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
501                ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
502                ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
503                ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
504                ProjectionElem::Downcast(_idx) => {}
505                ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
506            }
507        }
508    };
509}
510
511pub trait MirVisitor {
    fn visit_body(&mut self, body: &Body) { self.super_body(body) }
    fn visit_basic_block(&mut self, bb: &BasicBlock) {
        self.super_basic_block(bb)
    }
    fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
        self.super_ret_decl(local, decl)
    }
    fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
        self.super_arg_decl(local, decl)
    }
    fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn visit_statement(&mut self, stmt: &Statement, location: Location) {
        self.super_statement(stmt, location)
    }
    fn visit_terminator(&mut self, term: &Terminator, location: Location) {
        self.super_terminator(term, location)
    }
    fn visit_span(&mut self, span: &Span) { self.super_span(span) }
    fn visit_place(&mut self, place: &Place, ptx: PlaceContext,
        location: Location) {
        self.super_place(place, ptx, location)
    }
    fn super_place(&mut self, place: &Place, ptx: PlaceContext,
        location: Location) {
        self.visit_local(&place.local, ptx, location);
        for (idx, elem) in place.projection.iter().enumerate() {
            let place_ref =
                PlaceRef {
                    local: place.local,
                    projection: &place.projection[..idx],
                };
            self.visit_projection_elem(place_ref, elem, ptx, location);
        }
    }
    fn visit_projection_elem<'a>(&mut self, place_ref: PlaceRef<'a>,
        elem: &ProjectionElem, ptx: PlaceContext, location: Location) {
        let _ = place_ref;
        self.super_projection_elem(elem, ptx, location);
    }
    fn super_projection_elem(&mut self, elem: &ProjectionElem,
        ptx: PlaceContext, location: Location) {
        match elem {
            ProjectionElem::Deref => {}
            ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
            ProjectionElem::Index(local) =>
                self.visit_local(local, ptx, location),
            ProjectionElem::ConstantIndex {
                offset: _, min_length: _, from_end: _ } => {}
            ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
            ProjectionElem::Downcast(_idx) => {}
            ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
        }
    }
    fn visit_local(&mut self, local: &Local, ptx: PlaceContext,
        location: Location) {
        let _ = (local, ptx, location);
    }
    fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
        self.super_rvalue(rvalue, location)
    }
    fn visit_operand(&mut self, operand: &Operand, location: Location) {
        self.super_operand(operand, location)
    }
    fn visit_user_type_projection(&mut self,
        projection: &UserTypeProjection) {
        self.super_user_type_projection(projection)
    }
    fn visit_ty(&mut self, ty: &Ty, location: Location) {
        let _ = location;
        self.super_ty(ty)
    }
    fn visit_const_operand(&mut self, constant: &ConstOperand,
        location: Location) {
        self.super_const_operand(constant, location)
    }
    fn visit_mir_const(&mut self, constant: &MirConst, location: Location) {
        self.super_mir_const(constant, location)
    }
    fn visit_ty_const(&mut self, constant: &TyConst, location: Location) {
        let _ = location;
        self.super_ty_const(constant)
    }
    fn visit_region(&mut self, region: &Region, location: Location) {
        let _ = location;
        self.super_region(region)
    }
    fn visit_args(&mut self, args: &GenericArgs, location: Location) {
        let _ = location;
        self.super_args(args)
    }
    fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
        self.super_assert_msg(msg, location)
    }
    fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
        self.super_var_debug_info(var_debug_info);
    }
    fn super_body(&mut self, body: &Body) {
        let Body {
                blocks,
                locals: _,
                arg_count,
                var_debug_info,
                spread_arg: _,
                span } = body;
        for bb in blocks { self.visit_basic_block(bb); }
        self.visit_ret_decl(RETURN_LOCAL, body.ret_local());
        for (idx, arg) in body.arg_locals().iter().enumerate() {
            self.visit_arg_decl(idx + 1, arg)
        }
        let local_start = arg_count + 1;
        for (idx, arg) in body.inner_locals().iter().enumerate() {
            self.visit_local_decl(idx + local_start, arg)
        }
        for info in var_debug_info.iter() { self.visit_var_debug_info(info); }
        self.visit_span(span);
    }
    fn super_basic_block(&mut self, bb: &BasicBlock) {
        let BasicBlock { statements, terminator } = bb;
        for stmt in statements {
            self.visit_statement(stmt, Location(stmt.span));
        }
        self.visit_terminator(terminator, Location(terminator.span));
    }
    fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) {
        let _ = local;
        let LocalDecl { ty, span, .. } = decl;
        self.visit_ty(ty, Location(*span));
    }
    fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn super_statement(&mut self, stmt: &Statement, location: Location) {
        let Statement { kind, span } = stmt;
        self.visit_span(span);
        match kind {
            StatementKind::Assign(place, rvalue) => {
                self.visit_place(place, PlaceContext::MUTATING, location);
                self.visit_rvalue(rvalue, location);
            }
            StatementKind::FakeRead(_, place) |
                StatementKind::PlaceMention(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location);
            }
            StatementKind::SetDiscriminant { place, .. } => {
                self.visit_place(place, PlaceContext::MUTATING, location);
            }
            StatementKind::StorageLive(local) |
                StatementKind::StorageDead(local) => {
                self.visit_local(local, PlaceContext::NON_USE, location);
            }
            StatementKind::AscribeUserType { place, projections, variance: _ }
                => {
                self.visit_place(place, PlaceContext::NON_USE, location);
                self.visit_user_type_projection(projections);
            }
            StatementKind::Coverage(coverage) => visit_opaque(coverage),
            StatementKind::Intrinsic(intrinsic) =>
                match intrinsic {
                    NonDivergingIntrinsic::Assume(operand) => {
                        self.visit_operand(operand, location);
                    }
                    NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
                        src, dst, count }) => {
                        self.visit_operand(src, location);
                        self.visit_operand(dst, location);
                        self.visit_operand(count, location);
                    }
                },
            StatementKind::ConstEvalCounter | StatementKind::Nop => {}
        }
    }
    fn super_terminator(&mut self, term: &Terminator, location: Location) {
        let Terminator { kind, span } = term;
        self.visit_span(span);
        match kind {
            TerminatorKind::Goto { .. } | TerminatorKind::Resume |
                TerminatorKind::Abort | TerminatorKind::Unreachable => {}
            TerminatorKind::Assert {
                cond, expected: _, msg, target: _, unwind: _ } => {
                self.visit_operand(cond, location);
                self.visit_assert_msg(msg, location);
            }
            TerminatorKind::Drop { place, target: _, unwind: _ } => {
                self.visit_place(place, PlaceContext::MUTATING, location);
            }
            TerminatorKind::Call {
                func, args, destination, target: _, unwind: _ } => {
                self.visit_operand(func, location);
                for arg in args { self.visit_operand(arg, location); }
                self.visit_place(destination, PlaceContext::MUTATING,
                    location);
            }
            TerminatorKind::InlineAsm { operands, .. } => {
                for op in operands {
                    let InlineAsmOperand { in_value, out_place, raw_rpr: _ } =
                        op;
                    if let Some(input) = in_value {
                        self.visit_operand(input, location);
                    }
                    if let Some(output) = out_place {
                        self.visit_place(output, PlaceContext::MUTATING, location);
                    }
                }
            }
            TerminatorKind::Return => {
                let local = RETURN_LOCAL;
                self.visit_local(&local, PlaceContext::NON_MUTATING,
                    location);
            }
            TerminatorKind::SwitchInt { discr, targets: _ } => {
                self.visit_operand(discr, location);
            }
        }
    }
    fn super_span(&mut self, span: &Span) { let _ = span; }
    fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
        match rvalue {
            Rvalue::AddressOf(mutability, place) => {
                let pcx =
                    PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
                self.visit_place(place, pcx, location);
            }
            Rvalue::Aggregate(_, operands) => {
                for op in operands { self.visit_operand(op, location); }
            }
            Rvalue::BinaryOp(_, lhs, rhs) |
                Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
                self.visit_operand(lhs, location);
                self.visit_operand(rhs, location);
            }
            Rvalue::Cast(_, op, ty) => {
                self.visit_operand(op, location);
                self.visit_ty(ty, location);
            }
            Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) |
                Rvalue::Len(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location);
            }
            Rvalue::Ref(region, kind, place) => {
                self.visit_region(region, location);
                let pcx =
                    PlaceContext {
                        is_mut: #[allow(non_exhaustive_omitted_patterns)] match kind
                            {
                            BorrowKind::Mut { .. } => true,
                            _ => false,
                        },
                    };
                self.visit_place(place, pcx, location);
            }
            Rvalue::Repeat(op, constant) => {
                self.visit_operand(op, location);
                self.visit_ty_const(constant, location);
            }
            Rvalue::ThreadLocalRef(_) => {}
            Rvalue::UnaryOp(_, op) | Rvalue::Use(op, _) => {
                self.visit_operand(op, location);
            }
        }
    }
    fn super_operand(&mut self, operand: &Operand, location: Location) {
        match operand {
            Operand::Copy(place) | Operand::Move(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location)
            }
            Operand::Constant(constant) => {
                self.visit_const_operand(constant, location);
            }
            Operand::RuntimeChecks(_) => {}
        }
    }
    fn super_user_type_projection(&mut self,
        projection: &UserTypeProjection) {
        let _ = projection;
    }
    fn super_ty(&mut self, ty: &Ty) { let _ = ty; }
    fn super_const_operand(&mut self, constant: &ConstOperand,
        location: Location) {
        let ConstOperand { span, user_ty: _, const_ } = constant;
        self.visit_span(span);
        self.visit_mir_const(const_, location);
    }
    fn super_mir_const(&mut self, constant: &MirConst, location: Location) {
        let MirConst { kind: _, ty, id: _ } = constant;
        self.visit_ty(ty, location);
    }
    fn super_ty_const(&mut self, constant: &TyConst) { let _ = constant; }
    fn super_region(&mut self, region: &Region) { let _ = region; }
    fn super_args(&mut self, args: &GenericArgs) { let _ = args; }
    fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
        let VarDebugInfo {
                source_info, composite, value, name: _, argument_index: _ } =
            var_debug_info;
        self.visit_span(&source_info.span);
        let location = Location(source_info.span);
        if let Some(composite) = composite {
            self.visit_ty(&composite.ty, location);
        }
        match value {
            VarDebugInfoContents::Place(place) => {
                self.visit_place(place, PlaceContext::NON_USE, location);
            }
            VarDebugInfoContents::Const(constant) => {
                self.visit_mir_const(&constant.const_, location);
            }
        }
    }
    fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
        match msg {
            AssertMessage::BoundsCheck { len, index } => {
                self.visit_operand(len, location);
                self.visit_operand(index, location);
            }
            AssertMessage::Overflow(_, left, right) => {
                self.visit_operand(left, location);
                self.visit_operand(right, location);
            }
            AssertMessage::OverflowNeg(op) | AssertMessage::DivisionByZero(op)
                | AssertMessage::RemainderByZero(op) |
                AssertMessage::InvalidEnumConstruction(op) => {
                self.visit_operand(op, location);
            }
            AssertMessage::ResumedAfterReturn(_) |
                AssertMessage::ResumedAfterPanic(_) |
                AssertMessage::NullPointerDereference |
                AssertMessage::ResumedAfterDrop(_) => {}
            AssertMessage::MisalignedPointerDereference { required, found } =>
                {
                self.visit_operand(required, location);
                self.visit_operand(found, location);
            }
        }
    }
}make_mir_visitor!(MirVisitor,);
512pub trait MutMirVisitor {
    fn visit_body(&mut self, body: &mut Body) { self.super_body(body) }
    fn visit_basic_block(&mut self, bb: &mut BasicBlock) {
        self.super_basic_block(bb)
    }
    fn visit_ret_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        self.super_ret_decl(local, decl)
    }
    fn visit_arg_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        self.super_arg_decl(local, decl)
    }
    fn visit_local_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn visit_statement(&mut self, stmt: &mut Statement, location: Location) {
        self.super_statement(stmt, location)
    }
    fn visit_terminator(&mut self, term: &mut Terminator,
        location: Location) {
        self.super_terminator(term, location)
    }
    fn visit_span(&mut self, span: &mut Span) { self.super_span(span) }
    fn visit_place(&mut self, place: &mut Place, ptx: PlaceContext,
        location: Location) {
        self.super_place(place, ptx, location)
    }
    fn super_place(&mut self, place: &mut Place, ptx: PlaceContext,
        location: Location) {
        self.visit_local(&mut place.local, ptx, location);
        for elem in place.projection.iter_mut() {
            self.visit_projection_elem(elem, ptx, location);
        }
    }
    fn visit_projection_elem(&mut self, elem: &mut ProjectionElem,
        ptx: PlaceContext, location: Location) {
        self.super_projection_elem(elem, ptx, location)
    }
    fn super_projection_elem(&mut self, elem: &mut ProjectionElem,
        ptx: PlaceContext, location: Location) {
        match elem {
            ProjectionElem::Deref => {}
            ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
            ProjectionElem::Index(local) =>
                self.visit_local(local, ptx, location),
            ProjectionElem::ConstantIndex {
                offset: _, min_length: _, from_end: _ } => {}
            ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
            ProjectionElem::Downcast(_idx) => {}
            ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
        }
    }
    fn visit_local(&mut self, local: &mut Local, ptx: PlaceContext,
        location: Location) {
        let _ = (local, ptx, location);
    }
    fn visit_rvalue(&mut self, rvalue: &mut Rvalue, location: Location) {
        self.super_rvalue(rvalue, location)
    }
    fn visit_operand(&mut self, operand: &mut Operand, location: Location) {
        self.super_operand(operand, location)
    }
    fn visit_user_type_projection(&mut self,
        projection: &mut UserTypeProjection) {
        self.super_user_type_projection(projection)
    }
    fn visit_ty(&mut self, ty: &mut Ty, location: Location) {
        let _ = location;
        self.super_ty(ty)
    }
    fn visit_const_operand(&mut self, constant: &mut ConstOperand,
        location: Location) {
        self.super_const_operand(constant, location)
    }
    fn visit_mir_const(&mut self, constant: &mut MirConst,
        location: Location) {
        self.super_mir_const(constant, location)
    }
    fn visit_ty_const(&mut self, constant: &mut TyConst, location: Location) {
        let _ = location;
        self.super_ty_const(constant)
    }
    fn visit_region(&mut self, region: &mut Region, location: Location) {
        let _ = location;
        self.super_region(region)
    }
    fn visit_args(&mut self, args: &mut GenericArgs, location: Location) {
        let _ = location;
        self.super_args(args)
    }
    fn visit_assert_msg(&mut self, msg: &mut AssertMessage,
        location: Location) {
        self.super_assert_msg(msg, location)
    }
    fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo) {
        self.super_var_debug_info(var_debug_info);
    }
    fn super_body(&mut self, body: &mut Body) {
        for bb in body.blocks.iter_mut() { self.visit_basic_block(bb); }
        self.visit_ret_decl(RETURN_LOCAL, body.ret_local_mut());
        for (idx, arg) in body.arg_locals_mut().iter_mut().enumerate() {
            self.visit_arg_decl(idx + 1, arg)
        }
        let local_start = body.arg_count + 1;
        for (idx, arg) in body.inner_locals_mut().iter_mut().enumerate() {
            self.visit_local_decl(idx + local_start, arg)
        }
        for info in body.var_debug_info.iter_mut() {
            self.visit_var_debug_info(info);
        }
        self.visit_span(&mut body.span);
    }
    fn super_basic_block(&mut self, bb: &mut BasicBlock) {
        let BasicBlock { statements, terminator } = bb;
        for stmt in statements {
            self.visit_statement(stmt, Location(stmt.span));
        }
        self.visit_terminator(terminator, Location(terminator.span));
    }
    fn super_local_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        let _ = local;
        let LocalDecl { ty, span, .. } = decl;
        self.visit_ty(ty, Location(*span));
    }
    fn super_ret_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn super_arg_decl(&mut self, local: Local, decl: &mut LocalDecl) {
        self.super_local_decl(local, decl)
    }
    fn super_statement(&mut self, stmt: &mut Statement, location: Location) {
        let Statement { kind, span } = stmt;
        self.visit_span(span);
        match kind {
            StatementKind::Assign(place, rvalue) => {
                self.visit_place(place, PlaceContext::MUTATING, location);
                self.visit_rvalue(rvalue, location);
            }
            StatementKind::FakeRead(_, place) |
                StatementKind::PlaceMention(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location);
            }
            StatementKind::SetDiscriminant { place, .. } => {
                self.visit_place(place, PlaceContext::MUTATING, location);
            }
            StatementKind::StorageLive(local) |
                StatementKind::StorageDead(local) => {
                self.visit_local(local, PlaceContext::NON_USE, location);
            }
            StatementKind::AscribeUserType { place, projections, variance: _ }
                => {
                self.visit_place(place, PlaceContext::NON_USE, location);
                self.visit_user_type_projection(projections);
            }
            StatementKind::Coverage(coverage) => visit_opaque(coverage),
            StatementKind::Intrinsic(intrinsic) =>
                match intrinsic {
                    NonDivergingIntrinsic::Assume(operand) => {
                        self.visit_operand(operand, location);
                    }
                    NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
                        src, dst, count }) => {
                        self.visit_operand(src, location);
                        self.visit_operand(dst, location);
                        self.visit_operand(count, location);
                    }
                },
            StatementKind::ConstEvalCounter | StatementKind::Nop => {}
        }
    }
    fn super_terminator(&mut self, term: &mut Terminator,
        location: Location) {
        let Terminator { kind, span } = term;
        self.visit_span(span);
        match kind {
            TerminatorKind::Goto { .. } | TerminatorKind::Resume |
                TerminatorKind::Abort | TerminatorKind::Unreachable => {}
            TerminatorKind::Assert {
                cond, expected: _, msg, target: _, unwind: _ } => {
                self.visit_operand(cond, location);
                self.visit_assert_msg(msg, location);
            }
            TerminatorKind::Drop { place, target: _, unwind: _ } => {
                self.visit_place(place, PlaceContext::MUTATING, location);
            }
            TerminatorKind::Call {
                func, args, destination, target: _, unwind: _ } => {
                self.visit_operand(func, location);
                for arg in args { self.visit_operand(arg, location); }
                self.visit_place(destination, PlaceContext::MUTATING,
                    location);
            }
            TerminatorKind::InlineAsm { operands, .. } => {
                for op in operands {
                    let InlineAsmOperand { in_value, out_place, raw_rpr: _ } =
                        op;
                    if let Some(input) = in_value {
                        self.visit_operand(input, location);
                    }
                    if let Some(output) = out_place {
                        self.visit_place(output, PlaceContext::MUTATING, location);
                    }
                }
            }
            TerminatorKind::Return => {
                let mut local = RETURN_LOCAL;
                self.visit_local(&mut local, PlaceContext::NON_MUTATING,
                    location);
            }
            TerminatorKind::SwitchInt { discr, targets: _ } => {
                self.visit_operand(discr, location);
            }
        }
    }
    fn super_span(&mut self, span: &mut Span) { let _ = span; }
    fn super_rvalue(&mut self, rvalue: &mut Rvalue, location: Location) {
        match rvalue {
            Rvalue::AddressOf(mutability, place) => {
                let pcx =
                    PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
                self.visit_place(place, pcx, location);
            }
            Rvalue::Aggregate(_, operands) => {
                for op in operands { self.visit_operand(op, location); }
            }
            Rvalue::BinaryOp(_, lhs, rhs) |
                Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
                self.visit_operand(lhs, location);
                self.visit_operand(rhs, location);
            }
            Rvalue::Cast(_, op, ty) => {
                self.visit_operand(op, location);
                self.visit_ty(ty, location);
            }
            Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) |
                Rvalue::Len(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location);
            }
            Rvalue::Ref(region, kind, place) => {
                self.visit_region(region, location);
                let pcx =
                    PlaceContext {
                        is_mut: #[allow(non_exhaustive_omitted_patterns)] match kind
                            {
                            BorrowKind::Mut { .. } => true,
                            _ => false,
                        },
                    };
                self.visit_place(place, pcx, location);
            }
            Rvalue::Repeat(op, constant) => {
                self.visit_operand(op, location);
                self.visit_ty_const(constant, location);
            }
            Rvalue::ThreadLocalRef(_) => {}
            Rvalue::UnaryOp(_, op) | Rvalue::Use(op, _) => {
                self.visit_operand(op, location);
            }
        }
    }
    fn super_operand(&mut self, operand: &mut Operand, location: Location) {
        match operand {
            Operand::Copy(place) | Operand::Move(place) => {
                self.visit_place(place, PlaceContext::NON_MUTATING, location)
            }
            Operand::Constant(constant) => {
                self.visit_const_operand(constant, location);
            }
            Operand::RuntimeChecks(_) => {}
        }
    }
    fn super_user_type_projection(&mut self,
        projection: &mut UserTypeProjection) {
        let _ = projection;
    }
    fn super_ty(&mut self, ty: &mut Ty) { let _ = ty; }
    fn super_const_operand(&mut self, constant: &mut ConstOperand,
        location: Location) {
        let ConstOperand { span, user_ty: _, const_ } = constant;
        self.visit_span(span);
        self.visit_mir_const(const_, location);
    }
    fn super_mir_const(&mut self, constant: &mut MirConst,
        location: Location) {
        let MirConst { kind: _, ty, id: _ } = constant;
        self.visit_ty(ty, location);
    }
    fn super_ty_const(&mut self, constant: &mut TyConst) { let _ = constant; }
    fn super_region(&mut self, region: &mut Region) { let _ = region; }
    fn super_args(&mut self, args: &mut GenericArgs) { let _ = args; }
    fn super_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo) {
        let VarDebugInfo {
                source_info, composite, value, name: _, argument_index: _ } =
            var_debug_info;
        self.visit_span(&mut source_info.span);
        let location = Location(source_info.span);
        if let Some(composite) = composite {
            self.visit_ty(&mut composite.ty, location);
        }
        match value {
            VarDebugInfoContents::Place(place) => {
                self.visit_place(place, PlaceContext::NON_USE, location);
            }
            VarDebugInfoContents::Const(constant) => {
                self.visit_mir_const(&mut constant.const_, location);
            }
        }
    }
    fn super_assert_msg(&mut self, msg: &mut AssertMessage,
        location: Location) {
        match msg {
            AssertMessage::BoundsCheck { len, index } => {
                self.visit_operand(len, location);
                self.visit_operand(index, location);
            }
            AssertMessage::Overflow(_, left, right) => {
                self.visit_operand(left, location);
                self.visit_operand(right, location);
            }
            AssertMessage::OverflowNeg(op) | AssertMessage::DivisionByZero(op)
                | AssertMessage::RemainderByZero(op) |
                AssertMessage::InvalidEnumConstruction(op) => {
                self.visit_operand(op, location);
            }
            AssertMessage::ResumedAfterReturn(_) |
                AssertMessage::ResumedAfterPanic(_) |
                AssertMessage::NullPointerDereference |
                AssertMessage::ResumedAfterDrop(_) => {}
            AssertMessage::MisalignedPointerDereference { required, found } =>
                {
                self.visit_operand(required, location);
                self.visit_operand(found, location);
            }
        }
    }
}make_mir_visitor!(MutMirVisitor, mut);
513
514/// This function is a no-op that gets used to ensure this visitor is kept up-to-date.
515///
516/// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail
517/// when trying to invoke `visit_opaque`.
518///
519/// If you are here because your compilation is broken, replace the failing call to `visit_opaque()`
520/// by a `visit_<CONSTRUCT>` for your construct.
521fn visit_opaque(_: &Opaque) {}
522
523/// The location of a statement / terminator in the code and the CFG.
524#[derive(#[automatically_derived]
impl ::core::clone::Clone for Location {
    #[inline]
    fn clone(&self) -> Location {
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Location { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for Location {
    #[inline]
    fn eq(&self, other: &Location) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Location {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Span>;
    }
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for Location {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Location",
            &&self.0)
    }
}Debug)]
525pub struct Location(Span);
526
527impl Location {
528    pub fn span(&self) -> Span {
529        self.0
530    }
531}
532
533/// Location of the statement at the given index for a given basic block. Assumes that `stmt_idx`
534/// and `bb_idx` are valid for a given body.
535pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location {
536    let bb = &body.blocks[*bb_idx];
537    let stmt = &bb.statements[stmt_idx];
538    Location(stmt.span)
539}
540
541/// Location of the terminator for a given basic block. Assumes that `bb_idx` is valid for a given
542/// body.
543pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location {
544    let bb = &body.blocks[*bb_idx];
545    let terminator = &bb.terminator;
546    Location(terminator.span)
547}
548
549/// Reference to a place used to represent a partial projection.
550pub struct PlaceRef<'a> {
551    pub local: Local,
552    pub projection: &'a [ProjectionElem],
553}
554
555impl PlaceRef<'_> {
556    /// Get the type of this place.
557    pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
558        self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
559    }
560}
561
562/// Information about a place's usage.
563#[derive(#[automatically_derived]
impl ::core::marker::Copy for PlaceContext { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PlaceContext {
    #[inline]
    fn clone(&self) -> PlaceContext {
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for PlaceContext {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "PlaceContext",
            "is_mut", &&self.is_mut)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for PlaceContext {
    #[inline]
    fn eq(&self, other: &PlaceContext) -> bool { self.is_mut == other.is_mut }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PlaceContext {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for PlaceContext {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.is_mut, state)
    }
}Hash)]
564pub struct PlaceContext {
565    /// Whether the access is mutable or not. Keep this private so we can increment the type in a
566    /// backward compatible manner.
567    is_mut: bool,
568}
569
570impl PlaceContext {
571    const MUTATING: Self = PlaceContext { is_mut: true };
572    const NON_MUTATING: Self = PlaceContext { is_mut: false };
573    const NON_USE: Self = PlaceContext { is_mut: false };
574
575    pub fn is_mutating(&self) -> bool {
576        self.is_mut
577    }
578}