1use std::slice;
4
5use rustc_ast::InlineAsmOptions;
6use rustc_data_structures::packed::Pu128;
7use rustc_hir::LangItem;
8use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
9use smallvec::{SmallVec, smallvec};
10
11use super::*;
12
13impl SwitchTargets {
14 pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
19 let (values, mut targets): (SmallVec<_>, SmallVec<_>) =
20 targets.map(|(v, t)| (Pu128(v), t)).unzip();
21 targets.push(otherwise);
22 Self { values, targets }
23 }
24
25 pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
28 Self { values: smallvec![Pu128(value)], targets: smallvec![then, else_] }
29 }
30
31 #[inline]
33 pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> {
34 if let &[value] = &self.values[..]
35 && let &[then, else_] = &self.targets[..]
36 {
37 Some((value.get(), then, else_))
38 } else {
39 None
40 }
41 }
42
43 #[inline]
45 pub fn otherwise(&self) -> BasicBlock {
46 *self.targets.last().unwrap()
47 }
48
49 #[inline]
56 pub fn iter(&self) -> SwitchTargetsIter<'_> {
57 SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) }
58 }
59
60 #[inline]
62 pub fn all_targets(&self) -> &[BasicBlock] {
63 &self.targets
64 }
65
66 #[inline]
67 pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
68 &mut self.targets
69 }
70
71 #[inline]
73 pub fn all_values(&self) -> &[Pu128] {
74 &self.values
75 }
76
77 #[inline]
78 pub fn all_values_mut(&mut self) -> &mut [Pu128] {
79 &mut self.values
80 }
81
82 #[inline]
86 pub fn target_for_value(&self, value: u128) -> BasicBlock {
87 self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
88 }
89
90 #[inline]
92 pub fn add_target(&mut self, value: u128, bb: BasicBlock) {
93 let value = Pu128(value);
94 if self.values.contains(&value) {
95 bug!("target value {:?} already present", value);
96 }
97 self.values.push(value);
98 self.targets.insert(self.targets.len() - 1, bb);
99 }
100
101 #[inline]
103 pub fn is_distinct(&self) -> bool {
104 self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len()
105 }
106}
107
108pub struct SwitchTargetsIter<'a> {
109 inner: iter::Zip<slice::Iter<'a, Pu128>, slice::Iter<'a, BasicBlock>>,
110}
111
112impl<'a> Iterator for SwitchTargetsIter<'a> {
113 type Item = (u128, BasicBlock);
114
115 #[inline]
116 fn next(&mut self) -> Option<Self::Item> {
117 self.inner.next().map(|(val, bb)| (val.get(), *bb))
118 }
119
120 #[inline]
121 fn size_hint(&self) -> (usize, Option<usize>) {
122 self.inner.size_hint()
123 }
124}
125
126impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
127
128impl UnwindAction {
129 fn cleanup_block(self) -> Option<BasicBlock> {
130 match self {
131 UnwindAction::Cleanup(bb) => Some(bb),
132 UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
133 }
134 }
135}
136
137impl UnwindTerminateReason {
138 pub fn as_str(self) -> &'static str {
139 match self {
141 UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
142 UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
143 }
144 }
145
146 pub fn as_short_str(self) -> &'static str {
148 match self {
149 UnwindTerminateReason::Abi => "abi",
150 UnwindTerminateReason::InCleanup => "cleanup",
151 }
152 }
153
154 pub fn lang_item(self) -> LangItem {
155 match self {
156 UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
157 UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
158 }
159 }
160}
161
162impl<O> AssertKind<O> {
163 pub fn is_optional_overflow_check(&self) -> bool {
165 use AssertKind::*;
166 use BinOp::*;
167 matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
168 }
169
170 pub fn panic_function(&self) -> LangItem {
177 use AssertKind::*;
178 match self {
179 Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
180 Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
181 Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
182 Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
183 Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
184 OverflowNeg(_) => LangItem::PanicNegOverflow,
185 Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
186 Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
187 Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
188 DivisionByZero(_) => LangItem::PanicDivZero,
189 RemainderByZero(_) => LangItem::PanicRemZero,
190 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
191 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
192 LangItem::PanicAsyncFnResumed
193 }
194 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
195 LangItem::PanicAsyncGenFnResumed
196 }
197 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
198 LangItem::PanicGenFnNone
199 }
200 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
201 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
202 LangItem::PanicAsyncFnResumedPanic
203 }
204 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
205 LangItem::PanicAsyncGenFnResumedPanic
206 }
207 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
208 LangItem::PanicGenFnNonePanic
209 }
210 NullPointerDereference => LangItem::PanicNullPointerDereference,
211
212 BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
213 bug!("Unexpected AssertKind")
214 }
215 }
216 }
217
218 pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
225 where
226 O: Debug,
227 {
228 use AssertKind::*;
229 match self {
230 BoundsCheck { len, index } => write!(
231 f,
232 "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
233 ),
234
235 OverflowNeg(op) => {
236 write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
237 }
238 DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
239 RemainderByZero(op) => write!(
240 f,
241 "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
242 ),
243 Overflow(BinOp::Add, l, r) => write!(
244 f,
245 "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
246 ),
247 Overflow(BinOp::Sub, l, r) => write!(
248 f,
249 "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
250 ),
251 Overflow(BinOp::Mul, l, r) => write!(
252 f,
253 "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
254 ),
255 Overflow(BinOp::Div, l, r) => write!(
256 f,
257 "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
258 ),
259 Overflow(BinOp::Rem, l, r) => write!(
260 f,
261 "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
262 ),
263 Overflow(BinOp::Shr, _, r) => {
264 write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {r:?}")
265 }
266 Overflow(BinOp::Shl, _, r) => {
267 write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
268 }
269 Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
270 MisalignedPointerDereference { required, found } => {
271 write!(
272 f,
273 "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
274 )
275 }
276 NullPointerDereference => write!(f, "\"null pointer dereference occurred\""),
277 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
278 write!(f, "\"coroutine resumed after completion\"")
279 }
280 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
281 write!(f, "\"`async fn` resumed after completion\"")
282 }
283 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
284 write!(f, "\"`async gen fn` resumed after completion\"")
285 }
286 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
287 write!(f, "\"`gen fn` should just keep returning `None` after completion\"")
288 }
289 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
290 write!(f, "\"coroutine resumed after panicking\"")
291 }
292 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
293 write!(f, "\"`async fn` resumed after panicking\"")
294 }
295 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
296 write!(f, "\"`async gen fn` resumed after panicking\"")
297 }
298 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
299 write!(f, "\"`gen fn` should just keep returning `None` after panicking\"")
300 }
301 }
302 }
303
304 pub fn diagnostic_message(&self) -> DiagMessage {
311 use AssertKind::*;
312
313 use crate::fluent_generated::*;
314
315 match self {
316 BoundsCheck { .. } => middle_bounds_check,
317 Overflow(BinOp::Shl, _, _) => middle_assert_shl_overflow,
318 Overflow(BinOp::Shr, _, _) => middle_assert_shr_overflow,
319 Overflow(_, _, _) => middle_assert_op_overflow,
320 OverflowNeg(_) => middle_assert_overflow_neg,
321 DivisionByZero(_) => middle_assert_divide_by_zero,
322 RemainderByZero(_) => middle_assert_remainder_by_zero,
323 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
324 middle_assert_async_resume_after_return
325 }
326 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
327 todo!()
328 }
329 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
330 bug!("gen blocks can be resumed after they return and will keep returning `None`")
331 }
332 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
333 middle_assert_coroutine_resume_after_return
334 }
335 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
336 middle_assert_async_resume_after_panic
337 }
338 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
339 todo!()
340 }
341 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
342 middle_assert_gen_resume_after_panic
343 }
344 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
345 middle_assert_coroutine_resume_after_panic
346 }
347 NullPointerDereference => middle_assert_null_ptr_deref,
348 MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref,
349 }
350 }
351
352 pub fn add_args(self, adder: &mut dyn FnMut(DiagArgName, DiagArgValue))
353 where
354 O: fmt::Debug,
355 {
356 use AssertKind::*;
357
358 macro_rules! add {
359 ($name: expr, $value: expr) => {
360 adder($name.into(), $value.into_diag_arg(&mut None));
361 };
362 }
363
364 match self {
365 BoundsCheck { len, index } => {
366 add!("len", format!("{len:?}"));
367 add!("index", format!("{index:?}"));
368 }
369 Overflow(BinOp::Shl | BinOp::Shr, _, val)
370 | DivisionByZero(val)
371 | RemainderByZero(val)
372 | OverflowNeg(val) => {
373 add!("val", format!("{val:#?}"));
374 }
375 Overflow(binop, left, right) => {
376 add!("op", binop.to_hir_binop().as_str());
377 add!("left", format!("{left:#?}"));
378 add!("right", format!("{right:#?}"));
379 }
380 ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {}
381 MisalignedPointerDereference { required, found } => {
382 add!("required", format!("{required:#?}"));
383 add!("found", format!("{found:#?}"));
384 }
385 }
386 }
387}
388
389#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
390pub struct Terminator<'tcx> {
391 pub source_info: SourceInfo,
392 pub kind: TerminatorKind<'tcx>,
393}
394
395impl<'tcx> Terminator<'tcx> {
396 #[inline]
397 pub fn successors(&self) -> Successors<'_> {
398 self.kind.successors()
399 }
400
401 #[inline]
402 pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
403 self.kind.successors_mut()
404 }
405
406 #[inline]
407 pub fn unwind(&self) -> Option<&UnwindAction> {
408 self.kind.unwind()
409 }
410
411 #[inline]
412 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
413 self.kind.unwind_mut()
414 }
415}
416
417impl<'tcx> TerminatorKind<'tcx> {
418 pub const fn name(&self) -> &'static str {
421 match self {
422 TerminatorKind::Goto { .. } => "Goto",
423 TerminatorKind::SwitchInt { .. } => "SwitchInt",
424 TerminatorKind::UnwindResume => "UnwindResume",
425 TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
426 TerminatorKind::Return => "Return",
427 TerminatorKind::Unreachable => "Unreachable",
428 TerminatorKind::Drop { .. } => "Drop",
429 TerminatorKind::Call { .. } => "Call",
430 TerminatorKind::TailCall { .. } => "TailCall",
431 TerminatorKind::Assert { .. } => "Assert",
432 TerminatorKind::Yield { .. } => "Yield",
433 TerminatorKind::CoroutineDrop => "CoroutineDrop",
434 TerminatorKind::FalseEdge { .. } => "FalseEdge",
435 TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
436 TerminatorKind::InlineAsm { .. } => "InlineAsm",
437 }
438 }
439
440 #[inline]
441 pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
442 TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
443 }
444}
445
446pub use helper::*;
447
448mod helper {
449 use super::*;
450 pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
451 pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;
452
453 impl SwitchTargets {
454 #[inline]
457 #[cfg_attr(not(bootstrap), define_opaque(Successors))]
458 pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
459 let target = self.target_for_value(value);
460 (&[]).into_iter().copied().chain(Some(target))
461 }
462 }
463
464 impl<'tcx> TerminatorKind<'tcx> {
465 #[inline]
466 #[cfg_attr(not(bootstrap), define_opaque(Successors))]
467 pub fn successors(&self) -> Successors<'_> {
468 use self::TerminatorKind::*;
469 match *self {
470 Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
471 | Yield { resume: ref t, drop: Some(u), .. }
472 | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
473 | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
474 | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
475 slice::from_ref(t).into_iter().copied().chain(Some(u))
476 }
477 Goto { target: ref t }
478 | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
479 | Call { target: Some(ref t), unwind: _, .. }
480 | Yield { resume: ref t, drop: None, .. }
481 | Drop { target: ref t, unwind: _, .. }
482 | Assert { target: ref t, unwind: _, .. }
483 | FalseUnwind { real_target: ref t, unwind: _ } => {
484 slice::from_ref(t).into_iter().copied().chain(None)
485 }
486 UnwindResume
487 | UnwindTerminate(_)
488 | CoroutineDrop
489 | Return
490 | Unreachable
491 | TailCall { .. }
492 | Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
493 InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
494 targets.iter().copied().chain(Some(u))
495 }
496 InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
497 SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
498 FalseEdge { ref real_target, imaginary_target } => {
499 slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
500 }
501 }
502 }
503
504 #[inline]
505 #[cfg_attr(not(bootstrap), define_opaque(SuccessorsMut))]
506 pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
507 use self::TerminatorKind::*;
508 match *self {
509 Call {
510 target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), ..
511 }
512 | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
513 | Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
514 | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
515 | FalseUnwind {
516 real_target: ref mut t,
517 unwind: UnwindAction::Cleanup(ref mut u),
518 } => slice::from_mut(t).into_iter().chain(Some(u)),
519 Goto { target: ref mut t }
520 | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
521 | Call { target: Some(ref mut t), unwind: _, .. }
522 | Yield { resume: ref mut t, drop: None, .. }
523 | Drop { target: ref mut t, unwind: _, .. }
524 | Assert { target: ref mut t, unwind: _, .. }
525 | FalseUnwind { real_target: ref mut t, unwind: _ } => {
526 slice::from_mut(t).into_iter().chain(None)
527 }
528 UnwindResume
529 | UnwindTerminate(_)
530 | CoroutineDrop
531 | Return
532 | Unreachable
533 | TailCall { .. }
534 | Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
535 InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
536 targets.iter_mut().chain(Some(u))
537 }
538 InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
539 SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
540 FalseEdge { ref mut real_target, ref mut imaginary_target } => {
541 slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
542 }
543 }
544 }
545 }
546}
547
548impl<'tcx> TerminatorKind<'tcx> {
549 #[inline]
550 pub fn unwind(&self) -> Option<&UnwindAction> {
551 match *self {
552 TerminatorKind::Goto { .. }
553 | TerminatorKind::UnwindResume
554 | TerminatorKind::UnwindTerminate(_)
555 | TerminatorKind::Return
556 | TerminatorKind::TailCall { .. }
557 | TerminatorKind::Unreachable
558 | TerminatorKind::CoroutineDrop
559 | TerminatorKind::Yield { .. }
560 | TerminatorKind::SwitchInt { .. }
561 | TerminatorKind::FalseEdge { .. } => None,
562 TerminatorKind::Call { ref unwind, .. }
563 | TerminatorKind::Assert { ref unwind, .. }
564 | TerminatorKind::Drop { ref unwind, .. }
565 | TerminatorKind::FalseUnwind { ref unwind, .. }
566 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
567 }
568 }
569
570 #[inline]
571 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
572 match *self {
573 TerminatorKind::Goto { .. }
574 | TerminatorKind::UnwindResume
575 | TerminatorKind::UnwindTerminate(_)
576 | TerminatorKind::Return
577 | TerminatorKind::TailCall { .. }
578 | TerminatorKind::Unreachable
579 | TerminatorKind::CoroutineDrop
580 | TerminatorKind::Yield { .. }
581 | TerminatorKind::SwitchInt { .. }
582 | TerminatorKind::FalseEdge { .. } => None,
583 TerminatorKind::Call { ref mut unwind, .. }
584 | TerminatorKind::Assert { ref mut unwind, .. }
585 | TerminatorKind::Drop { ref mut unwind, .. }
586 | TerminatorKind::FalseUnwind { ref mut unwind, .. }
587 | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
588 }
589 }
590
591 #[inline]
592 pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> {
593 match self {
594 TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)),
595 _ => None,
596 }
597 }
598
599 #[inline]
600 pub fn as_goto(&self) -> Option<BasicBlock> {
601 match self {
602 TerminatorKind::Goto { target } => Some(*target),
603 _ => None,
604 }
605 }
606}
607
608#[derive(Copy, Clone, Debug)]
609pub enum TerminatorEdges<'mir, 'tcx> {
610 None,
612 Single(BasicBlock),
615 Double(BasicBlock, BasicBlock),
618 AssignOnReturn {
620 return_: &'mir [BasicBlock],
621 cleanup: Option<BasicBlock>,
623 place: CallReturnPlaces<'mir, 'tcx>,
624 },
625 SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> },
627}
628
629#[derive(Copy, Clone, Debug)]
632pub enum CallReturnPlaces<'a, 'tcx> {
633 Call(Place<'tcx>),
634 Yield(Place<'tcx>),
635 InlineAsm(&'a [InlineAsmOperand<'tcx>]),
636}
637
638impl<'tcx> CallReturnPlaces<'_, 'tcx> {
639 pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) {
640 match *self {
641 Self::Call(place) | Self::Yield(place) => f(place),
642 Self::InlineAsm(operands) => {
643 for op in operands {
644 match *op {
645 InlineAsmOperand::Out { place: Some(place), .. }
646 | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
647 _ => {}
648 }
649 }
650 }
651 }
652 }
653}
654
655impl<'tcx> Terminator<'tcx> {
656 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
657 self.kind.edges()
658 }
659}
660
661impl<'tcx> TerminatorKind<'tcx> {
662 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
663 use TerminatorKind::*;
664 match *self {
665 Return
666 | TailCall { .. }
667 | UnwindResume
668 | UnwindTerminate(_)
669 | CoroutineDrop
670 | Unreachable => TerminatorEdges::None,
671
672 Goto { target } => TerminatorEdges::Single(target),
673
674 Assert { target, unwind, expected: _, msg: _, cond: _ }
675 | Drop { target, unwind, place: _, replace: _ }
676 | FalseUnwind { real_target: target, unwind } => match unwind {
677 UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
678 UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
679 TerminatorEdges::Single(target)
680 }
681 },
682
683 FalseEdge { real_target, imaginary_target } => {
684 TerminatorEdges::Double(real_target, imaginary_target)
685 }
686
687 Yield { resume: ref target, drop, resume_arg, value: _ } => {
688 TerminatorEdges::AssignOnReturn {
689 return_: slice::from_ref(target),
690 cleanup: drop,
691 place: CallReturnPlaces::Yield(resume_arg),
692 }
693 }
694
695 Call {
696 unwind,
697 destination,
698 ref target,
699 func: _,
700 args: _,
701 fn_span: _,
702 call_source: _,
703 } => TerminatorEdges::AssignOnReturn {
704 return_: target.as_ref().map(slice::from_ref).unwrap_or_default(),
705 cleanup: unwind.cleanup_block(),
706 place: CallReturnPlaces::Call(destination),
707 },
708
709 InlineAsm {
710 asm_macro: _,
711 template: _,
712 ref operands,
713 options: _,
714 line_spans: _,
715 ref targets,
716 unwind,
717 } => TerminatorEdges::AssignOnReturn {
718 return_: targets,
719 cleanup: unwind.cleanup_block(),
720 place: CallReturnPlaces::InlineAsm(operands),
721 },
722
723 SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr },
724 }
725 }
726}
727
728impl CallSource {
729 pub fn from_hir_call(self) -> bool {
730 matches!(self, CallSource::Normal)
731 }
732}
733
734impl InlineAsmMacro {
735 pub const fn diverges(self, options: InlineAsmOptions) -> bool {
736 match self {
737 InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
738 InlineAsmMacro::NakedAsm => true,
739 }
740 }
741}