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