1use std::slice;
4
5use rustc_ast::InlineAsmOptions;
6use rustc_data_structures::packed::Pu128;
7use rustc_hir::LangItem;
8use rustc_hir::attrs::AttributeKind;
9use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
10use smallvec::{SmallVec, smallvec};
11use thin_vec::ThinVec;
12
13use super::*;
14
15impl SwitchTargets {
16 pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
21 let (values, mut targets): (SmallVec<_>, SmallVec<_>) =
22 targets.map(|(v, t)| (Pu128(v), t)).unzip();
23 targets.push(otherwise);
24 Self { values, targets }
25 }
26
27 pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
30 Self { values: {
let count = 0usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(Pu128(value));
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[Pu128(value)])))
}
}smallvec![Pu128(value)], targets: {
let count = 0usize + 1usize + 1usize;
let mut vec = ::smallvec::SmallVec::new();
if count <= vec.inline_size() {
vec.push(then);
vec.push(else_);
vec
} else {
::smallvec::SmallVec::from_vec(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[then, else_])))
}
}smallvec![then, else_] }
31 }
32
33 #[inline]
35 pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> {
36 if let &[value] = &self.values[..]
37 && let &[then, else_] = &self.targets[..]
38 {
39 Some((value.get(), then, else_))
40 } else {
41 None
42 }
43 }
44
45 #[inline]
47 pub fn otherwise(&self) -> BasicBlock {
48 *self.targets.last().unwrap()
49 }
50
51 #[inline]
58 pub fn iter(&self) -> SwitchTargetsIter<'_> {
59 SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) }
60 }
61
62 #[inline]
64 pub fn all_targets(&self) -> &[BasicBlock] {
65 &self.targets
66 }
67
68 #[inline]
69 pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
70 &mut self.targets
71 }
72
73 #[inline]
75 pub fn all_values(&self) -> &[Pu128] {
76 &self.values
77 }
78
79 #[inline]
80 pub fn all_values_mut(&mut self) -> &mut [Pu128] {
81 &mut self.values
82 }
83
84 #[inline]
88 pub fn target_for_value(&self, value: u128) -> BasicBlock {
89 self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
90 }
91
92 #[inline]
94 pub fn add_target(&mut self, value: u128, bb: BasicBlock) {
95 let value = Pu128(value);
96 if self.values.contains(&value) {
97 crate::util::bug::bug_fmt(format_args!("target value {0:?} already present",
value));bug!("target value {:?} already present", value);
98 }
99 self.values.push(value);
100 self.targets.insert(self.targets.len() - 1, bb);
101 }
102
103 #[inline]
105 pub fn is_distinct(&self) -> bool {
106 self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len()
107 }
108}
109
110pub struct SwitchTargetsIter<'a> {
111 inner: iter::Zip<slice::Iter<'a, Pu128>, slice::Iter<'a, BasicBlock>>,
112}
113
114impl<'a> Iterator for SwitchTargetsIter<'a> {
115 type Item = (u128, BasicBlock);
116
117 #[inline]
118 fn next(&mut self) -> Option<Self::Item> {
119 self.inner.next().map(|(val, bb)| (val.get(), *bb))
120 }
121
122 #[inline]
123 fn size_hint(&self) -> (usize, Option<usize>) {
124 self.inner.size_hint()
125 }
126}
127
128impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
129
130impl UnwindAction {
131 fn cleanup_block(self) -> Option<BasicBlock> {
132 match self {
133 UnwindAction::Cleanup(bb) => Some(bb),
134 UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
135 }
136 }
137}
138
139impl UnwindTerminateReason {
140 pub fn as_str(self) -> &'static str {
141 match self {
143 UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
144 UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
145 }
146 }
147
148 pub fn as_short_str(self) -> &'static str {
150 match self {
151 UnwindTerminateReason::Abi => "abi",
152 UnwindTerminateReason::InCleanup => "cleanup",
153 }
154 }
155
156 pub fn lang_item(self) -> LangItem {
157 match self {
158 UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
159 UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
160 }
161 }
162}
163
164impl<O> AssertKind<O> {
165 pub fn is_optional_overflow_check(&self) -> bool {
167 use AssertKind::*;
168 use BinOp::*;
169 #[allow(non_exhaustive_omitted_patterns)] match self {
OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..) => true,
_ => false,
}matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
170 }
171
172 pub fn panic_function(&self) -> LangItem {
179 use AssertKind::*;
180 match self {
181 Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
182 Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
183 Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
184 Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
185 Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
186 OverflowNeg(_) => LangItem::PanicNegOverflow,
187 Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
188 Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
189 Overflow(op, _, _) => crate::util::bug::bug_fmt(format_args!("{0:?} cannot overflow", op))bug!("{:?} cannot overflow", op),
190 DivisionByZero(_) => LangItem::PanicDivZero,
191 RemainderByZero(_) => LangItem::PanicRemZero,
192 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
193 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
194 LangItem::PanicAsyncFnResumed
195 }
196 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
197 LangItem::PanicAsyncGenFnResumed
198 }
199 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
200 LangItem::PanicGenFnNone
201 }
202 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
203 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
204 LangItem::PanicAsyncFnResumedPanic
205 }
206 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
207 LangItem::PanicAsyncGenFnResumedPanic
208 }
209 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
210 LangItem::PanicGenFnNonePanic
211 }
212 NullPointerDereference => LangItem::PanicNullPointerDereference,
213 InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction,
214 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop,
215 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
216 LangItem::PanicAsyncFnResumedDrop
217 }
218 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
219 LangItem::PanicAsyncGenFnResumedDrop
220 }
221 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
222 LangItem::PanicGenFnNoneDrop
223 }
224
225 BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
226 crate::util::bug::bug_fmt(format_args!("Unexpected AssertKind"))bug!("Unexpected AssertKind")
227 }
228 }
229 }
230
231 pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
238 where
239 O: Debug,
240 {
241 use AssertKind::*;
242 match self {
243 BoundsCheck { len, index } => f.write_fmt(format_args!("\"index out of bounds: the length is {{}} but the index is {{}}\", {0:?}, {1:?}",
len, index))write!(
244 f,
245 "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
246 ),
247
248 OverflowNeg(op) => {
249 f.write_fmt(format_args!("\"attempt to negate `{{}}`, which would overflow\", {0:?}",
op))write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
250 }
251 DivisionByZero(op) => f.write_fmt(format_args!("\"attempt to divide `{{}}` by zero\", {0:?}", op))write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
252 RemainderByZero(op) => f.write_fmt(format_args!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {0:?}",
op))write!(
253 f,
254 "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
255 ),
256 Overflow(BinOp::Add, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
257 f,
258 "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
259 ),
260 Overflow(BinOp::Sub, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
261 f,
262 "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
263 ),
264 Overflow(BinOp::Mul, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
265 f,
266 "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
267 ),
268 Overflow(BinOp::Div, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
269 f,
270 "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
271 ),
272 Overflow(BinOp::Rem, l, r) => f.write_fmt(format_args!("\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
273 f,
274 "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
275 ),
276 Overflow(BinOp::Shr, _, r) => {
277 f.write_fmt(format_args!("\"attempt to shift right by `{{}}`, which would overflow\", {0:?}",
r))write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {r:?}")
278 }
279 Overflow(BinOp::Shl, _, r) => {
280 f.write_fmt(format_args!("\"attempt to shift left by `{{}}`, which would overflow\", {0:?}",
r))write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
281 }
282 Overflow(op, _, _) => crate::util::bug::bug_fmt(format_args!("{0:?} cannot overflow", op))bug!("{:?} cannot overflow", op),
283 MisalignedPointerDereference { required, found } => {
284 f.write_fmt(format_args!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {0:?}, {1:?}",
required, found))write!(
285 f,
286 "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
287 )
288 }
289 NullPointerDereference => f.write_fmt(format_args!("\"null pointer dereference occurred\""))write!(f, "\"null pointer dereference occurred\""),
290 InvalidEnumConstruction(source) => {
291 f.write_fmt(format_args!("\"trying to construct an enum from an invalid value {{}}\", {0:?}",
source))write!(f, "\"trying to construct an enum from an invalid value {{}}\", {source:?}")
292 }
293 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
294 f.write_fmt(format_args!("\"coroutine resumed after completion\""))write!(f, "\"coroutine resumed after completion\"")
295 }
296 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
297 f.write_fmt(format_args!("\"`async fn` resumed after completion\""))write!(f, "\"`async fn` resumed after completion\"")
298 }
299 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
300 f.write_fmt(format_args!("\"`async gen fn` resumed after completion\""))write!(f, "\"`async gen fn` resumed after completion\"")
301 }
302 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
303 f.write_fmt(format_args!("\"`gen fn` should just keep returning `None` after completion\""))write!(f, "\"`gen fn` should just keep returning `None` after completion\"")
304 }
305 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
306 f.write_fmt(format_args!("\"coroutine resumed after panicking\""))write!(f, "\"coroutine resumed after panicking\"")
307 }
308 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
309 f.write_fmt(format_args!("\"`async fn` resumed after panicking\""))write!(f, "\"`async fn` resumed after panicking\"")
310 }
311 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
312 f.write_fmt(format_args!("\"`async gen fn` resumed after panicking\""))write!(f, "\"`async gen fn` resumed after panicking\"")
313 }
314 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
315 f.write_fmt(format_args!("\"`gen fn` should just keep returning `None` after panicking\""))write!(f, "\"`gen fn` should just keep returning `None` after panicking\"")
316 }
317 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
318 f.write_fmt(format_args!("\"coroutine resumed after async drop\""))write!(f, "\"coroutine resumed after async drop\"")
319 }
320 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
321 f.write_fmt(format_args!("\"`async fn` resumed after async drop\""))write!(f, "\"`async fn` resumed after async drop\"")
322 }
323 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
324 f.write_fmt(format_args!("\"`async gen fn` resumed after async drop\""))write!(f, "\"`async gen fn` resumed after async drop\"")
325 }
326 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
327 f.write_fmt(format_args!("\"`gen fn` resumed after drop\""))write!(f, "\"`gen fn` resumed after drop\"")
328 }
329 }
330 }
331}
332
333impl<O: fmt::Debug> fmt::Display for AssertKind<O> {
340 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
341 use AssertKind::*;
342
343 match self {
344 BoundsCheck { len, index } => {
345 f.write_fmt(format_args!("index out of bounds: the length is {0:?} but the index is {1:?}",
len, index))write!(f, "index out of bounds: the length is {len:?} but the index is {index:?}")
346 }
347 Overflow(BinOp::Shl, _, val) => {
348 f.write_fmt(format_args!("attempt to shift left by `{0:#?}`, which would overflow",
val))write!(f, "attempt to shift left by `{val:#?}`, which would overflow")
349 }
350 Overflow(BinOp::Shr, _, val) => {
351 f.write_fmt(format_args!("attempt to shift right by `{0:#?}`, which would overflow",
val))write!(f, "attempt to shift right by `{val:#?}`, which would overflow")
352 }
353 Overflow(binop, left, right) => {
354 f.write_fmt(format_args!("attempt to compute `{1:#?} {0} {2:#?}`, which would overflow",
binop.to_hir_binop().as_str(), left, right))write!(
355 f,
356 "attempt to compute `{left:#?} {op} {right:#?}`, which would overflow",
357 op = binop.to_hir_binop().as_str()
358 )
359 }
360 OverflowNeg(val) => f.write_fmt(format_args!("attempt to negate `{0:#?}`, which would overflow",
val))write!(f, "attempt to negate `{val:#?}`, which would overflow"),
361 DivisionByZero(val) => f.write_fmt(format_args!("attempt to divide `{0:#?}` by zero", val))write!(f, "attempt to divide `{val:#?}` by zero"),
362 RemainderByZero(val) => {
363 f.write_fmt(format_args!("attempt to calculate the remainder of `{0:#?}` with a divisor of zero",
val))write!(f, "attempt to calculate the remainder of `{val:#?}` with a divisor of zero")
364 }
365 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
366 f.write_fmt(format_args!("`async fn` resumed after completion"))write!(f, "`async fn` resumed after completion")
367 }
368 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
369 ::core::panicking::panic("not yet implemented")todo!()
370 }
371 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
372 crate::util::bug::bug_fmt(format_args!("gen blocks can be resumed after they return and will keep returning `None`"))bug!("gen blocks can be resumed after they return and will keep returning `None`")
373 }
374 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
375 f.write_fmt(format_args!("coroutine resumed after completion"))write!(f, "coroutine resumed after completion")
376 }
377 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
378 f.write_fmt(format_args!("`async fn` resumed after panicking"))write!(f, "`async fn` resumed after panicking")
379 }
380 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
381 ::core::panicking::panic("not yet implemented")todo!()
382 }
383 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
384 f.write_fmt(format_args!("`gen` fn or block cannot be further iterated on after it panicked"))write!(f, "`gen` fn or block cannot be further iterated on after it panicked")
385 }
386 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
387 f.write_fmt(format_args!("coroutine resumed after panicking"))write!(f, "coroutine resumed after panicking")
388 }
389 NullPointerDereference => f.write_fmt(format_args!("null pointer dereference occurred"))write!(f, "null pointer dereference occurred"),
390 InvalidEnumConstruction(source) => {
391 f.write_fmt(format_args!("trying to construct an enum from an invalid value `{0:#?}`",
source))write!(f, "trying to construct an enum from an invalid value `{source:#?}`")
392 }
393 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
394 f.write_fmt(format_args!("`async fn` resumed after async drop"))write!(f, "`async fn` resumed after async drop")
395 }
396 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
397 ::core::panicking::panic("not yet implemented")todo!()
398 }
399 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
400 f.write_fmt(format_args!("`gen` fn or block cannot be further iterated on after it async dropped"))write!(f, "`gen` fn or block cannot be further iterated on after it async dropped")
401 }
402 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
403 f.write_fmt(format_args!("coroutine resumed after async drop"))write!(f, "coroutine resumed after async drop")
404 }
405
406 MisalignedPointerDereference { required, found } => f.write_fmt(format_args!("misaligned pointer dereference: address must be a multiple of {0:#?} but is {1:#?}",
required, found))write!(
407 f,
408 "misaligned pointer dereference: address must be a multiple of {required:#?} but is {found:#?}"
409 ),
410 }
411 }
412}
413
414#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for Terminator<'tcx> {
#[inline]
fn clone(&self) -> Terminator<'tcx> {
Terminator {
source_info: ::core::clone::Clone::clone(&self.source_info),
kind: ::core::clone::Clone::clone(&self.kind),
attributes: ::core::clone::Clone::clone(&self.attributes),
}
}
}Clone, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for Terminator<'tcx> {
fn encode(&self, __encoder: &mut __E) {
match *self {
Terminator {
source_info: ref __binding_0,
kind: ref __binding_1,
attributes: ref __binding_2 } => {
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_2,
__encoder);
}
}
}
}
};TyEncodable, const _: () =
{
impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
::rustc_serialize::Decodable<__D> for Terminator<'tcx> {
fn decode(__decoder: &mut __D) -> Self {
Terminator {
source_info: ::rustc_serialize::Decodable::decode(__decoder),
kind: ::rustc_serialize::Decodable::decode(__decoder),
attributes: ::rustc_serialize::Decodable::decode(__decoder),
}
}
}
};TyDecodable, const _: () =
{
impl<'tcx> ::rustc_data_structures::stable_hash::StableHash for
Terminator<'tcx> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
Terminator {
source_info: ref __binding_0,
kind: ref __binding_1,
attributes: ref __binding_2 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
for Terminator<'tcx> {
fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Result<Self, __F::Error> {
Ok(match self {
Terminator {
source_info: __binding_0,
kind: __binding_1,
attributes: __binding_2 } => {
Terminator {
source_info: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
__folder)?,
kind: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
__folder)?,
attributes: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_2,
__folder)?,
}
}
})
}
fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Self {
match self {
Terminator {
source_info: __binding_0,
kind: __binding_1,
attributes: __binding_2 } => {
Terminator {
source_info: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
__folder),
kind: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
__folder),
attributes: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_2,
__folder),
}
}
}
}
}
};TypeFoldable, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
for Terminator<'tcx> {
fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
__visitor: &mut __V) -> __V::Result {
match *self {
Terminator {
source_info: ref __binding_0,
kind: ref __binding_1,
attributes: ref __binding_2 } => {
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_2,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
}
}
<__V::Result as ::rustc_middle::ty::VisitorResult>::output()
}
}
};TypeVisitable)]
415pub struct Terminator<'tcx> {
416 pub source_info: SourceInfo,
417 pub kind: TerminatorKind<'tcx>,
418 pub attributes: ThinVec<AttributeKind>,
419}
420
421impl<'tcx> Terminator<'tcx> {
422 #[inline]
423 pub fn successors(&self) -> Successors<'_> {
424 self.kind.successors()
425 }
426
427 #[inline]
429 pub fn identical_successor(&self) -> Option<BasicBlock> {
430 let mut successors = self.successors();
431 let first_succ = successors.next()?;
432 if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None }
433 }
434
435 #[inline]
436 pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) {
437 self.kind.successors_mut(f)
438 }
439
440 #[inline]
441 pub fn unwind(&self) -> Option<&UnwindAction> {
442 self.kind.unwind()
443 }
444
445 #[inline]
446 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
447 self.kind.unwind_mut()
448 }
449}
450
451impl<'tcx> TerminatorKind<'tcx> {
452 pub const fn name(&self) -> &'static str {
455 match self {
456 TerminatorKind::Goto { .. } => "Goto",
457 TerminatorKind::SwitchInt { .. } => "SwitchInt",
458 TerminatorKind::UnwindResume => "UnwindResume",
459 TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
460 TerminatorKind::Return => "Return",
461 TerminatorKind::Unreachable => "Unreachable",
462 TerminatorKind::Drop { .. } => "Drop",
463 TerminatorKind::Call { .. } => "Call",
464 TerminatorKind::TailCall { .. } => "TailCall",
465 TerminatorKind::Assert { .. } => "Assert",
466 TerminatorKind::Yield { .. } => "Yield",
467 TerminatorKind::CoroutineDrop => "CoroutineDrop",
468 TerminatorKind::FalseEdge { .. } => "FalseEdge",
469 TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
470 TerminatorKind::InlineAsm { .. } => "InlineAsm",
471 }
472 }
473
474 #[inline]
475 pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
476 TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
477 }
478}
479
480pub use helper::*;
481
482mod helper {
483 use super::*;
484 pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
485
486 #[inline]
488 #[define_opaque(Successors)]
489 fn mk_successors(
490 slice: &[BasicBlock],
491 option1: Option<BasicBlock>,
492 option2: Option<BasicBlock>,
493 ) -> Successors<'_> {
494 slice.iter().copied().chain(option1.into_iter().chain(option2))
495 }
496
497 impl SwitchTargets {
498 #[inline]
501 pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
502 let target = self.target_for_value(value);
503 mk_successors(&[], Some(target), None)
504 }
505 }
506
507 impl<'tcx> TerminatorKind<'tcx> {
508 #[inline]
509 pub fn successors(&self) -> Successors<'_> {
510 use self::TerminatorKind::*;
511 match *self {
512 Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => {
514 mk_successors(slice::from_ref(t), Some(u), Some(d))
515 }
516 Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
518 | Yield { resume: ref t, drop: Some(u), .. }
519 | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: None, .. }
520 | Drop { target: ref t, unwind: _, drop: Some(u), .. }
521 | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
522 | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
523 mk_successors(slice::from_ref(t), Some(u), None)
524 }
525 Goto { target: ref t }
527 | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
528 | Call { target: Some(ref t), unwind: _, .. }
529 | Yield { resume: ref t, drop: None, .. }
530 | Drop { target: ref t, unwind: _, .. }
531 | Assert { target: ref t, unwind: _, .. }
532 | FalseUnwind { real_target: ref t, unwind: _ } => {
533 mk_successors(slice::from_ref(t), None, None)
534 }
535 UnwindResume
537 | UnwindTerminate(_)
538 | CoroutineDrop
539 | Return
540 | Unreachable
541 | TailCall { .. }
542 | Call { target: None, unwind: _, .. } => mk_successors(&[], None, None),
543 InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
545 mk_successors(targets, Some(u), None)
546 }
547 InlineAsm { ref targets, unwind: _, .. } => mk_successors(targets, None, None),
548 SwitchInt { ref targets, .. } => mk_successors(&targets.targets, None, None),
549 FalseEdge { ref real_target, imaginary_target } => {
551 mk_successors(slice::from_ref(real_target), Some(imaginary_target), None)
552 }
553 }
554 }
555
556 #[inline]
557 pub fn successors_mut<'a>(&'a mut self, mut f: impl FnMut(&'a mut BasicBlock)) {
558 use self::TerminatorKind::*;
559 match self {
560 Drop { target, unwind, drop, .. } => {
561 f(target);
562 if let UnwindAction::Cleanup(u) = unwind {
563 f(u)
564 }
565 if let Some(d) = drop {
566 f(d)
567 }
568 }
569 Call { target, unwind, .. } => {
570 if let Some(target) = target {
571 f(target);
572 }
573 if let UnwindAction::Cleanup(u) = unwind {
574 f(u)
575 }
576 }
577 Yield { resume, drop, .. } => {
578 f(resume);
579 if let Some(d) = drop {
580 f(d)
581 }
582 }
583 Assert { target, unwind, .. } | FalseUnwind { real_target: target, unwind } => {
584 f(target);
585 if let UnwindAction::Cleanup(u) = unwind {
586 f(u)
587 }
588 }
589 Goto { target } => {
590 f(target);
591 }
592 UnwindResume
593 | UnwindTerminate(_)
594 | CoroutineDrop
595 | Return
596 | Unreachable
597 | TailCall { .. } => {}
598 InlineAsm { targets, unwind, .. } => {
599 for target in targets {
600 f(target);
601 }
602 if let UnwindAction::Cleanup(u) = unwind {
603 f(u)
604 }
605 }
606 SwitchInt { targets, .. } => {
607 for target in &mut targets.targets {
608 f(target);
609 }
610 }
611 FalseEdge { real_target, imaginary_target } => {
612 f(real_target);
613 f(imaginary_target);
614 }
615 }
616 }
617 }
618}
619
620impl<'tcx> TerminatorKind<'tcx> {
621 #[inline]
622 pub fn unwind(&self) -> Option<&UnwindAction> {
623 match *self {
624 TerminatorKind::Goto { .. }
625 | TerminatorKind::UnwindResume
626 | TerminatorKind::UnwindTerminate(_)
627 | TerminatorKind::Return
628 | TerminatorKind::TailCall { .. }
629 | TerminatorKind::Unreachable
630 | TerminatorKind::CoroutineDrop
631 | TerminatorKind::Yield { .. }
632 | TerminatorKind::SwitchInt { .. }
633 | TerminatorKind::FalseEdge { .. } => None,
634 TerminatorKind::Call { ref unwind, .. }
635 | TerminatorKind::Assert { ref unwind, .. }
636 | TerminatorKind::Drop { ref unwind, .. }
637 | TerminatorKind::FalseUnwind { ref unwind, .. }
638 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
639 }
640 }
641
642 #[inline]
643 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
644 match *self {
645 TerminatorKind::Goto { .. }
646 | TerminatorKind::UnwindResume
647 | TerminatorKind::UnwindTerminate(_)
648 | TerminatorKind::Return
649 | TerminatorKind::TailCall { .. }
650 | TerminatorKind::Unreachable
651 | TerminatorKind::CoroutineDrop
652 | TerminatorKind::Yield { .. }
653 | TerminatorKind::SwitchInt { .. }
654 | TerminatorKind::FalseEdge { .. } => None,
655 TerminatorKind::Call { ref mut unwind, .. }
656 | TerminatorKind::Assert { ref mut unwind, .. }
657 | TerminatorKind::Drop { ref mut unwind, .. }
658 | TerminatorKind::FalseUnwind { ref mut unwind, .. }
659 | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
660 }
661 }
662
663 #[inline]
664 pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> {
665 match self {
666 TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)),
667 _ => None,
668 }
669 }
670
671 #[inline]
672 pub fn as_goto(&self) -> Option<BasicBlock> {
673 match self {
674 TerminatorKind::Goto { target } => Some(*target),
675 _ => None,
676 }
677 }
678}
679
680#[derive(#[automatically_derived]
impl<'mir, 'tcx> ::core::fmt::Debug for TerminatorEdges<'mir, 'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
TerminatorEdges::None =>
::core::fmt::Formatter::write_str(f, "None"),
TerminatorEdges::Single(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Single",
&__self_0),
TerminatorEdges::Double(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Double",
__self_0, &__self_1),
TerminatorEdges::AssignOnReturn {
return_: __self_0, cleanup: __self_1, place: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"AssignOnReturn", "return_", __self_0, "cleanup", __self_1,
"place", &__self_2),
TerminatorEdges::SwitchInt { targets: __self_0, discr: __self_1 }
=>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SwitchInt", "targets", __self_0, "discr", &__self_1),
}
}
}Debug)]
681pub enum TerminatorEdges<'mir, 'tcx> {
682 None,
684 Single(BasicBlock),
687 Double(BasicBlock, BasicBlock),
690 AssignOnReturn {
692 return_: Box<[BasicBlock]>,
693 cleanup: Option<BasicBlock>,
695 place: CallReturnPlaces<'mir, 'tcx>,
696 },
697 SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> },
699}
700
701#[derive(#[automatically_derived]
impl<'a, 'tcx> ::core::marker::Copy for CallReturnPlaces<'a, 'tcx> { }Copy, #[automatically_derived]
impl<'a, 'tcx> ::core::clone::Clone for CallReturnPlaces<'a, 'tcx> {
#[inline]
fn clone(&self) -> CallReturnPlaces<'a, 'tcx> {
let _: ::core::clone::AssertParamIsClone<Place<'tcx>>;
let _: ::core::clone::AssertParamIsClone<Place<'tcx>>;
let _:
::core::clone::AssertParamIsClone<&'a [InlineAsmOperand<'tcx>]>;
*self
}
}Clone, #[automatically_derived]
impl<'a, 'tcx> ::core::fmt::Debug for CallReturnPlaces<'a, 'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
CallReturnPlaces::Call(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Call",
&__self_0),
CallReturnPlaces::Yield(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Yield",
&__self_0),
CallReturnPlaces::InlineAsm(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InlineAsm", &__self_0),
}
}
}Debug)]
704pub enum CallReturnPlaces<'a, 'tcx> {
705 Call(Place<'tcx>),
706 Yield(Place<'tcx>),
707 InlineAsm(&'a [InlineAsmOperand<'tcx>]),
708}
709
710impl<'tcx> CallReturnPlaces<'_, 'tcx> {
711 pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) {
712 match *self {
713 Self::Call(place) | Self::Yield(place) => f(place),
714 Self::InlineAsm(operands) => {
715 for op in operands {
716 match *op {
717 InlineAsmOperand::Out { place: Some(place), .. }
718 | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
719 _ => {}
720 }
721 }
722 }
723 }
724 }
725}
726
727impl<'tcx> Terminator<'tcx> {
728 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
729 self.kind.edges()
730 }
731}
732
733impl<'tcx> TerminatorKind<'tcx> {
734 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
735 use TerminatorKind::*;
736 match *self {
737 Return
738 | TailCall { .. }
739 | UnwindResume
740 | UnwindTerminate(_)
741 | CoroutineDrop
742 | Unreachable => TerminatorEdges::None,
743
744 Goto { target } => TerminatorEdges::Single(target),
745
746 Assert { target, unwind, expected: _, msg: _, cond: _ }
749 | Drop { target, unwind, place: _, replace: _, drop: _ }
750 | FalseUnwind { real_target: target, unwind } => match unwind {
751 UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
752 UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
753 TerminatorEdges::Single(target)
754 }
755 },
756
757 FalseEdge { real_target, imaginary_target } => {
758 TerminatorEdges::Double(real_target, imaginary_target)
759 }
760
761 Yield { resume: target, drop, resume_arg, value: _ } => {
762 TerminatorEdges::AssignOnReturn {
763 return_: [target].into_iter().chain(drop.into_iter()).collect(),
764 cleanup: None,
765 place: CallReturnPlaces::Yield(resume_arg),
766 }
767 }
768
769 Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
770 TerminatorEdges::AssignOnReturn {
771 return_: target.into_iter().collect(),
772 cleanup: unwind.cleanup_block(),
773 place: CallReturnPlaces::Call(destination),
774 }
775 }
776
777 InlineAsm {
778 asm_macro: _,
779 template: _,
780 ref operands,
781 options: _,
782 line_spans: _,
783 ref targets,
784 unwind,
785 } => TerminatorEdges::AssignOnReturn {
786 return_: targets.to_owned(),
787 cleanup: unwind.cleanup_block(),
788 place: CallReturnPlaces::InlineAsm(operands),
789 },
790
791 SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr },
792 }
793 }
794}
795
796impl CallSource {
797 pub fn from_hir_call(self) -> bool {
798 #[allow(non_exhaustive_omitted_patterns)] match self {
CallSource::Normal => true,
_ => false,
}matches!(self, CallSource::Normal)
799 }
800}
801
802impl InlineAsmMacro {
803 pub const fn diverges(self, options: InlineAsmOptions) -> bool {
804 match self {
805 InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
806 InlineAsmMacro::NakedAsm => true,
807 }
808 }
809}