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