1use std::slice;
4
5use rustc_ast::InlineAsmOptions;
6use rustc_data_structures::packed::Pu128;
7use rustc_hir::LangItem;
8use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
9use smallvec::{SmallVec, smallvec};
10
11use super::*;
12
13impl SwitchTargets {
14 pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
19 let (values, mut targets): (SmallVec<_>, SmallVec<_>) =
20 targets.map(|(v, t)| (Pu128(v), t)).unzip();
21 targets.push(otherwise);
22 Self { values, targets }
23 }
24
25 pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
28 Self { values: {
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(<[_]>::into_vec(::alloc::boxed::box_new([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(<[_]>::into_vec(::alloc::boxed::box_new([then,
else_])))
}
}smallvec![then, else_] }
29 }
30
31 #[inline]
33 pub fn as_static_if(&self) -> Option<(u128, BasicBlock, BasicBlock)> {
34 if let &[value] = &self.values[..]
35 && let &[then, else_] = &self.targets[..]
36 {
37 Some((value.get(), then, else_))
38 } else {
39 None
40 }
41 }
42
43 #[inline]
45 pub fn otherwise(&self) -> BasicBlock {
46 *self.targets.last().unwrap()
47 }
48
49 #[inline]
56 pub fn iter(&self) -> SwitchTargetsIter<'_> {
57 SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) }
58 }
59
60 #[inline]
62 pub fn all_targets(&self) -> &[BasicBlock] {
63 &self.targets
64 }
65
66 #[inline]
67 pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
68 &mut self.targets
69 }
70
71 #[inline]
73 pub fn all_values(&self) -> &[Pu128] {
74 &self.values
75 }
76
77 #[inline]
78 pub fn all_values_mut(&mut self) -> &mut [Pu128] {
79 &mut self.values
80 }
81
82 #[inline]
86 pub fn target_for_value(&self, value: u128) -> BasicBlock {
87 self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
88 }
89
90 #[inline]
92 pub fn add_target(&mut self, value: u128, bb: BasicBlock) {
93 let value = Pu128(value);
94 if self.values.contains(&value) {
95 crate::util::bug::bug_fmt(format_args!("target value {0:?} already present",
value));bug!("target value {:?} already present", value);
96 }
97 self.values.push(value);
98 self.targets.insert(self.targets.len() - 1, bb);
99 }
100
101 #[inline]
103 pub fn is_distinct(&self) -> bool {
104 self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len()
105 }
106}
107
108pub struct SwitchTargetsIter<'a> {
109 inner: iter::Zip<slice::Iter<'a, Pu128>, slice::Iter<'a, BasicBlock>>,
110}
111
112impl<'a> Iterator for SwitchTargetsIter<'a> {
113 type Item = (u128, BasicBlock);
114
115 #[inline]
116 fn next(&mut self) -> Option<Self::Item> {
117 self.inner.next().map(|(val, bb)| (val.get(), *bb))
118 }
119
120 #[inline]
121 fn size_hint(&self) -> (usize, Option<usize>) {
122 self.inner.size_hint()
123 }
124}
125
126impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
127
128impl UnwindAction {
129 fn cleanup_block(self) -> Option<BasicBlock> {
130 match self {
131 UnwindAction::Cleanup(bb) => Some(bb),
132 UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
133 }
134 }
135}
136
137impl UnwindTerminateReason {
138 pub fn as_str(self) -> &'static str {
139 match self {
141 UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
142 UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
143 }
144 }
145
146 pub fn as_short_str(self) -> &'static str {
148 match self {
149 UnwindTerminateReason::Abi => "abi",
150 UnwindTerminateReason::InCleanup => "cleanup",
151 }
152 }
153
154 pub fn lang_item(self) -> LangItem {
155 match self {
156 UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
157 UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
158 }
159 }
160}
161
162impl<O> AssertKind<O> {
163 pub fn is_optional_overflow_check(&self) -> bool {
165 use AssertKind::*;
166 use BinOp::*;
167 #[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, ..))
168 }
169
170 pub fn panic_function(&self) -> LangItem {
177 use AssertKind::*;
178 match self {
179 Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
180 Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
181 Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
182 Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
183 Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
184 OverflowNeg(_) => LangItem::PanicNegOverflow,
185 Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
186 Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
187 Overflow(op, _, _) => crate::util::bug::bug_fmt(format_args!("{0:?} cannot overflow", op))bug!("{:?} cannot overflow", op),
188 DivisionByZero(_) => LangItem::PanicDivZero,
189 RemainderByZero(_) => LangItem::PanicRemZero,
190 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
191 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
192 LangItem::PanicAsyncFnResumed
193 }
194 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
195 LangItem::PanicAsyncGenFnResumed
196 }
197 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
198 LangItem::PanicGenFnNone
199 }
200 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
201 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
202 LangItem::PanicAsyncFnResumedPanic
203 }
204 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
205 LangItem::PanicAsyncGenFnResumedPanic
206 }
207 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
208 LangItem::PanicGenFnNonePanic
209 }
210 NullPointerDereference => LangItem::PanicNullPointerDereference,
211 InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction,
212 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop,
213 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
214 LangItem::PanicAsyncFnResumedDrop
215 }
216 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
217 LangItem::PanicAsyncGenFnResumedDrop
218 }
219 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
220 LangItem::PanicGenFnNoneDrop
221 }
222
223 BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
224 crate::util::bug::bug_fmt(format_args!("Unexpected AssertKind"))bug!("Unexpected AssertKind")
225 }
226 }
227 }
228
229 pub fn fmt_assert_args<W: fmt::Write>(&self, f: &mut W) -> fmt::Result
236 where
237 O: Debug,
238 {
239 use AssertKind::*;
240 match self {
241 BoundsCheck { len, index } => f.write_fmt(format_args!("\"index out of bounds: the length is {{}} but the index is {{}}\", {0:?}, {1:?}",
len, index))write!(
242 f,
243 "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}"
244 ),
245
246 OverflowNeg(op) => {
247 f.write_fmt(format_args!("\"attempt to negate `{{}}`, which would overflow\", {0:?}",
op))write!(f, "\"attempt to negate `{{}}`, which would overflow\", {op:?}")
248 }
249 DivisionByZero(op) => f.write_fmt(format_args!("\"attempt to divide `{{}}` by zero\", {0:?}", op))write!(f, "\"attempt to divide `{{}}` by zero\", {op:?}"),
250 RemainderByZero(op) => f.write_fmt(format_args!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {0:?}",
op))write!(
251 f,
252 "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {op:?}"
253 ),
254 Overflow(BinOp::Add, l, r) => f.write_fmt(format_args!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
255 f,
256 "\"attempt to compute `{{}} + {{}}`, which would overflow\", {l:?}, {r:?}"
257 ),
258 Overflow(BinOp::Sub, 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::Mul, 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::Div, 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::Rem, l, r) => f.write_fmt(format_args!("\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {0:?}, {1:?}",
l, r))write!(
271 f,
272 "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {l:?}, {r:?}"
273 ),
274 Overflow(BinOp::Shr, _, r) => {
275 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:?}")
276 }
277 Overflow(BinOp::Shl, _, r) => {
278 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:?}")
279 }
280 Overflow(op, _, _) => crate::util::bug::bug_fmt(format_args!("{0:?} cannot overflow", op))bug!("{:?} cannot overflow", op),
281 MisalignedPointerDereference { required, found } => {
282 f.write_fmt(format_args!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {0:?}, {1:?}",
required, found))write!(
283 f,
284 "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
285 )
286 }
287 NullPointerDereference => f.write_fmt(format_args!("\"null pointer dereference occurred\""))write!(f, "\"null pointer dereference occurred\""),
288 InvalidEnumConstruction(source) => {
289 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:?}")
290 }
291 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
292 f.write_fmt(format_args!("\"coroutine resumed after completion\""))write!(f, "\"coroutine resumed after completion\"")
293 }
294 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
295 f.write_fmt(format_args!("\"`async fn` resumed after completion\""))write!(f, "\"`async fn` resumed after completion\"")
296 }
297 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
298 f.write_fmt(format_args!("\"`async gen fn` resumed after completion\""))write!(f, "\"`async gen fn` resumed after completion\"")
299 }
300 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
301 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\"")
302 }
303 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
304 f.write_fmt(format_args!("\"coroutine resumed after panicking\""))write!(f, "\"coroutine resumed after panicking\"")
305 }
306 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
307 f.write_fmt(format_args!("\"`async fn` resumed after panicking\""))write!(f, "\"`async fn` resumed after panicking\"")
308 }
309 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
310 f.write_fmt(format_args!("\"`async gen fn` resumed after panicking\""))write!(f, "\"`async gen fn` resumed after panicking\"")
311 }
312 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
313 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\"")
314 }
315 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
316 f.write_fmt(format_args!("\"coroutine resumed after async drop\""))write!(f, "\"coroutine resumed after async drop\"")
317 }
318 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
319 f.write_fmt(format_args!("\"`async fn` resumed after async drop\""))write!(f, "\"`async fn` resumed after async drop\"")
320 }
321 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
322 f.write_fmt(format_args!("\"`async gen fn` resumed after async drop\""))write!(f, "\"`async gen fn` resumed after async drop\"")
323 }
324 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
325 f.write_fmt(format_args!("\"`gen fn` resumed after drop\""))write!(f, "\"`gen fn` resumed after drop\"")
326 }
327 }
328 }
329
330 pub fn diagnostic_message(&self) -> DiagMessage {
337 use AssertKind::*;
338
339 match self {
340 BoundsCheck { .. } => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("index out of bounds: the length is {$len} but the index is {$index}"))inline_fluent!(
341 "index out of bounds: the length is {$len} but the index is {$index}"
342 ),
343 Overflow(BinOp::Shl, _, _) => {
344 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to shift left by `{$val}`, which would overflow"))inline_fluent!("attempt to shift left by `{$val}`, which would overflow")
345 }
346 Overflow(BinOp::Shr, _, _) => {
347 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to shift right by `{$val}`, which would overflow"))inline_fluent!("attempt to shift right by `{$val}`, which would overflow")
348 }
349 Overflow(_, _, _) => {
350 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to compute `{$left} {$op} {$right}`, which would overflow"))inline_fluent!("attempt to compute `{$left} {$op} {$right}`, which would overflow")
351 }
352 OverflowNeg(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to negate `{$val}`, which would overflow"))inline_fluent!("attempt to negate `{$val}`, which would overflow"),
353 DivisionByZero(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to divide `{$val}` by zero"))inline_fluent!("attempt to divide `{$val}` by zero"),
354 RemainderByZero(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("attempt to calculate the remainder of `{$val}` with a divisor of zero"))inline_fluent!(
355 "attempt to calculate the remainder of `{$val}` with a divisor of zero"
356 ),
357 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
358 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`async fn` resumed after completion"))inline_fluent!("`async fn` resumed after completion")
359 }
360 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
361 ::core::panicking::panic("not yet implemented")todo!()
362 }
363 ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
364 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`")
365 }
366 ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
367 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("coroutine resumed after completion"))inline_fluent!("coroutine resumed after completion")
368 }
369 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
370 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`async fn` resumed after panicking"))inline_fluent!("`async fn` resumed after panicking")
371 }
372 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
373 ::core::panicking::panic("not yet implemented")todo!()
374 }
375 ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
376 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`gen` fn or block cannot be further iterated on after it panicked"))inline_fluent!("`gen` fn or block cannot be further iterated on after it panicked")
377 }
378 ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
379 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("coroutine resumed after panicking"))inline_fluent!("coroutine resumed after panicking")
380 }
381 NullPointerDereference => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("null pointer dereference occurred"))inline_fluent!("null pointer dereference occurred"),
382 InvalidEnumConstruction(_) => {
383 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("trying to construct an enum from an invalid value `{$source}`"))inline_fluent!("trying to construct an enum from an invalid value `{$source}`")
384 }
385 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
386 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`async fn` resumed after async drop"))inline_fluent!("`async fn` resumed after async drop")
387 }
388 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
389 ::core::panicking::panic("not yet implemented")todo!()
390 }
391 ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
392 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`gen` fn or block cannot be further iterated on after it async dropped"))inline_fluent!(
393 "`gen` fn or block cannot be further iterated on after it async dropped"
394 )
395 }
396 ResumedAfterDrop(CoroutineKind::Coroutine(_)) => {
397 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("coroutine resumed after async drop"))inline_fluent!("coroutine resumed after async drop")
398 }
399
400 MisalignedPointerDereference { .. } => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("misaligned pointer dereference: address must be a multiple of {$required} but is {$found}"))inline_fluent!(
401 "misaligned pointer dereference: address must be a multiple of {$required} but is {$found}"
402 ),
403 }
404 }
405
406 pub fn add_args(self, adder: &mut dyn FnMut(DiagArgName, DiagArgValue))
407 where
408 O: fmt::Debug,
409 {
410 use AssertKind::*;
411
412 macro_rules! add {
413 ($name: expr, $value: expr) => {
414 adder($name.into(), $value.into_diag_arg(&mut None));
415 };
416 }
417
418 match self {
419 BoundsCheck { len, index } => {
420 adder("len".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", len))
}).into_diag_arg(&mut None));add!("len", format!("{len:?}"));
421 adder("index".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", index))
}).into_diag_arg(&mut None));add!("index", format!("{index:?}"));
422 }
423 Overflow(BinOp::Shl | BinOp::Shr, _, val)
424 | DivisionByZero(val)
425 | RemainderByZero(val)
426 | OverflowNeg(val) => {
427 adder("val".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", val))
}).into_diag_arg(&mut None));add!("val", format!("{val:#?}"));
428 }
429 Overflow(binop, left, right) => {
430 adder("op".into(), binop.to_hir_binop().as_str().into_diag_arg(&mut None));add!("op", binop.to_hir_binop().as_str());
431 adder("left".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", left))
}).into_diag_arg(&mut None));add!("left", format!("{left:#?}"));
432 adder("right".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", right))
}).into_diag_arg(&mut None));add!("right", format!("{right:#?}"));
433 }
434 ResumedAfterReturn(_)
435 | ResumedAfterPanic(_)
436 | NullPointerDereference
437 | ResumedAfterDrop(_) => {}
438 MisalignedPointerDereference { required, found } => {
439 adder("required".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", required))
}).into_diag_arg(&mut None));add!("required", format!("{required:#?}"));
440 adder("found".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", found))
}).into_diag_arg(&mut None));add!("found", format!("{found:#?}"));
441 }
442 InvalidEnumConstruction(source) => {
443 adder("source".into(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", source))
}).into_diag_arg(&mut None));add!("source", format!("{source:#?}"));
444 }
445 }
446 }
447}
448
449#[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),
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Terminator<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Terminator",
"source_info", &self.source_info, "kind", &&self.kind)
}
}Debug, 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 } => {
::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, '__ctx>
::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
for Terminator<'tcx> {
#[inline]
fn hash_stable(&self,
__hcx:
&mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
Terminator {
source_info: ref __binding_0, kind: ref __binding_1 } => {
{ __binding_0.hash_stable(__hcx, __hasher); }
{ __binding_1.hash_stable(__hcx, __hasher); }
}
}
}
}
};HashStable, 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)]
450pub struct Terminator<'tcx> {
451 pub source_info: SourceInfo,
452 pub kind: TerminatorKind<'tcx>,
453}
454
455impl<'tcx> Terminator<'tcx> {
456 #[inline]
457 pub fn successors(&self) -> Successors<'_> {
458 self.kind.successors()
459 }
460
461 #[inline]
463 pub fn identical_successor(&self) -> Option<BasicBlock> {
464 let mut successors = self.successors();
465 let first_succ = successors.next()?;
466 if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None }
467 }
468
469 #[inline]
470 pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) {
471 self.kind.successors_mut(f)
472 }
473
474 #[inline]
475 pub fn unwind(&self) -> Option<&UnwindAction> {
476 self.kind.unwind()
477 }
478
479 #[inline]
480 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
481 self.kind.unwind_mut()
482 }
483}
484
485impl<'tcx> TerminatorKind<'tcx> {
486 pub const fn name(&self) -> &'static str {
489 match self {
490 TerminatorKind::Goto { .. } => "Goto",
491 TerminatorKind::SwitchInt { .. } => "SwitchInt",
492 TerminatorKind::UnwindResume => "UnwindResume",
493 TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
494 TerminatorKind::Return => "Return",
495 TerminatorKind::Unreachable => "Unreachable",
496 TerminatorKind::Drop { .. } => "Drop",
497 TerminatorKind::Call { .. } => "Call",
498 TerminatorKind::TailCall { .. } => "TailCall",
499 TerminatorKind::Assert { .. } => "Assert",
500 TerminatorKind::Yield { .. } => "Yield",
501 TerminatorKind::CoroutineDrop => "CoroutineDrop",
502 TerminatorKind::FalseEdge { .. } => "FalseEdge",
503 TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
504 TerminatorKind::InlineAsm { .. } => "InlineAsm",
505 }
506 }
507
508 #[inline]
509 pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
510 TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
511 }
512}
513
514pub use helper::*;
515use rustc_errors::inline_fluent;
516
517mod helper {
518 use super::*;
519 pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
520
521 #[inline]
523 #[define_opaque(Successors)]
524 fn mk_successors(
525 slice: &[BasicBlock],
526 option1: Option<BasicBlock>,
527 option2: Option<BasicBlock>,
528 ) -> Successors<'_> {
529 slice.iter().copied().chain(option1.into_iter().chain(option2))
530 }
531
532 impl SwitchTargets {
533 #[inline]
536 pub fn successors_for_value(&self, value: u128) -> Successors<'_> {
537 let target = self.target_for_value(value);
538 mk_successors(&[], Some(target), None)
539 }
540 }
541
542 impl<'tcx> TerminatorKind<'tcx> {
543 #[inline]
544 pub fn successors(&self) -> Successors<'_> {
545 use self::TerminatorKind::*;
546 match *self {
547 Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: Some(d), .. } => {
549 mk_successors(slice::from_ref(t), Some(u), Some(d))
550 }
551 Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
553 | Yield { resume: ref t, drop: Some(u), .. }
554 | Drop { target: ref t, unwind: UnwindAction::Cleanup(u), drop: None, .. }
555 | Drop { target: ref t, unwind: _, drop: Some(u), .. }
556 | Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
557 | FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
558 mk_successors(slice::from_ref(t), Some(u), None)
559 }
560 Goto { target: ref t }
562 | Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
563 | Call { target: Some(ref t), unwind: _, .. }
564 | Yield { resume: ref t, drop: None, .. }
565 | Drop { target: ref t, unwind: _, .. }
566 | Assert { target: ref t, unwind: _, .. }
567 | FalseUnwind { real_target: ref t, unwind: _ } => {
568 mk_successors(slice::from_ref(t), None, None)
569 }
570 UnwindResume
572 | UnwindTerminate(_)
573 | CoroutineDrop
574 | Return
575 | Unreachable
576 | TailCall { .. }
577 | Call { target: None, unwind: _, .. } => mk_successors(&[], None, None),
578 InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
580 mk_successors(targets, Some(u), None)
581 }
582 InlineAsm { ref targets, unwind: _, .. } => mk_successors(targets, None, None),
583 SwitchInt { ref targets, .. } => mk_successors(&targets.targets, None, None),
584 FalseEdge { ref real_target, imaginary_target } => {
586 mk_successors(slice::from_ref(real_target), Some(imaginary_target), None)
587 }
588 }
589 }
590
591 #[inline]
592 pub fn successors_mut<'a>(&'a mut self, mut f: impl FnMut(&'a mut BasicBlock)) {
593 use self::TerminatorKind::*;
594 match self {
595 Drop { target, unwind, drop, .. } => {
596 f(target);
597 if let UnwindAction::Cleanup(u) = unwind {
598 f(u)
599 }
600 if let Some(d) = drop {
601 f(d)
602 }
603 }
604 Call { target, unwind, .. } => {
605 if let Some(target) = target {
606 f(target);
607 }
608 if let UnwindAction::Cleanup(u) = unwind {
609 f(u)
610 }
611 }
612 Yield { resume, drop, .. } => {
613 f(resume);
614 if let Some(d) = drop {
615 f(d)
616 }
617 }
618 Assert { target, unwind, .. } | FalseUnwind { real_target: target, unwind } => {
619 f(target);
620 if let UnwindAction::Cleanup(u) = unwind {
621 f(u)
622 }
623 }
624 Goto { target } => {
625 f(target);
626 }
627 UnwindResume
628 | UnwindTerminate(_)
629 | CoroutineDrop
630 | Return
631 | Unreachable
632 | TailCall { .. } => {}
633 InlineAsm { targets, unwind, .. } => {
634 for target in targets {
635 f(target);
636 }
637 if let UnwindAction::Cleanup(u) = unwind {
638 f(u)
639 }
640 }
641 SwitchInt { targets, .. } => {
642 for target in &mut targets.targets {
643 f(target);
644 }
645 }
646 FalseEdge { real_target, imaginary_target } => {
647 f(real_target);
648 f(imaginary_target);
649 }
650 }
651 }
652 }
653}
654
655impl<'tcx> TerminatorKind<'tcx> {
656 #[inline]
657 pub fn unwind(&self) -> Option<&UnwindAction> {
658 match *self {
659 TerminatorKind::Goto { .. }
660 | TerminatorKind::UnwindResume
661 | TerminatorKind::UnwindTerminate(_)
662 | TerminatorKind::Return
663 | TerminatorKind::TailCall { .. }
664 | TerminatorKind::Unreachable
665 | TerminatorKind::CoroutineDrop
666 | TerminatorKind::Yield { .. }
667 | TerminatorKind::SwitchInt { .. }
668 | TerminatorKind::FalseEdge { .. } => None,
669 TerminatorKind::Call { ref unwind, .. }
670 | TerminatorKind::Assert { ref unwind, .. }
671 | TerminatorKind::Drop { ref unwind, .. }
672 | TerminatorKind::FalseUnwind { ref unwind, .. }
673 | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
674 }
675 }
676
677 #[inline]
678 pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
679 match *self {
680 TerminatorKind::Goto { .. }
681 | TerminatorKind::UnwindResume
682 | TerminatorKind::UnwindTerminate(_)
683 | TerminatorKind::Return
684 | TerminatorKind::TailCall { .. }
685 | TerminatorKind::Unreachable
686 | TerminatorKind::CoroutineDrop
687 | TerminatorKind::Yield { .. }
688 | TerminatorKind::SwitchInt { .. }
689 | TerminatorKind::FalseEdge { .. } => None,
690 TerminatorKind::Call { ref mut unwind, .. }
691 | TerminatorKind::Assert { ref mut unwind, .. }
692 | TerminatorKind::Drop { ref mut unwind, .. }
693 | TerminatorKind::FalseUnwind { ref mut unwind, .. }
694 | TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
695 }
696 }
697
698 #[inline]
699 pub fn as_switch(&self) -> Option<(&Operand<'tcx>, &SwitchTargets)> {
700 match self {
701 TerminatorKind::SwitchInt { discr, targets } => Some((discr, targets)),
702 _ => None,
703 }
704 }
705
706 #[inline]
707 pub fn as_goto(&self) -> Option<BasicBlock> {
708 match self {
709 TerminatorKind::Goto { target } => Some(*target),
710 _ => None,
711 }
712 }
713
714 pub fn can_write_to_memory(&self) -> bool {
716 match self {
717 TerminatorKind::Goto { .. }
718 | TerminatorKind::SwitchInt { .. }
719 | TerminatorKind::UnwindResume
720 | TerminatorKind::UnwindTerminate(_)
721 | TerminatorKind::Return
722 | TerminatorKind::Assert { .. }
723 | TerminatorKind::CoroutineDrop
724 | TerminatorKind::FalseEdge { .. }
725 | TerminatorKind::FalseUnwind { .. }
726 | TerminatorKind::Unreachable => false,
727 TerminatorKind::Call { .. }
728 | TerminatorKind::Drop { .. }
729 | TerminatorKind::TailCall { .. }
730 | TerminatorKind::Yield { .. }
732 | TerminatorKind::InlineAsm { .. } => true,
733 }
734 }
735}
736
737#[derive(#[automatically_derived]
impl<'mir, 'tcx> ::core::marker::Copy for TerminatorEdges<'mir, 'tcx> { }Copy, #[automatically_derived]
impl<'mir, 'tcx> ::core::clone::Clone for TerminatorEdges<'mir, 'tcx> {
#[inline]
fn clone(&self) -> TerminatorEdges<'mir, 'tcx> {
let _: ::core::clone::AssertParamIsClone<BasicBlock>;
let _: ::core::clone::AssertParamIsClone<&'mir [BasicBlock]>;
let _: ::core::clone::AssertParamIsClone<Option<BasicBlock>>;
let _:
::core::clone::AssertParamIsClone<CallReturnPlaces<'mir,
'tcx>>;
let _: ::core::clone::AssertParamIsClone<&'mir SwitchTargets>;
let _: ::core::clone::AssertParamIsClone<&'mir Operand<'tcx>>;
*self
}
}Clone, #[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)]
738pub enum TerminatorEdges<'mir, 'tcx> {
739 None,
741 Single(BasicBlock),
744 Double(BasicBlock, BasicBlock),
747 AssignOnReturn {
749 return_: &'mir [BasicBlock],
750 cleanup: Option<BasicBlock>,
752 place: CallReturnPlaces<'mir, 'tcx>,
753 },
754 SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> },
756}
757
758#[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)]
761pub enum CallReturnPlaces<'a, 'tcx> {
762 Call(Place<'tcx>),
763 Yield(Place<'tcx>),
764 InlineAsm(&'a [InlineAsmOperand<'tcx>]),
765}
766
767impl<'tcx> CallReturnPlaces<'_, 'tcx> {
768 pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) {
769 match *self {
770 Self::Call(place) | Self::Yield(place) => f(place),
771 Self::InlineAsm(operands) => {
772 for op in operands {
773 match *op {
774 InlineAsmOperand::Out { place: Some(place), .. }
775 | InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
776 _ => {}
777 }
778 }
779 }
780 }
781 }
782}
783
784impl<'tcx> Terminator<'tcx> {
785 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
786 self.kind.edges()
787 }
788}
789
790impl<'tcx> TerminatorKind<'tcx> {
791 pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
792 use TerminatorKind::*;
793 match *self {
794 Return
795 | TailCall { .. }
796 | UnwindResume
797 | UnwindTerminate(_)
798 | CoroutineDrop
799 | Unreachable => TerminatorEdges::None,
800
801 Goto { target } => TerminatorEdges::Single(target),
802
803 Assert { target, unwind, expected: _, msg: _, cond: _ }
806 | Drop { target, unwind, place: _, replace: _, drop: _, async_fut: _ }
807 | FalseUnwind { real_target: target, unwind } => match unwind {
808 UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
809 UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
810 TerminatorEdges::Single(target)
811 }
812 },
813
814 FalseEdge { real_target, imaginary_target } => {
815 TerminatorEdges::Double(real_target, imaginary_target)
816 }
817
818 Yield { resume: ref target, drop, resume_arg, value: _ } => {
819 TerminatorEdges::AssignOnReturn {
820 return_: slice::from_ref(target),
821 cleanup: drop,
822 place: CallReturnPlaces::Yield(resume_arg),
823 }
824 }
825
826 Call {
827 unwind,
828 destination,
829 ref target,
830 func: _,
831 args: _,
832 fn_span: _,
833 call_source: _,
834 } => TerminatorEdges::AssignOnReturn {
835 return_: target.as_ref().map(slice::from_ref).unwrap_or_default(),
836 cleanup: unwind.cleanup_block(),
837 place: CallReturnPlaces::Call(destination),
838 },
839
840 InlineAsm {
841 asm_macro: _,
842 template: _,
843 ref operands,
844 options: _,
845 line_spans: _,
846 ref targets,
847 unwind,
848 } => TerminatorEdges::AssignOnReturn {
849 return_: targets,
850 cleanup: unwind.cleanup_block(),
851 place: CallReturnPlaces::InlineAsm(operands),
852 },
853
854 SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr },
855 }
856 }
857}
858
859impl CallSource {
860 pub fn from_hir_call(self) -> bool {
861 #[allow(non_exhaustive_omitted_patterns)] match self {
CallSource::Normal => true,
_ => false,
}matches!(self, CallSource::Normal)
862 }
863}
864
865impl InlineAsmMacro {
866 pub const fn diverges(self, options: InlineAsmOptions) -> bool {
867 match self {
868 InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
869 InlineAsmMacro::NakedAsm => true,
870 }
871 }
872}