1use 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 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 }
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 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
514fn visit_opaque(_: &Opaque) {}
522
523#[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
533pub 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
541pub 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
549pub struct PlaceRef<'a> {
551 pub local: Local,
552 pub projection: &'a [ProjectionElem],
553}
554
555impl PlaceRef<'_> {
556 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#[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 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}