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 | StatementKind::Deinit(place)
174 | StatementKind::Retag(_, place) => {
175 self.visit_place(place, PlaceContext::MUTATING, location);
176 }
177 StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
178 self.visit_local(local, PlaceContext::NON_USE, location);
179 }
180 StatementKind::AscribeUserType { place, projections, variance: _ } => {
181 self.visit_place(place, PlaceContext::NON_USE, location);
182 self.visit_user_type_projection(projections);
183 }
184 StatementKind::Coverage(coverage) => visit_opaque(coverage),
185 StatementKind::Intrinsic(intrisic) => match intrisic {
186 NonDivergingIntrinsic::Assume(operand) => {
187 self.visit_operand(operand, location);
188 }
189 NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
190 src,
191 dst,
192 count,
193 }) => {
194 self.visit_operand(src, location);
195 self.visit_operand(dst, location);
196 self.visit_operand(count, location);
197 }
198 },
199 StatementKind::ConstEvalCounter | StatementKind::Nop => {}
200 }
201 }
202
203 fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) {
204 let Terminator { kind, span } = term;
205 self.visit_span(span);
206 match kind {
207 TerminatorKind::Goto { .. }
208 | TerminatorKind::Resume
209 | TerminatorKind::Abort
210 | TerminatorKind::Unreachable => {}
211 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
212 self.visit_operand(cond, location);
213 self.visit_assert_msg(msg, location);
214 }
215 TerminatorKind::Drop { place, target: _, unwind: _ } => {
216 self.visit_place(place, PlaceContext::MUTATING, location);
217 }
218 TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
219 self.visit_operand(func, location);
220 for arg in args {
221 self.visit_operand(arg, location);
222 }
223 self.visit_place(destination, PlaceContext::MUTATING, location);
224 }
225 TerminatorKind::InlineAsm { operands, .. } => {
226 for op in operands {
227 let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
228 if let Some(input) = in_value {
229 self.visit_operand(input, location);
230 }
231 if let Some(output) = out_place {
232 self.visit_place(output, PlaceContext::MUTATING, location);
233 }
234 }
235 }
236 TerminatorKind::Return => {
237 let $($mutability)? local = RETURN_LOCAL;
238 self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location);
239 }
240 TerminatorKind::SwitchInt { discr, targets: _ } => {
241 self.visit_operand(discr, location);
242 }
243 }
244 }
245
246 fn super_span(&mut self, span: &$($mutability)? Span) {
247 let _ = span;
248 }
249
250 fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) {
251 match rvalue {
252 Rvalue::AddressOf(mutability, place) => {
253 let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
254 self.visit_place(place, pcx, location);
255 }
256 Rvalue::Aggregate(_, operands) => {
257 for op in operands {
258 self.visit_operand(op, location);
259 }
260 }
261 Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
262 self.visit_operand(lhs, location);
263 self.visit_operand(rhs, location);
264 }
265 Rvalue::Cast(_, op, ty) => {
266 self.visit_operand(op, location);
267 self.visit_ty(ty, location);
268 }
269 Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
270 self.visit_place(place, PlaceContext::NON_MUTATING, location);
271 }
272 Rvalue::Ref(region, kind, place) => {
273 self.visit_region(region, location);
274 let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
275 self.visit_place(place, pcx, location);
276 }
277 Rvalue::Repeat(op, constant) => {
278 self.visit_operand(op, location);
279 self.visit_ty_const(constant, location);
280 }
281 Rvalue::ShallowInitBox(op, ty) => {
282 self.visit_ty(ty, location);
283 self.visit_operand(op, location)
284 }
285 Rvalue::ThreadLocalRef(_) => {}
286 Rvalue::NullaryOp(_, ty) => {
287 self.visit_ty(ty, location);
288 }
289 Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
290 self.visit_operand(op, location);
291 }
292 }
293 }
294
295 fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
296 match operand {
297 Operand::Copy(place) | Operand::Move(place) => {
298 self.visit_place(place, PlaceContext::NON_MUTATING, location)
299 }
300 Operand::Constant(constant) => {
301 self.visit_const_operand(constant, location);
302 }
303 }
304 }
305
306 fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
307 let _ = projection;
309 }
310
311 fn super_ty(&mut self, ty: &$($mutability)? Ty) {
312 let _ = ty;
313 }
314
315 fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
316 let ConstOperand { span, user_ty: _, const_ } = constant;
317 self.visit_span(span);
318 self.visit_mir_const(const_, location);
319 }
320
321 fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
322 let MirConst { kind: _, ty, id: _ } = constant;
323 self.visit_ty(ty, location);
324 }
325
326 fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) {
327 let _ = constant;
328 }
329
330 fn super_region(&mut self, region: &$($mutability)? Region) {
331 let _ = region;
332 }
333
334 fn super_args(&mut self, args: &$($mutability)? GenericArgs) {
335 let _ = args;
336 }
337
338 fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
339 let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
340 var_debug_info;
341 self.visit_span(&$($mutability)? source_info.span);
342 let location = Location(source_info.span);
343 if let Some(composite) = composite {
344 self.visit_ty(&$($mutability)? composite.ty, location);
345 }
346 match value {
347 VarDebugInfoContents::Place(place) => {
348 self.visit_place(place, PlaceContext::NON_USE, location);
349 }
350 VarDebugInfoContents::Const(constant) => {
351 self.visit_mir_const(&$($mutability)? constant.const_, location);
352 }
353 }
354 }
355
356 fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
357 match msg {
358 AssertMessage::BoundsCheck { len, index } => {
359 self.visit_operand(len, location);
360 self.visit_operand(index, location);
361 }
362 AssertMessage::Overflow(_, left, right) => {
363 self.visit_operand(left, location);
364 self.visit_operand(right, location);
365 }
366 AssertMessage::OverflowNeg(op)
367 | AssertMessage::DivisionByZero(op)
368 | AssertMessage::RemainderByZero(op) => {
369 self.visit_operand(op, location);
370 }
371 AssertMessage::ResumedAfterReturn(_)
372 | AssertMessage::ResumedAfterPanic(_)
373 | AssertMessage::NullPointerDereference => {
374 }
376 AssertMessage::MisalignedPointerDereference { required, found } => {
377 self.visit_operand(required, location);
378 self.visit_operand(found, location);
379 }
380 }
381 }
382 }
383 };
384}
385
386macro_rules! super_body {
387 ($self:ident, $body:ident, mut) => {
388 for bb in $body.blocks.iter_mut() {
389 $self.visit_basic_block(bb);
390 }
391
392 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut());
393
394 for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() {
395 $self.visit_arg_decl(idx + 1, arg)
396 }
397
398 let local_start = $body.arg_count + 1;
399 for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() {
400 $self.visit_local_decl(idx + local_start, arg)
401 }
402
403 for info in $body.var_debug_info.iter_mut() {
404 $self.visit_var_debug_info(info);
405 }
406
407 $self.visit_span(&mut $body.span)
408 };
409
410 ($self:ident, $body:ident, ) => {
411 let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body;
412
413 for bb in blocks {
414 $self.visit_basic_block(bb);
415 }
416
417 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local());
418
419 for (idx, arg) in $body.arg_locals().iter().enumerate() {
420 $self.visit_arg_decl(idx + 1, arg)
421 }
422
423 let local_start = arg_count + 1;
424 for (idx, arg) in $body.inner_locals().iter().enumerate() {
425 $self.visit_local_decl(idx + local_start, arg)
426 }
427
428 for info in var_debug_info.iter() {
429 $self.visit_var_debug_info(info);
430 }
431
432 $self.visit_span(span)
433 };
434}
435
436macro_rules! visit_place_fns {
437 (mut) => {
438 fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) {
439 self.visit_local(&mut place.local, ptx, location);
440
441 for elem in place.projection.iter_mut() {
442 self.visit_projection_elem(elem, ptx, location);
443 }
444 }
445
446 fn visit_projection_elem(
450 &mut self,
451 elem: &mut ProjectionElem,
452 ptx: PlaceContext,
453 location: Location,
454 ) {
455 self.super_projection_elem(elem, ptx, location)
456 }
457
458 fn super_projection_elem(
459 &mut self,
460 elem: &mut ProjectionElem,
461 ptx: PlaceContext,
462 location: Location,
463 ) {
464 match elem {
465 ProjectionElem::Deref => {}
466 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
467 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
468 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
469 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
470 ProjectionElem::Downcast(_idx) => {}
471 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
472 ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
473 }
474 }
475 };
476
477 () => {
478 fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
479 self.visit_local(&place.local, ptx, location);
480
481 for (idx, elem) in place.projection.iter().enumerate() {
482 let place_ref =
483 PlaceRef { local: place.local, projection: &place.projection[..idx] };
484 self.visit_projection_elem(place_ref, elem, ptx, location);
485 }
486 }
487
488 fn visit_projection_elem<'a>(
489 &mut self,
490 place_ref: PlaceRef<'a>,
491 elem: &ProjectionElem,
492 ptx: PlaceContext,
493 location: Location,
494 ) {
495 let _ = place_ref;
496 self.super_projection_elem(elem, ptx, location);
497 }
498
499 fn super_projection_elem(
500 &mut self,
501 elem: &ProjectionElem,
502 ptx: PlaceContext,
503 location: Location,
504 ) {
505 match elem {
506 ProjectionElem::Deref => {}
507 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
508 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
509 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
510 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
511 ProjectionElem::Downcast(_idx) => {}
512 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
513 ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
514 }
515 }
516 };
517}
518
519make_mir_visitor!(MirVisitor,);
520make_mir_visitor!(MutMirVisitor, mut);
521
522fn visit_opaque(_: &Opaque) {}
530
531#[derive(Clone, Copy, PartialEq, Eq, Debug)]
533pub struct Location(Span);
534
535impl Location {
536 pub fn span(&self) -> Span {
537 self.0
538 }
539}
540
541pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location {
544 let bb = &body.blocks[*bb_idx];
545 let stmt = &bb.statements[stmt_idx];
546 Location(stmt.span)
547}
548
549pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location {
552 let bb = &body.blocks[*bb_idx];
553 let terminator = &bb.terminator;
554 Location(terminator.span)
555}
556
557pub struct PlaceRef<'a> {
559 pub local: Local,
560 pub projection: &'a [ProjectionElem],
561}
562
563impl PlaceRef<'_> {
564 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
566 self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?))
567 }
568}
569
570#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
572pub struct PlaceContext {
573 is_mut: bool,
576}
577
578impl PlaceContext {
579 const MUTATING: Self = PlaceContext { is_mut: true };
580 const NON_MUTATING: Self = PlaceContext { is_mut: false };
581 const NON_USE: Self = PlaceContext { is_mut: false };
582
583 pub fn is_mutating(&self) -> bool {
584 self.is_mut
585 }
586}