1use std::slice;
4
5use rustc_ast::InlineAsmOptions;
6use rustc_attr_ir::lang_items::LangItem;
7use rustc_data_structures::packed::Pu128;
8use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
9use rustc_span::bug;
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 ::rustc_span::macros::bug_impl(None,
format_args!("target value {0:?} already present", value),
Location::caller());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 match self.targets.as_slice() {
107 &[a, b] => a != b,
110 &[a, b, c] => a != b && a != c && b != c,
111 targets => targets.iter().collect::<FxHashSet<_>>().len() == targets.len(),
112 }
113 }
114}
115
116pub struct SwitchTargetsIter<'a> {
117 inner: iter::Zip<slice::Iter<'a, Pu128>, slice::Iter<'a, BasicBlock>>,
118}
119
120impl<'a> Iterator for SwitchTargetsIter<'a> {
121 type Item = (u128, BasicBlock);
122
123 #[inline]
124 fn next(&mut self) -> Option<Self::Item> {
125 self.inner.next().map(|(val, bb)| (val.get(), *bb))
126 }
127
128 #[inline]
129 fn size_hint(&self) -> (usize, Option<usize>) {
130 self.inner.size_hint()
131 }
132}
133
134impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
135
136impl UnwindAction {
137 fn cleanup_block(self) -> Option<BasicBlock> {
138 match self {
139 UnwindAction::Cleanup(bb) => Some(bb),
140 UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
141 }
142 }
143}
144
145impl UnwindTerminateReason {
146 pub fn as_str(self) -> &'static str {
147 match self {
149 UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
150 UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
151 }
152 }
153
154 pub fn as_short_str(self) -> &'static str {
156 match self {
157 UnwindTerminateReason::Abi => "abi",
158 UnwindTerminateReason::InCleanup => "cleanup",
159 }
160 }
161
162 pub fn lang_item(self) -> LangItem {
163 match self {
164 UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
165 UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
166 }
167 }
168}
169
170impl<O> AssertKind<O> {
171 pub fn is_optional_overflow_check(&self) -> bool {
173 use AssertKind::*;
174 use BinOp::*;
175 #[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, ..))
176 }
177
178 pub fn panic_function(&self) -> LangItem {
185 use AssertKind::*;
186 match self {
187 Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
188 Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
189 Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
190 Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
191 Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
192 OverflowNeg(_) => LangItem::PanicNegOverflow,
193 Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
194 Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
195 Overflow(op, _, _) => ::rustc_span::macros::bug_impl(None,
format_args!("{0:?} cannot overflow", op), Location::caller())bug!("{:?} cannot overflow", op),
196 DivisionByZero(_) => LangItem::PanicDivZero,
197 RemainderByZero(_) => LangItem::PanicRemZero,
198 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
199 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
200 LangItem::PanicAsyncFnResumed
201 }
202 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
203 LangItem::PanicAsyncGenFnResumed
204 }
205 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
206 LangItem::PanicGenFnNone
207 }
208 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
209 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
210 LangItem::PanicAsyncFnResumedPanic
211 }
212 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
213 LangItem::PanicAsyncGenFnResumedPanic
214 }
215 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
216 LangItem::PanicGenFnNonePanic
217 }
218 NullPointerDereference => LangItem::PanicNullPointerDereference,
219 NullReferenceConstructed => LangItem::PanicNullReferenceConstructed,
220 InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction,
221 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop,
222 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
223 LangItem::PanicAsyncFnResumedDrop
224 }
225 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
226 LangItem::PanicAsyncGenFnResumedDrop
227 }
228 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
229 LangItem::PanicGenFnNoneDrop
230 }
231
232 BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
233 ::rustc_span::macros::bug_impl(None, format_args!("Unexpected AssertKind"),
Location::caller())bug!("Unexpected AssertKind")
234 }
235 }
236 }
237
238 pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
245 where
246 O: Debug,
247 {
248 use AssertKind::*;
249 match self {
250 BoundsCheck { len, index } => f.write_fmt(format_args!("\"index out of bounds: the length is {{}} but the index is {{}}\", {0:?}, {1:?}",
len, index))write!(
251 f,
252 "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
253 ),
254
255 OverflowNeg(op) => {
256 f.write_fmt(format_args!("\"attempt to negate `{{}}`, which would overflow\", {0:?}",
op))write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
257 }
258 DivisionByZero(op) => f.write_fmt(format_args!("\"attempt to divide `{{}}` by zero\", {0:?}", op))write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
259 RemainderByZero(op) => f.write_fmt(format_args!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {0:?}",
op))write!(
260 f,
261 "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
262 ),
263 Overflow(BinOp::Add, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
264 f,
265 "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
266 ),
267 Overflow(BinOp::Sub, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
268 f,
269 "\"attempt to compute `{{}} - {{}}`, which would overflow\", {l:?}, {r:?}"
270 ),
271 Overflow(BinOp::Mul, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
272 f,
273 "\"attempt to compute `{{}} * {{}}`, which would overflow\", {l:?}, {r:?}"
274 ),
275 Overflow(BinOp::Div, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
276 f,
277 "\"attempt to compute `{{}} / {{}}`, which would overflow\", {l:?}, {r:?}"
278 ),
279 Overflow(BinOp::Rem, l, r) => f.write_fmt(format_args!("\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
280 f,
281 "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
282 ),
283 Overflow(BinOp::Shr, _, r) => {
284 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:?}")
285 }
286 Overflow(BinOp::Shl, _, r) => {
287 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:?}")
288 }
289 Overflow(op, _, _) => ::rustc_span::macros::bug_impl(None,
format_args!("{0:?} cannot overflow", op), Location::caller())bug!("{:?} cannot overflow", op),
290 MisalignedPointerDereference { required, found } => {
291 f.write_fmt(format_args!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {0:?}, {1:?}",
required, found))write!(
292 f,
293 "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
294 )
295 }
296 NullPointerDereference => f.write_fmt(format_args!("\"null pointer dereference occurred\""))write!(f, "\"null pointer dereference occurred\""),
297 NullReferenceConstructed => f.write_fmt(format_args!("\"null reference produced\""))write!(f, "\"null reference produced\""),
298 InvalidEnumConstruction(source) => {
299 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:?}")
300 }
301 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
302 f.write_fmt(format_args!("\"coroutine resumed after completion\""))write!(f, "\"coroutine resumed after completion\"")
303 }
304 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
305 f.write_fmt(format_args!("\"`async fn` resumed after completion\""))write!(f, "\"`async fn` resumed after completion\"")
306 }
307 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
308 f.write_fmt(format_args!("\"`async gen fn` resumed after completion\""))write!(f, "\"`async gen fn` resumed after completion\"")
309 }
310 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
311 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\"")
312 }
313 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
314 f.write_fmt(format_args!("\"coroutine resumed after panicking\""))write!(f, "\"coroutine resumed after panicking\"")
315 }
316 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
317 f.write_fmt(format_args!("\"`async fn` resumed after panicking\""))write!(f, "\"`async fn` resumed after panicking\"")
318 }
319 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
320 f.write_fmt(format_args!("\"`async gen fn` resumed after panicking\""))write!(f, "\"`async gen fn` resumed after panicking\"")
321 }
322 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
323 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\"")
324 }
325 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
326 f.write_fmt(format_args!("\"coroutine resumed after async drop\""))write!(f, "\"coroutine resumed after async drop\"")
327 }
328 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
329 f.write_fmt(format_args!("\"`async fn` resumed after async drop\""))write!(f, "\"`async fn` resumed after async drop\"")
330 }
331 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
332 f.write_fmt(format_args!("\"`async gen fn` resumed after async drop\""))write!(f, "\"`async gen fn` resumed after async drop\"")
333 }
334 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
335 f.write_fmt(format_args!("\"`gen fn` resumed after drop\""))write!(f, "\"`gen fn` resumed after drop\"")
336 }
337 }
338 }
339}
340
341impl<O: fmt::Debug> fmt::Display for AssertKind<O> {
348 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
349 use AssertKind::*;
350
351 match self {
352 BoundsCheck { len, index } => {
353 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:?}")
354 }
355 Overflow(BinOp::Shl, _, val) => {
356 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")
357 }
358 Overflow(BinOp::Shr, _, val) => {
359 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")
360 }
361 Overflow(binop, left, right) => {
362 f.write_fmt(format_args!("attempt to compute `{1:#?} {0} {2:#?}`, which would overflow",
binop.to_hir_binop().as_str(), left, right))write!(
363 f,
364 "attempt to compute `{left:#?} {op} {right:#?}`, which would overflow",
365 op = binop.to_hir_binop().as_str()
366 )
367 }
368 OverflowNeg(val) => f.write_fmt(format_args!("attempt to negate `{0:#?}`, which would overflow",
val))write!(f, "attempt to negate `{val:#?}`, which would overflow"),
369 DivisionByZero(val) => f.write_fmt(format_args!("attempt to divide `{0:#?}` by zero", val))write!(f, "attempt to divide `{val:#?}` by zero"),
370 RemainderByZero(val) => {
371 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")
372 }
373 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
374 f.write_fmt(format_args!("`async fn` resumed after completion"))write!(f, "`async fn` resumed after completion")
375 }
376 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
377 ::core::panicking::unimplemented_default_msg()unimplemented!()
378 }
379 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
380 ::rustc_span::macros::bug_impl(None,
format_args!("gen blocks can be resumed after they return and will keep returning `None`"),
Location::caller())bug!("gen blocks can be resumed after they return and will keep returning `None`")
381 }
382 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
383 f.write_fmt(format_args!("coroutine resumed after completion"))write!(f, "coroutine resumed after completion")
384 }
385 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
386 f.write_fmt(format_args!("`async fn` resumed after panicking"))write!(f, "`async fn` resumed after panicking")
387 }
388 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
389 ::core::panicking::unimplemented_default_msg()unimplemented!()
390 }
391 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
392 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")
393 }
394 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
395 f.write_fmt(format_args!("coroutine resumed after panicking"))write!(f, "coroutine resumed after panicking")
396 }
397 NullPointerDereference => f.write_fmt(format_args!("null pointer dereference occurred"))write!(f, "null pointer dereference occurred"),
398 NullReferenceConstructed => f.write_fmt(format_args!("null reference produced"))write!(f, "null reference produced"),
399 InvalidEnumConstruction(source) => {
400 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:#?}`")
401 }
402 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
403 f.write_fmt(format_args!("`async fn` resumed after async drop"))write!(f, "`async fn` resumed after async drop")
404 }
405 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
406 ::core::panicking::unimplemented_default_msg()unimplemented!()
407 }
408 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
409 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")
410 }
411 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
412 f.write_fmt(format_args!("coroutine resumed after async drop"))write!(f, "coroutine resumed after async drop")
413 }
414
415 MisalignedPointerDereference { required, found } => f.write_fmt(format_args!("misaligned pointer dereference: address must be a multiple of {0:#?} but is {1:#?}",
required, found))write!(
416 f,
417 "misaligned pointer dereference: address must be a multiple of {required:#?} but is {found:#?}"
418 ),
419 }
420 }
421}
422
423#[derive(#[automatically_derived]impl<'tcx> ::core::clone::Clone for Terminator<'tcx> {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
Terminator {
source_info: ::core::clone::Clone::clone(&self.source_info),
kind: ::core::clone::Clone::clone(&self.kind),
}
}
}Clone, const _: () =
{
impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
::rustc_serialize::Encodable<__E> for Terminator<'tcx> {
fn encode(&self, __encoder: &mut __E) {
let Terminator {
source_info: ref __binding_0, kind: ref __binding_1 } =
*self;
::rustc_serialize::Encodable::<__E>::encode(__binding_0,
__encoder);
::rustc_serialize::Encodable::<__E>::encode(__binding_1,
__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),
}
}
}
};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 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.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 }
=> {
Terminator {
source_info: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
__folder)?,
kind: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
__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 }
=> {
Terminator {
source_info: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
__folder),
kind: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
__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 } => {
{
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);
}
}
}
}
}
<__V::Result as ::rustc_middle::ty::VisitorResult>::output()
}
}
};TypeVisitable)]
424pub struct Terminator<'tcx> {
425 pub source_info: SourceInfo,
426 pub kind: TerminatorKind<'tcx>,
427}
428
429impl<'tcx> Terminator<'tcx> {
430 #[inline]
431 pub fn successors(&self) -> Successors<'_> {
432 self.kind.successors()
433 }
434
435 #[inline]
437 pub fn identical_successor(&self) -> Option<BasicBlock> {
438 let mut successors = self.successors();
439 let first_succ = successors.next()?;
440 if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None }
441 }
442
443 #[inline]
444 pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) {
445 self.kind.successors_mut(f)
446 }
447
448 #[inline]
449 pub fn unwind(&self) -> Option<&UnwindAction> {
450 self.kind.unwind()
451 }
452
453 #[inline]
454 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
455 self.kind.unwind_mut()
456 }
457}
458
459impl<'tcx> TerminatorKind<'tcx> {
460 pub const fn name(&self) -> &'static str {
463 match self {
464 TerminatorKind::Goto { .. } => "Goto",
465 TerminatorKind::SwitchInt { .. } => "SwitchInt",
466 TerminatorKind::UnwindResume => "UnwindResume",
467 TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
468 TerminatorKind::Return => "Return",
469 TerminatorKind::Unreachable => "Unreachable",
470 TerminatorKind::Drop { .. } => "Drop",
471 TerminatorKind::Call { .. } => "Call",
472 TerminatorKind::TailCall { .. } => "TailCall",
473 TerminatorKind::Assert { .. } => "Assert",
474 TerminatorKind::Yield { .. } => "Yield",
475 TerminatorKind::CoroutineDrop => "CoroutineDrop",
476 TerminatorKind::FalseEdge { .. } => "FalseEdge",
477 TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
478 TerminatorKind::InlineAsm { .. } => "InlineAsm",
479 }
480 }
481
482 #[inline]
483 pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
484 TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
485 }
486
487 #[inline]
488 pub fn goto(target: BasicBlock) -> TerminatorKind<'tcx> {
489 TerminatorKind::Goto { target, loop_hint_attrs: ThinVec::new() }
490 }
491}
492
493pub use helper::*;
494
495mod helper {
496 use super::*;
497 pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
498
499 #[inline]
501 #[define_opaque(Successors)]
502 fn mk_successors(
503 slice: &[BasicBlock],
504 option1: Option<BasicBlock>,
505 option2: Option<BasicBlock>,
506 ) -> Successors<'_> {
507 slice.iter().copied().chain(option1.into_iter().chain(option2))
508 }
509
510 impl SwitchTargets {
511 #[inline]
514 pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
515 let target = self.target_for_value(value);
516 mk_successors(&[], Some(target), None)
517 }
518 }
519
520 impl<'tcx> TerminatorKind<'tcx> {
521 #[inline]
522 pub fn successors(&self) -> Successors<'_> {
523 use self::TerminatorKind::*;
524 match *self {
525 Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => {
527 mk_successors(slice::from_ref(t), Some(u), Some(d))
528 }
529 Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
531 | Yield { resume: ref t, drop: Some(u), .. }
532 | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: None, .. }
533 | Drop { target: ref t, unwind: _, drop: Some(u), .. }
534 | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
535 | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
536 mk_successors(slice::from_ref(t), Some(u), None)
537 }
538 Goto { target: ref t, .. }
540 | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
541 | Call { target: Some(ref t), unwind: _, .. }
542 | Yield { resume: ref t, drop: None, .. }
543 | Drop { target: ref t, unwind: _, .. }
544 | Assert { target: ref t, unwind: _, .. }
545 | FalseUnwind { real_target: ref t, unwind: _ } => {
546 mk_successors(slice::from_ref(t), None, None)
547 }
548 UnwindResume
550 | UnwindTerminate(_)
551 | CoroutineDrop
552 | Return
553 | Unreachable
554 | TailCall { .. }
555 | Call { target: None, unwind: _, .. } => mk_successors(&[], None, None),
556 InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
558 mk_successors(targets, Some(u), None)
559 }
560 InlineAsm { ref targets, unwind: _, .. } => mk_successors(targets, None, None),
561 SwitchInt { ref targets, .. } => mk_successors(&targets.targets, None, None),
562 FalseEdge { ref real_target, imaginary_target } => {
564 mk_successors(slice::from_ref(real_target), Some(imaginary_target), None)
565 }
566 }
567 }
568
569 #[inline]
570 pub fn successors_mut<'a>(&'a mut self, mut f: impl FnMut(&'a mut BasicBlock)) {
571 use self::TerminatorKind::*;
572 match self {
573 Drop { target, unwind, drop, .. } => {
574 f(target);
575 if let UnwindAction::Cleanup(u) = unwind {
576 f(u)
577 }
578 if let Some(d) = drop {
579 f(d)
580 }
581 }
582 Call { target, unwind, .. } => {
583 if let Some(target) = target {
584 f(target);
585 }
586 if let UnwindAction::Cleanup(u) = unwind {
587 f(u)
588 }
589 }
590 Yield { resume, drop, .. } => {
591 f(resume);
592 if let Some(d) = drop {
593 f(d)
594 }
595 }
596 Assert { target, unwind, .. } | FalseUnwind { real_target: target, unwind } => {
597 f(target);
598 if let UnwindAction::Cleanup(u) = unwind {
599 f(u)
600 }
601 }
602 Goto { target, .. } => {
603 f(target);
604 }
605 UnwindResume
606 | UnwindTerminate(_)
607 | CoroutineDrop
608 | Return
609 | Unreachable
610 | TailCall { .. } => {}
611 InlineAsm { targets, unwind, .. } => {
612 for target in targets {
613 f(target);
614 }
615 if let UnwindAction::Cleanup(u) = unwind {
616 f(u)
617 }
618 }
619 SwitchInt { targets, .. } => {
620 for target in &mut targets.targets {
621 f(target);
622 }
623 }
624 FalseEdge { real_target, imaginary_target } => {
625 f(real_target);
626 f(imaginary_target);
627 }
628 }
629 }
630 }
631}
632
633impl<'tcx> TerminatorKind<'tcx> {
634 #[inline]
635 pub fn unwind(&self) -> Option<&UnwindAction> {
636 match *self {
637 TerminatorKind::Goto { .. }
638 | TerminatorKind::UnwindResume
639 | TerminatorKind::UnwindTerminate(_)
640 | TerminatorKind::Return
641 | TerminatorKind::TailCall { .. }
642 | TerminatorKind::Unreachable
643 | TerminatorKind::CoroutineDrop
644 | TerminatorKind::Yield { .. }
645 | TerminatorKind::SwitchInt { .. }
646 | TerminatorKind::FalseEdge { .. } => None,
647 TerminatorKind::Call { ref unwind, .. }
648 | TerminatorKind::Assert { ref unwind, .. }
649 | TerminatorKind::Drop { ref unwind, .. }
650 | TerminatorKind::FalseUnwind { ref unwind, .. }
651 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
652 }
653 }
654
655 #[inline]
656 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
657 match *self {
658 TerminatorKind::Goto { .. }
659 | TerminatorKind::UnwindResume
660 | TerminatorKind::UnwindTerminate(_)
661 | TerminatorKind::Return
662 | TerminatorKind::TailCall { .. }
663 | TerminatorKind::Unreachable
664 | TerminatorKind::CoroutineDrop
665 | TerminatorKind::Yield { .. }
666 | TerminatorKind::SwitchInt { .. }
667 | TerminatorKind::FalseEdge { .. } => None,
668 TerminatorKind::Call { ref mut unwind, .. }
669 | TerminatorKind::Assert { ref mut unwind, .. }
670 | TerminatorKind::Drop { ref mut unwind, .. }
671 | TerminatorKind::FalseUnwind { ref mut unwind, .. }
672 | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
673 }
674 }
675
676 #[inline]
677 pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> {
678 match self {
679 TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)),
680 _ => None,
681 }
682 }
683
684 #[inline]
685 pub fn as_goto(&self) -> Option<BasicBlock> {
686 match self {
687 TerminatorKind::Goto { target, loop_hint_attrs: _ } => Some(*target),
688 _ => None,
689 }
690 }
691}
692
693#[derive(#[automatically_derived]impl<'mir, 'tcx> ::core::fmt::Debug for
TerminatorEdges<'mir, 'tcx> {
#[inline]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::None => ::core::fmt::Formatter::write_str(f, "None"),
Self::Single(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"Single", &__self_0),
Self::Double(__self_0, __self_1) =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"Double", __self_0, &__self_1),
Self::AssignOnReturn {
return_: __self_0, cleanup: __self_1, place: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"AssignOnReturn return_ cleanup place", __self_0, __self_1,
&__self_2),
Self::SwitchInt { targets: __self_0, discr: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SwitchInt targets discr", __self_0, &__self_1),
}
}
}Debug)]
694pub enum TerminatorEdges<'mir, 'tcx> {
695 None,
697 Single(BasicBlock),
700 Double(BasicBlock, BasicBlock),
703 AssignOnReturn {
705 return_: SmallVec<[BasicBlock; 1]>,
706 cleanup: Option<BasicBlock>,
708 place: CallReturnPlaces<'mir, 'tcx>,
709 },
710 SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> },
712}
713
714#[derive(#[automatically_derived]impl<'a, 'tcx> ::core::marker::Copy for
CallReturnPlaces<'a, 'tcx> {
}Copy, #[automatically_derived]#[doc(hidden)]unsafe impl<'a, 'tcx>
::core::clone::TrivialClone for CallReturnPlaces<'a, 'tcx> {
}
#[automatically_derived]impl<'a, 'tcx> ::core::clone::Clone for
CallReturnPlaces<'a, 'tcx> {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
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]
#[rustc_trivial_field_reads]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Self::Call(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Call",
&__self_0),
Self::Yield(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Yield",
&__self_0),
Self::InlineAsm(__self_0) =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"InlineAsm", &__self_0),
}
}
}Debug)]
717pub enum CallReturnPlaces<'a, 'tcx> {
718 Call(Place<'tcx>),
719 Yield(Place<'tcx>),
720 InlineAsm(&'a [InlineAsmOperand<'tcx>]),
721}
722
723impl<'tcx> CallReturnPlaces<'_, 'tcx> {
724 pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) {
725 match *self {
726 Self::Call(place) | Self::Yield(place) => f(place),
727 Self::InlineAsm(operands) => {
728 for op in operands {
729 match *op {
730 InlineAsmOperand::Out { place: Some(place), .. }
731 | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
732 _ => {}
733 }
734 }
735 }
736 }
737 }
738}
739
740impl<'tcx> Terminator<'tcx> {
741 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
742 self.kind.edges()
743 }
744}
745
746impl<'tcx> TerminatorKind<'tcx> {
747 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
748 use TerminatorKind::*;
749 match *self {
750 Return
751 | TailCall { .. }
752 | UnwindResume
753 | UnwindTerminate(_)
754 | CoroutineDrop
755 | Unreachable => TerminatorEdges::None,
756
757 Goto { target, loop_hint_attrs: _ } => TerminatorEdges::Single(target),
758
759 Assert { target, unwind, expected: _, msg: _, cond: _ }
762 | Drop { target, unwind, place: _, replace: _, drop: _ }
763 | FalseUnwind { real_target: target, unwind } => match unwind {
764 UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
765 UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
766 TerminatorEdges::Single(target)
767 }
768 },
769
770 FalseEdge { real_target, imaginary_target } => {
771 TerminatorEdges::Double(real_target, imaginary_target)
772 }
773
774 Yield { resume: target, drop, resume_arg, value: _ } => {
775 TerminatorEdges::AssignOnReturn {
776 return_: [target].into_iter().chain(drop.into_iter()).collect(),
777 cleanup: None,
778 place: CallReturnPlaces::Yield(resume_arg),
779 }
780 }
781
782 Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
783 TerminatorEdges::AssignOnReturn {
784 return_: target.into_iter().collect(),
785 cleanup: unwind.cleanup_block(),
786 place: CallReturnPlaces::Call(destination),
787 }
788 }
789
790 InlineAsm {
791 asm_macro: _,
792 template: _,
793 ref operands,
794 options: _,
795 line_spans: _,
796 ref targets,
797 unwind,
798 } => TerminatorEdges::AssignOnReturn {
799 return_: targets.iter().copied().collect(),
800 cleanup: unwind.cleanup_block(),
801 place: CallReturnPlaces::InlineAsm(operands),
802 },
803
804 SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr },
805 }
806 }
807}
808
809impl CallSource {
810 pub fn from_hir_call(self) -> bool {
811 #[allow(non_exhaustive_omitted_patterns)] match self {
CallSource::Normal => true,
_ => false,
}matches!(self, CallSource::Normal)
812 }
813}
814
815impl InlineAsmMacro {
816 pub const fn diverges(self, options: InlineAsmOptions) -> bool {
817 match self {
818 InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
819 InlineAsmMacro::NakedAsm => true,
820 }
821 }
822}