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(intrinsic) => match intrinsic {
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(_) => {}
286 Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
287 self.visit_operand(op, location);
288 }
289 }
290 }
291
292 fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
293 match operand {
294 Operand::Copy(place) | Operand::Move(place) => {
295 self.visit_place(place, PlaceContext::NON_MUTATING, location)
296 }
297 Operand::Constant(constant) => {
298 self.visit_const_operand(constant, location);
299 }
300 }
301 }
302
303 fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
304 let _ = projection;
306 }
307
308 fn super_ty(&mut self, ty: &$($mutability)? Ty) {
309 let _ = ty;
310 }
311
312 fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
313 let ConstOperand { span, user_ty: _, const_ } = constant;
314 self.visit_span(span);
315 self.visit_mir_const(const_, location);
316 }
317
318 fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
319 let MirConst { kind: _, ty, id: _ } = constant;
320 self.visit_ty(ty, location);
321 }
322
323 fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) {
324 let _ = constant;
325 }
326
327 fn super_region(&mut self, region: &$($mutability)? Region) {
328 let _ = region;
329 }
330
331 fn super_args(&mut self, args: &$($mutability)? GenericArgs) {
332 let _ = args;
333 }
334
335 fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
336 let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
337 var_debug_info;
338 self.visit_span(&$($mutability)? source_info.span);
339 let location = Location(source_info.span);
340 if let Some(composite) = composite {
341 self.visit_ty(&$($mutability)? composite.ty, location);
342 }
343 match value {
344 VarDebugInfoContents::Place(place) => {
345 self.visit_place(place, PlaceContext::NON_USE, location);
346 }
347 VarDebugInfoContents::Const(constant) => {
348 self.visit_mir_const(&$($mutability)? constant.const_, location);
349 }
350 }
351 }
352
353 fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
354 match msg {
355 AssertMessage::BoundsCheck { len, index } => {
356 self.visit_operand(len, location);
357 self.visit_operand(index, location);
358 }
359 AssertMessage::Overflow(_, left, right) => {
360 self.visit_operand(left, location);
361 self.visit_operand(right, location);
362 }
363 AssertMessage::OverflowNeg(op)
364 | AssertMessage::DivisionByZero(op)
365 | AssertMessage::RemainderByZero(op)
366 | AssertMessage::InvalidEnumConstruction(op) => {
367 self.visit_operand(op, location);
368 }
369 AssertMessage::ResumedAfterReturn(_)
370 | AssertMessage::ResumedAfterPanic(_)
371 | AssertMessage::NullPointerDereference
372 | AssertMessage::ResumedAfterDrop(_) => {
373 }
375 AssertMessage::MisalignedPointerDereference { required, found } => {
376 self.visit_operand(required, location);
377 self.visit_operand(found, location);
378 }
379 }
380 }
381 }
382 };
383}
384
385macro_rules! super_body {
386 ($self:ident, $body:ident, mut) => {
387 for bb in $body.blocks.iter_mut() {
388 $self.visit_basic_block(bb);
389 }
390
391 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut());
392
393 for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() {
394 $self.visit_arg_decl(idx + 1, arg)
395 }
396
397 let local_start = $body.arg_count + 1;
398 for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() {
399 $self.visit_local_decl(idx + local_start, arg)
400 }
401
402 for info in $body.var_debug_info.iter_mut() {
403 $self.visit_var_debug_info(info);
404 }
405
406 $self.visit_span(&mut $body.span)
407 };
408
409 ($self:ident, $body:ident, ) => {
410 let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body;
411
412 for bb in blocks {
413 $self.visit_basic_block(bb);
414 }
415
416 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local());
417
418 for (idx, arg) in $body.arg_locals().iter().enumerate() {
419 $self.visit_arg_decl(idx + 1, arg)
420 }
421
422 let local_start = arg_count + 1;
423 for (idx, arg) in $body.inner_locals().iter().enumerate() {
424 $self.visit_local_decl(idx + local_start, arg)
425 }
426
427 for info in var_debug_info.iter() {
428 $self.visit_var_debug_info(info);
429 }
430
431 $self.visit_span(span)
432 };
433}
434
435macro_rules! visit_place_fns {
436 (mut) => {
437 fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) {
438 self.visit_local(&mut place.local, ptx, location);
439
440 for elem in place.projection.iter_mut() {
441 self.visit_projection_elem(elem, ptx, location);
442 }
443 }
444
445 fn visit_projection_elem(
449 &mut self,
450 elem: &mut ProjectionElem,
451 ptx: PlaceContext,
452 location: Location,
453 ) {
454 self.super_projection_elem(elem, ptx, location)
455 }
456
457 fn super_projection_elem(
458 &mut self,
459 elem: &mut ProjectionElem,
460 ptx: PlaceContext,
461 location: Location,
462 ) {
463 match elem {
464 ProjectionElem::Deref => {}
465 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
466 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
467 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
468 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
469 ProjectionElem::Downcast(_idx) => {}
470 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
471 }
472 }
473 };
474
475 () => {
476 fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
477 self.visit_local(&place.local, ptx, location);
478
479 for (idx, elem) in place.projection.iter().enumerate() {
480 let place_ref =
481 PlaceRef { local: place.local, projection: &place.projection[..idx] };
482 self.visit_projection_elem(place_ref, elem, ptx, location);
483 }
484 }
485
486 fn visit_projection_elem<'a>(
487 &mut self,
488 place_ref: PlaceRef<'a>,
489 elem: &ProjectionElem,
490 ptx: PlaceContext,
491 location: Location,
492 ) {
493 let _ = place_ref;
494 self.super_projection_elem(elem, ptx, location);
495 }
496
497 fn super_projection_elem(
498 &mut self,
499 elem: &ProjectionElem,
500 ptx: PlaceContext,
501 location: Location,
502 ) {
503 match elem {
504 ProjectionElem::Deref => {}
505 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
506 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
507 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
508 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
509 ProjectionElem::Downcast(_idx) => {}
510 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
511 }
512 }
513 };
514}
515
516make_mir_visitor!(MirVisitor,);
517make_mir_visitor!(MutMirVisitor, mut);
518
519fn visit_opaque(_: &Opaque) {}
527
528#[derive(Clone, Copy, PartialEq, Eq, Debug)]
530pub struct Location(Span);
531
532impl Location {
533 pub fn span(&self) -> Span {
534 self.0
535 }
536}
537
538pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location {
541 let bb = &body.blocks[*bb_idx];
542 let stmt = &bb.statements[stmt_idx];
543 Location(stmt.span)
544}
545
546pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location {
549 let bb = &body.blocks[*bb_idx];
550 let terminator = &bb.terminator;
551 Location(terminator.span)
552}
553
554pub struct PlaceRef<'a> {
556 pub local: Local,
557 pub projection: &'a [ProjectionElem],
558}
559
560impl PlaceRef<'_> {
561 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
563 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
564 }
565}
566
567#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
569pub struct PlaceContext {
570 is_mut: bool,
573}
574
575impl PlaceContext {
576 const MUTATING: Self = PlaceContext { is_mut: true };
577 const NON_MUTATING: Self = PlaceContext { is_mut: false };
578 const NON_USE: Self = PlaceContext { is_mut: false };
579
580 pub fn is_mutating(&self) -> bool {
581 self.is_mut
582 }
583}