Auto merge of #102906 - nbdd0121:mir, r=wesleywiser,tmiasko
Refactor unwind in MIR This makes unwinding from current `Option<BasicBlock>` into ```rust enum UnwindAction { Continue, Cleanup(BasicBlock), Unreachable, Terminate, } ``` cc `@JakobDegen` `@RalfJung` `@Amanieu`
This commit is contained in:
commit
da14081468
294 changed files with 1225 additions and 933 deletions
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::{Body, Local, Location};
|
use rustc_middle::mir::{self, Body, Local, Location};
|
||||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
|
|
||||||
pub(crate) fn find<'tcx>(
|
pub(crate) fn find<'tcx>(
|
||||||
|
@ -70,7 +70,10 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
|
||||||
block_data
|
block_data
|
||||||
.terminator()
|
.terminator()
|
||||||
.successors()
|
.successors()
|
||||||
.filter(|&bb| Some(&Some(bb)) != block_data.terminator().unwind())
|
.filter(|&bb| {
|
||||||
|
Some(&mir::UnwindAction::Cleanup(bb))
|
||||||
|
!= block_data.terminator().unwind()
|
||||||
|
})
|
||||||
.map(|bb| Location { statement_index: 0, block: bb }),
|
.map(|bb| Location { statement_index: 0, block: bb }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
|
@ -135,7 +135,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
self.mutate_place(location, *destination, Deep);
|
self.mutate_place(location, *destination, Deep);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
|
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
||||||
self.consume_operand(location, cond);
|
self.consume_operand(location, cond);
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
if let AssertKind::BoundsCheck { len, index } = msg {
|
if let AssertKind::BoundsCheck { len, index } = msg {
|
||||||
|
@ -173,7 +173,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
match op {
|
match op {
|
||||||
|
@ -198,7 +198,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Goto { target: _ }
|
TerminatorKind::Goto { target: _ }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
||||||
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
|
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
|
||||||
|
|
|
@ -740,7 +740,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
|
@ -750,7 +750,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
}
|
}
|
||||||
self.mutate_place(loc, (*destination, span), Deep, flow_state);
|
self.mutate_place(loc, (*destination, span), Deep, flow_state);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cond, expected: _, msg, target: _, cleanup: _ } => {
|
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
||||||
self.consume_operand(loc, (cond, span), flow_state);
|
self.consume_operand(loc, (cond, span), flow_state);
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
if let AssertKind::BoundsCheck { len, index } = msg {
|
if let AssertKind::BoundsCheck { len, index } = msg {
|
||||||
|
@ -770,7 +770,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
match op {
|
match op {
|
||||||
|
@ -801,7 +801,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Goto { target: _ }
|
TerminatorKind::Goto { target: _ }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
|
@ -845,7 +845,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Abort
|
TerminatorKind::Terminate
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
|
|
|
@ -1300,7 +1300,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
match &term.kind {
|
match &term.kind {
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
|
@ -1584,7 +1584,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
span_mirbug!(self, block_data, "resume on non-cleanup block!")
|
span_mirbug!(self, block_data, "resume on non-cleanup block!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Abort => {
|
TerminatorKind::Terminate => {
|
||||||
if !is_cleanup {
|
if !is_cleanup {
|
||||||
span_mirbug!(self, block_data, "abort on non-cleanup block!")
|
span_mirbug!(self, block_data, "abort on non-cleanup block!")
|
||||||
}
|
}
|
||||||
|
@ -1610,25 +1610,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
TerminatorKind::Unreachable => {}
|
TerminatorKind::Unreachable => {}
|
||||||
TerminatorKind::Drop { target, unwind, .. }
|
TerminatorKind::Drop { target, unwind, .. }
|
||||||
| TerminatorKind::Assert { target, cleanup: unwind, .. } => {
|
| TerminatorKind::Assert { target, unwind, .. } => {
|
||||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||||
if let Some(unwind) = unwind {
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
if is_cleanup {
|
|
||||||
span_mirbug!(self, block_data, "unwind on cleanup block")
|
|
||||||
}
|
|
||||||
self.assert_iscleanup(body, block_data, unwind, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { ref target, cleanup, .. } => {
|
TerminatorKind::Call { ref target, unwind, .. } => {
|
||||||
if let &Some(target) = target {
|
if let &Some(target) = target {
|
||||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||||
}
|
}
|
||||||
if let Some(cleanup) = cleanup {
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
if is_cleanup {
|
|
||||||
span_mirbug!(self, block_data, "cleanup on cleanup block")
|
|
||||||
}
|
|
||||||
self.assert_iscleanup(body, block_data, cleanup, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
|
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
|
||||||
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
||||||
|
@ -1636,23 +1626,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
TerminatorKind::FalseUnwind { real_target, unwind } => {
|
TerminatorKind::FalseUnwind { real_target, unwind } => {
|
||||||
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
||||||
if let Some(unwind) = unwind {
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
if is_cleanup {
|
|
||||||
span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
|
|
||||||
}
|
|
||||||
self.assert_iscleanup(body, block_data, unwind, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { destination, cleanup, .. } => {
|
TerminatorKind::InlineAsm { destination, unwind, .. } => {
|
||||||
if let Some(target) = destination {
|
if let Some(target) = destination {
|
||||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||||
}
|
}
|
||||||
if let Some(cleanup) = cleanup {
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
if is_cleanup {
|
|
||||||
span_mirbug!(self, block_data, "cleanup on cleanup block")
|
|
||||||
}
|
|
||||||
self.assert_iscleanup(body, block_data, cleanup, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1669,6 +1649,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assert_iscleanup_unwind(
|
||||||
|
&mut self,
|
||||||
|
body: &Body<'tcx>,
|
||||||
|
ctxt: &dyn fmt::Debug,
|
||||||
|
unwind: UnwindAction,
|
||||||
|
is_cleanup: bool,
|
||||||
|
) {
|
||||||
|
match unwind {
|
||||||
|
UnwindAction::Cleanup(unwind) => {
|
||||||
|
if is_cleanup {
|
||||||
|
span_mirbug!(self, ctxt, "unwind on cleanup block")
|
||||||
|
}
|
||||||
|
self.assert_iscleanup(body, ctxt, unwind, true);
|
||||||
|
}
|
||||||
|
UnwindAction::Continue => {
|
||||||
|
if is_cleanup {
|
||||||
|
span_mirbug!(self, ctxt, "unwind on cleanup block")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||||
match body.local_kind(local) {
|
match body.local_kind(local) {
|
||||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||||
|
|
|
@ -345,7 +345,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
crate::abi::codegen_return(fx);
|
crate::abi::codegen_return(fx);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cond, expected, msg, target, cleanup: _ } => {
|
TerminatorKind::Assert { cond, expected, msg, target, unwind: _ } => {
|
||||||
if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
|
if !fx.tcx.sess.overflow_checks() && msg.is_optional_overflow_check() {
|
||||||
let target = fx.get_block(*target);
|
let target = fx.get_block(*target);
|
||||||
fx.bcx.ins().jump(target, &[]);
|
fx.bcx.ins().jump(target, &[]);
|
||||||
|
@ -450,7 +450,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
fn_span,
|
fn_span,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
} => {
|
} => {
|
||||||
fx.tcx.prof.generic_activity("codegen call").run(|| {
|
fx.tcx.prof.generic_activity("codegen call").run(|| {
|
||||||
|
@ -470,7 +470,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
options,
|
options,
|
||||||
destination,
|
destination,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||||
fx.tcx.sess.span_fatal(
|
fx.tcx.sess.span_fatal(
|
||||||
|
@ -488,7 +488,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||||
*destination,
|
*destination,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TerminatorKind::Abort => {
|
TerminatorKind::Terminate => {
|
||||||
codegen_panic_cannot_unwind(fx, source_info);
|
codegen_panic_cannot_unwind(fx, source_info);
|
||||||
}
|
}
|
||||||
TerminatorKind::Resume => {
|
TerminatorKind::Resume => {
|
||||||
|
|
|
@ -549,7 +549,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
|
|
|
@ -284,7 +284,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||||
match data.terminator().kind {
|
match data.terminator().kind {
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
|
@ -292,11 +292,11 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
|
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
|
||||||
TerminatorKind::Call { cleanup: unwind, .. }
|
TerminatorKind::Call { unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
|
| TerminatorKind::InlineAsm { unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: unwind, .. }
|
| TerminatorKind::Assert { unwind, .. }
|
||||||
| TerminatorKind::Drop { unwind, .. } => {
|
| TerminatorKind::Drop { unwind, .. } => {
|
||||||
if let Some(unwind) = unwind {
|
if let mir::UnwindAction::Cleanup(unwind) = unwind {
|
||||||
debug!(
|
debug!(
|
||||||
"cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
|
"cleanup_kinds: {:?}/{:?} registering {:?} as funclet",
|
||||||
bb, data, unwind
|
bb, data, unwind
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional
|
/// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional
|
||||||
/// return destination `destination` and the cleanup function `cleanup`.
|
/// return destination `destination` and the unwind action `unwind`.
|
||||||
fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
|
fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
||||||
|
@ -156,7 +156,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
fn_ptr: Bx::Value,
|
fn_ptr: Bx::Value,
|
||||||
llargs: &[Bx::Value],
|
llargs: &[Bx::Value],
|
||||||
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
|
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
mut unwind: mir::UnwindAction,
|
||||||
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
|
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
|
@ -164,23 +164,23 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
// do an invoke, otherwise do a call.
|
// do an invoke, otherwise do a call.
|
||||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||||
|
|
||||||
let unwind_block = if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
|
if !fn_abi.can_unwind {
|
||||||
Some(self.llbb_with_cleanup(fx, cleanup))
|
unwind = mir::UnwindAction::Unreachable;
|
||||||
} else if fx.mir[self.bb].is_cleanup
|
}
|
||||||
&& fn_abi.can_unwind
|
|
||||||
&& !base::wants_msvc_seh(fx.cx.tcx().sess)
|
let unwind_block = match unwind {
|
||||||
{
|
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||||
// Exception must not propagate out of the execution of a cleanup (doing so
|
mir::UnwindAction::Continue => None,
|
||||||
// can cause undefined behaviour). We insert a double unwind guard for
|
mir::UnwindAction::Unreachable => None,
|
||||||
// functions that can potentially unwind to protect against this.
|
mir::UnwindAction::Terminate => {
|
||||||
//
|
if fx.mir[self.bb].is_cleanup && base::wants_msvc_seh(fx.cx.tcx().sess) {
|
||||||
// This is not necessary for SEH which does not use successive unwinding
|
// SEH will abort automatically if an exception tries to
|
||||||
// like Itanium EH. EH frames in SEH are different from normal function
|
// propagate out from cleanup.
|
||||||
// frames and SEH will abort automatically if an exception tries to
|
None
|
||||||
// propagate out from cleanup.
|
} else {
|
||||||
Some(fx.double_unwind_guard())
|
Some(fx.terminate_block())
|
||||||
} else {
|
}
|
||||||
None
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(unwind_block) = unwind_block {
|
if let Some(unwind_block) = unwind_block {
|
||||||
|
@ -234,7 +234,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates inline assembly with optional `destination` and `cleanup`.
|
/// Generates inline assembly with optional `destination` and `unwind`.
|
||||||
fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
|
fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
||||||
|
@ -244,11 +244,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
options: InlineAsmOptions,
|
options: InlineAsmOptions,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
destination: Option<mir::BasicBlock>,
|
destination: Option<mir::BasicBlock>,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
if let Some(cleanup) = cleanup {
|
let unwind_target = match unwind {
|
||||||
|
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||||
|
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
|
||||||
|
mir::UnwindAction::Continue => None,
|
||||||
|
mir::UnwindAction::Unreachable => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(cleanup) = unwind_target {
|
||||||
let ret_llbb = if let Some(target) = destination {
|
let ret_llbb = if let Some(target) = destination {
|
||||||
fx.llbb(target)
|
fx.llbb(target)
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,7 +268,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
instance,
|
instance,
|
||||||
Some((ret_llbb, self.llbb_with_cleanup(fx, cleanup), self.funclet(fx))),
|
Some((ret_llbb, cleanup, self.funclet(fx))),
|
||||||
);
|
);
|
||||||
MergingSucc::False
|
MergingSucc::False
|
||||||
} else {
|
} else {
|
||||||
|
@ -431,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
location: mir::Place<'tcx>,
|
location: mir::Place<'tcx>,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
let ty = location.ty(self.mir, bx.tcx()).ty;
|
let ty = location.ty(self.mir, bx.tcx()).ty;
|
||||||
|
@ -552,7 +559,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
expected: bool,
|
expected: bool,
|
||||||
msg: &mir::AssertMessage<'tcx>,
|
msg: &mir::AssertMessage<'tcx>,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
let span = terminator.source_info.span;
|
let span = terminator.source_info.span;
|
||||||
|
@ -618,12 +625,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
|
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
|
||||||
|
|
||||||
// Codegen the actual panic invoke/call.
|
// Codegen the actual panic invoke/call.
|
||||||
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, cleanup, &[], false);
|
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
|
||||||
assert_eq!(merging_succ, MergingSucc::False);
|
assert_eq!(merging_succ, MergingSucc::False);
|
||||||
MergingSucc::False
|
MergingSucc::False
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_abort_terminator(
|
fn codegen_terminate_terminator(
|
||||||
&mut self,
|
&mut self,
|
||||||
helper: TerminatorCodegenHelper<'tcx>,
|
helper: TerminatorCodegenHelper<'tcx>,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
|
@ -636,7 +643,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
|
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
|
||||||
|
|
||||||
// Codegen the actual panic invoke/call.
|
// Codegen the actual panic invoke/call.
|
||||||
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &[], None, None, &[], false);
|
let merging_succ = helper.do_call(
|
||||||
|
self,
|
||||||
|
bx,
|
||||||
|
fn_abi,
|
||||||
|
llfn,
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
mir::UnwindAction::Unreachable,
|
||||||
|
&[],
|
||||||
|
false,
|
||||||
|
);
|
||||||
assert_eq!(merging_succ, MergingSucc::False);
|
assert_eq!(merging_succ, MergingSucc::False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +666,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
instance: Option<Instance<'tcx>>,
|
instance: Option<Instance<'tcx>>,
|
||||||
source_info: mir::SourceInfo,
|
source_info: mir::SourceInfo,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> Option<MergingSucc> {
|
) -> Option<MergingSucc> {
|
||||||
// Emit a panic or a no-op for `assert_*` intrinsics.
|
// Emit a panic or a no-op for `assert_*` intrinsics.
|
||||||
|
@ -696,7 +713,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
llfn,
|
llfn,
|
||||||
&[msg.0, msg.1],
|
&[msg.0, msg.1],
|
||||||
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
|
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
|
||||||
cleanup,
|
unwind,
|
||||||
&[],
|
&[],
|
||||||
mergeable_succ,
|
mergeable_succ,
|
||||||
)
|
)
|
||||||
|
@ -719,7 +736,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
args: &[mir::Operand<'tcx>],
|
args: &[mir::Operand<'tcx>],
|
||||||
destination: mir::Place<'tcx>,
|
destination: mir::Place<'tcx>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
fn_span: Span,
|
fn_span: Span,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
|
@ -783,7 +800,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
instance,
|
instance,
|
||||||
source_info,
|
source_info,
|
||||||
target,
|
target,
|
||||||
cleanup,
|
unwind,
|
||||||
mergeable_succ,
|
mergeable_succ,
|
||||||
) {
|
) {
|
||||||
return merging_succ;
|
return merging_succ;
|
||||||
|
@ -1064,7 +1081,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
fn_ptr,
|
fn_ptr,
|
||||||
&llargs,
|
&llargs,
|
||||||
target.as_ref().map(|&target| (ret_dest, target)),
|
target.as_ref().map(|&target| (ret_dest, target)),
|
||||||
cleanup,
|
unwind,
|
||||||
&copied_constant_arguments,
|
&copied_constant_arguments,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -1084,7 +1101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
fn_ptr,
|
fn_ptr,
|
||||||
&llargs,
|
&llargs,
|
||||||
target.as_ref().map(|&target| (ret_dest, target)),
|
target.as_ref().map(|&target| (ret_dest, target)),
|
||||||
cleanup,
|
unwind,
|
||||||
&copied_constant_arguments,
|
&copied_constant_arguments,
|
||||||
mergeable_succ,
|
mergeable_succ,
|
||||||
)
|
)
|
||||||
|
@ -1100,7 +1117,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
options: ast::InlineAsmOptions,
|
options: ast::InlineAsmOptions,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
destination: Option<mir::BasicBlock>,
|
destination: Option<mir::BasicBlock>,
|
||||||
cleanup: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
) -> MergingSucc {
|
) -> MergingSucc {
|
||||||
|
@ -1164,7 +1181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
destination,
|
||||||
cleanup,
|
unwind,
|
||||||
instance,
|
instance,
|
||||||
mergeable_succ,
|
mergeable_succ,
|
||||||
)
|
)
|
||||||
|
@ -1246,8 +1263,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
MergingSucc::False
|
MergingSucc::False
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::Abort => {
|
mir::TerminatorKind::Terminate => {
|
||||||
self.codegen_abort_terminator(helper, bx, terminator);
|
self.codegen_terminate_terminator(helper, bx, terminator);
|
||||||
MergingSucc::False
|
MergingSucc::False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1274,7 +1291,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
|
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => self
|
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
|
||||||
.codegen_assert_terminator(
|
.codegen_assert_terminator(
|
||||||
helper,
|
helper,
|
||||||
bx,
|
bx,
|
||||||
|
@ -1283,7 +1300,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
expected,
|
expected,
|
||||||
msg,
|
msg,
|
||||||
target,
|
target,
|
||||||
cleanup,
|
unwind,
|
||||||
mergeable_succ(),
|
mergeable_succ(),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -1292,7 +1309,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
ref args,
|
ref args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
cleanup,
|
unwind,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span,
|
fn_span,
|
||||||
} => self.codegen_call_terminator(
|
} => self.codegen_call_terminator(
|
||||||
|
@ -1303,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
cleanup,
|
unwind,
|
||||||
fn_span,
|
fn_span,
|
||||||
mergeable_succ(),
|
mergeable_succ(),
|
||||||
),
|
),
|
||||||
|
@ -1320,7 +1337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
destination,
|
||||||
cleanup,
|
unwind,
|
||||||
} => self.codegen_asm_terminator(
|
} => self.codegen_asm_terminator(
|
||||||
helper,
|
helper,
|
||||||
bx,
|
bx,
|
||||||
|
@ -1330,7 +1347,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
destination,
|
||||||
cleanup,
|
unwind,
|
||||||
self.instance,
|
self.instance,
|
||||||
mergeable_succ(),
|
mergeable_succ(),
|
||||||
),
|
),
|
||||||
|
@ -1536,62 +1553,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
|
fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
|
||||||
let llbb = self.llbb(bb);
|
let llbb = self.llbb(bb);
|
||||||
if base::wants_msvc_seh(self.cx.sess()) {
|
if base::wants_msvc_seh(self.cx.sess()) {
|
||||||
let funclet;
|
let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
|
||||||
let ret_llbb;
|
let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
|
||||||
match self.mir[bb].terminator.as_ref().map(|t| &t.kind) {
|
let funclet = cleanup_bx.cleanup_pad(None, &[]);
|
||||||
// This is a basic block that we're aborting the program for,
|
cleanup_bx.br(llbb);
|
||||||
// notably in an `extern` function. These basic blocks are inserted
|
|
||||||
// so that we assert that `extern` functions do indeed not panic,
|
|
||||||
// and if they do we abort the process.
|
|
||||||
//
|
|
||||||
// On MSVC these are tricky though (where we're doing funclets). If
|
|
||||||
// we were to do a cleanuppad (like below) the normal functions like
|
|
||||||
// `longjmp` would trigger the abort logic, terminating the
|
|
||||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
|
||||||
// which magically doesn't trigger when `longjmp` files over this
|
|
||||||
// frame.
|
|
||||||
//
|
|
||||||
// Lots more discussion can be found on #48251 but this codegen is
|
|
||||||
// modeled after clang's for:
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// foo();
|
|
||||||
// } catch (...) {
|
|
||||||
// bar();
|
|
||||||
// }
|
|
||||||
Some(&mir::TerminatorKind::Abort) => {
|
|
||||||
let cs_llbb =
|
|
||||||
Bx::append_block(self.cx, self.llfn, &format!("cs_funclet{:?}", bb));
|
|
||||||
let cp_llbb =
|
|
||||||
Bx::append_block(self.cx, self.llfn, &format!("cp_funclet{:?}", bb));
|
|
||||||
ret_llbb = cs_llbb;
|
|
||||||
|
|
||||||
let mut cs_bx = Bx::build(self.cx, cs_llbb);
|
|
||||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
|
||||||
|
|
||||||
// The "null" here is actually a RTTI type descriptor for the
|
|
||||||
// C++ personality function, but `catch (...)` has no type so
|
|
||||||
// it's null. The 64 here is actually a bitfield which
|
|
||||||
// represents that this is a catch-all block.
|
|
||||||
let mut cp_bx = Bx::build(self.cx, cp_llbb);
|
|
||||||
let null = cp_bx.const_null(
|
|
||||||
cp_bx.type_i8p_ext(cp_bx.cx().data_layout().instruction_address_space),
|
|
||||||
);
|
|
||||||
let sixty_four = cp_bx.const_i32(64);
|
|
||||||
funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
|
|
||||||
cp_bx.br(llbb);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let cleanup_llbb =
|
|
||||||
Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
|
|
||||||
ret_llbb = cleanup_llbb;
|
|
||||||
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
|
||||||
funclet = cleanup_bx.cleanup_pad(None, &[]);
|
|
||||||
cleanup_bx.br(llbb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.funclets[bb] = Some(funclet);
|
self.funclets[bb] = Some(funclet);
|
||||||
ret_llbb
|
cleanup_bb
|
||||||
} else {
|
} else {
|
||||||
let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
|
let cleanup_llbb = Bx::append_block(self.cx, self.llfn, "cleanup");
|
||||||
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
let mut cleanup_bx = Bx::build(self.cx, cleanup_llbb);
|
||||||
|
@ -1618,26 +1585,68 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn double_unwind_guard(&mut self) -> Bx::BasicBlock {
|
fn terminate_block(&mut self) -> Bx::BasicBlock {
|
||||||
self.double_unwind_guard.unwrap_or_else(|| {
|
self.terminate_block.unwrap_or_else(|| {
|
||||||
assert!(!base::wants_msvc_seh(self.cx.sess()));
|
let funclet;
|
||||||
|
let llbb;
|
||||||
|
let mut bx;
|
||||||
|
if base::wants_msvc_seh(self.cx.sess()) {
|
||||||
|
// This is a basic block that we're aborting the program for,
|
||||||
|
// notably in an `extern` function. These basic blocks are inserted
|
||||||
|
// so that we assert that `extern` functions do indeed not panic,
|
||||||
|
// and if they do we abort the process.
|
||||||
|
//
|
||||||
|
// On MSVC these are tricky though (where we're doing funclets). If
|
||||||
|
// we were to do a cleanuppad (like below) the normal functions like
|
||||||
|
// `longjmp` would trigger the abort logic, terminating the
|
||||||
|
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||||
|
// which magically doesn't trigger when `longjmp` files over this
|
||||||
|
// frame.
|
||||||
|
//
|
||||||
|
// Lots more discussion can be found on #48251 but this codegen is
|
||||||
|
// modeled after clang's for:
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// foo();
|
||||||
|
// } catch (...) {
|
||||||
|
// bar();
|
||||||
|
// }
|
||||||
|
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||||
|
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||||
|
|
||||||
|
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||||
|
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||||
|
|
||||||
|
// The "null" here is actually a RTTI type descriptor for the
|
||||||
|
// C++ personality function, but `catch (...)` has no type so
|
||||||
|
// it's null. The 64 here is actually a bitfield which
|
||||||
|
// represents that this is a catch-all block.
|
||||||
|
bx = Bx::build(self.cx, cp_llbb);
|
||||||
|
let null =
|
||||||
|
bx.const_null(bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space));
|
||||||
|
let sixty_four = bx.const_i32(64);
|
||||||
|
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
|
||||||
|
} else {
|
||||||
|
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||||
|
bx = Bx::build(self.cx, llbb);
|
||||||
|
|
||||||
|
let llpersonality = self.cx.eh_personality();
|
||||||
|
bx.cleanup_landing_pad(llpersonality);
|
||||||
|
|
||||||
|
funclet = None;
|
||||||
|
}
|
||||||
|
|
||||||
let llbb = Bx::append_block(self.cx, self.llfn, "abort");
|
|
||||||
let mut bx = Bx::build(self.cx, llbb);
|
|
||||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||||
|
|
||||||
let llpersonality = self.cx.eh_personality();
|
|
||||||
bx.cleanup_landing_pad(llpersonality);
|
|
||||||
|
|
||||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
|
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
|
||||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||||
|
|
||||||
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], None);
|
let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||||
bx.do_not_inline(llret);
|
bx.do_not_inline(llret);
|
||||||
|
|
||||||
bx.unreachable();
|
bx.unreachable();
|
||||||
|
|
||||||
self.double_unwind_guard = Some(llbb);
|
self.terminate_block = Some(llbb);
|
||||||
llbb
|
llbb
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||||
/// Cached unreachable block
|
/// Cached unreachable block
|
||||||
unreachable_block: Option<Bx::BasicBlock>,
|
unreachable_block: Option<Bx::BasicBlock>,
|
||||||
|
|
||||||
/// Cached double unwind guarding block
|
/// Cached terminate upon unwinding block
|
||||||
double_unwind_guard: Option<Bx::BasicBlock>,
|
terminate_block: Option<Bx::BasicBlock>,
|
||||||
|
|
||||||
/// The location where each MIR arg/var/tmp/ret is stored. This is
|
/// The location where each MIR arg/var/tmp/ret is stored. This is
|
||||||
/// usually an `PlaceRef` representing an alloca, but not always:
|
/// usually an `PlaceRef` representing an alloca, but not always:
|
||||||
|
@ -166,7 +166,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
let start_llbb = Bx::append_block(cx, llfn, "start");
|
let start_llbb = Bx::append_block(cx, llfn, "start");
|
||||||
let mut start_bx = Bx::build(cx, start_llbb);
|
let mut start_bx = Bx::build(cx, start_llbb);
|
||||||
|
|
||||||
if mir.basic_blocks.iter().any(|bb| bb.is_cleanup) {
|
if mir.basic_blocks.iter().any(|bb| {
|
||||||
|
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
|
||||||
|
}) {
|
||||||
start_bx.set_personality_fn(cx.eh_personality());
|
start_bx.set_personality_fn(cx.eh_personality());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
personality_slot: None,
|
personality_slot: None,
|
||||||
cached_llbbs,
|
cached_llbbs,
|
||||||
unreachable_block: None,
|
unreachable_block: None,
|
||||||
double_unwind_guard: None,
|
terminate_block: None,
|
||||||
cleanup_kinds,
|
cleanup_kinds,
|
||||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||||
|
|
|
@ -23,7 +23,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
||||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
|
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::error::*;
|
use super::error::*;
|
||||||
|
@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
/* with_caller_location = */ false,
|
/* with_caller_location = */ false,
|
||||||
dest,
|
dest,
|
||||||
ret,
|
ret,
|
||||||
StackPopUnwind::NotAllowed,
|
mir::UnwindAction::Unreachable,
|
||||||
)?;
|
)?;
|
||||||
Ok(ControlFlow::Break(()))
|
Ok(ControlFlow::Break(()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -401,7 +401,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
args: &[OpTy<'tcx>],
|
args: &[OpTy<'tcx>],
|
||||||
dest: &PlaceTy<'tcx>,
|
dest: &PlaceTy<'tcx>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
_unwind: StackPopUnwind, // unwinding is not supported in consts
|
_unwind: mir::UnwindAction, // unwinding is not supported in consts
|
||||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
debug!("find_mir_or_eval_fn: {:?}", instance);
|
debug!("find_mir_or_eval_fn: {:?}", instance);
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
args: &[OpTy<'tcx>],
|
args: &[OpTy<'tcx>],
|
||||||
dest: &PlaceTy<'tcx, Self::Provenance>,
|
dest: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
// Shared intrinsics.
|
// Shared intrinsics.
|
||||||
if ecx.emulate_intrinsic(instance, args, dest, target)? {
|
if ecx.emulate_intrinsic(instance, args, dest, target)? {
|
||||||
|
@ -526,7 +526,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
msg: &AssertMessage<'tcx>,
|
msg: &AssertMessage<'tcx>,
|
||||||
_unwind: Option<mir::BasicBlock>,
|
_unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
use rustc_middle::mir::AssertKind::*;
|
use rustc_middle::mir::AssertKind::*;
|
||||||
// Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
|
// Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
|
||||||
|
|
|
@ -139,17 +139,6 @@ pub struct FrameInfo<'tcx> {
|
||||||
pub lint_root: Option<hir::HirId>,
|
pub lint_root: Option<hir::HirId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unwind information.
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
|
||||||
pub enum StackPopUnwind {
|
|
||||||
/// The cleanup block.
|
|
||||||
Cleanup(mir::BasicBlock),
|
|
||||||
/// No cleanup needs to be done.
|
|
||||||
Skip,
|
|
||||||
/// Unwinding is not allowed (UB).
|
|
||||||
NotAllowed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
|
||||||
pub enum StackPopCleanup {
|
pub enum StackPopCleanup {
|
||||||
/// Jump to the next block in the caller, or cause UB if None (that's a function
|
/// Jump to the next block in the caller, or cause UB if None (that's a function
|
||||||
|
@ -157,7 +146,7 @@ pub enum StackPopCleanup {
|
||||||
/// we can validate it at that layout.
|
/// we can validate it at that layout.
|
||||||
/// `ret` stores the block we jump to on a normal return, while `unwind`
|
/// `ret` stores the block we jump to on a normal return, while `unwind`
|
||||||
/// stores the block used for cleanup during unwinding.
|
/// stores the block used for cleanup during unwinding.
|
||||||
Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
|
Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
|
||||||
/// The root frame of the stack: nowhere else to jump to.
|
/// The root frame of the stack: nowhere else to jump to.
|
||||||
/// `cleanup` says whether locals are deallocated. Static computation
|
/// `cleanup` says whether locals are deallocated. Static computation
|
||||||
/// wants them leaked to intern what they need (and just throw away
|
/// wants them leaked to intern what they need (and just throw away
|
||||||
|
@ -735,18 +724,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
/// *Unwind* to the given `target` basic block.
|
/// *Unwind* to the given `target` basic block.
|
||||||
/// Do *not* use for returning! Use `return_to_block` instead.
|
/// Do *not* use for returning! Use `return_to_block` instead.
|
||||||
///
|
///
|
||||||
/// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
|
/// If `target` is `UnwindAction::Continue`, that indicates the function does not need cleanup
|
||||||
/// during unwinding, and we will just keep propagating that upwards.
|
/// during unwinding, and we will just keep propagating that upwards.
|
||||||
///
|
///
|
||||||
/// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
|
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
|
||||||
/// unwinding, and doing so is UB.
|
/// unwinding, and doing so is UB.
|
||||||
pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
|
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||||
self.frame_mut().loc = match target {
|
self.frame_mut().loc = match target {
|
||||||
StackPopUnwind::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||||
StackPopUnwind::Skip => Right(self.frame_mut().body.span),
|
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
|
||||||
StackPopUnwind::NotAllowed => {
|
mir::UnwindAction::Unreachable => {
|
||||||
throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
|
throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
|
||||||
}
|
}
|
||||||
|
mir::UnwindAction::Terminate => {
|
||||||
|
self.frame_mut().loc = Right(self.frame_mut().body.span);
|
||||||
|
M::abort(self, "panic in a function that cannot unwind".to_owned())?;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
|
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
|
||||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
|
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Data returned by Machine::stack_pop,
|
/// Data returned by Machine::stack_pop,
|
||||||
|
@ -185,7 +185,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
args: &[OpTy<'tcx, Self::Provenance>],
|
args: &[OpTy<'tcx, Self::Provenance>],
|
||||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
|
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
|
||||||
|
|
||||||
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
|
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
|
||||||
|
@ -197,7 +197,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
args: &[OpTy<'tcx, Self::Provenance>],
|
args: &[OpTy<'tcx, Self::Provenance>],
|
||||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx>;
|
) -> InterpResult<'tcx>;
|
||||||
|
|
||||||
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
|
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
|
||||||
|
@ -208,17 +208,17 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
args: &[OpTy<'tcx, Self::Provenance>],
|
args: &[OpTy<'tcx, Self::Provenance>],
|
||||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx>;
|
) -> InterpResult<'tcx>;
|
||||||
|
|
||||||
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
msg: &mir::AssertMessage<'tcx>,
|
msg: &mir::AssertMessage<'tcx>,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx>;
|
) -> InterpResult<'tcx>;
|
||||||
|
|
||||||
/// Called to evaluate `Abort` MIR terminator.
|
/// Called to abort evaluation.
|
||||||
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> {
|
fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: String) -> InterpResult<'tcx, !> {
|
||||||
throw_unsup_format!("aborting execution is not supported")
|
throw_unsup_format!("aborting execution is not supported")
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||||
_args: &[OpTy<$tcx>],
|
_args: &[OpTy<$tcx>],
|
||||||
_destination: &PlaceTy<$tcx, Self::Provenance>,
|
_destination: &PlaceTy<$tcx, Self::Provenance>,
|
||||||
_target: Option<mir::BasicBlock>,
|
_target: Option<mir::BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<$tcx> {
|
) -> InterpResult<$tcx> {
|
||||||
match fn_val {}
|
match fn_val {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,7 @@ mod visitor;
|
||||||
|
|
||||||
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
||||||
|
|
||||||
pub use self::eval_context::{
|
pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
|
||||||
Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
|
|
||||||
};
|
|
||||||
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
||||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||||
|
|
|
@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
|
FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
|
||||||
PlaceTy, Scalar, StackPopCleanup, StackPopUnwind,
|
PlaceTy, Scalar, StackPopCleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
|
@ -60,7 +60,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
ref args,
|
ref args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
ref cleanup,
|
unwind,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
|
@ -106,11 +106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
with_caller_location,
|
with_caller_location,
|
||||||
&destination,
|
&destination,
|
||||||
target,
|
target,
|
||||||
match (cleanup, fn_abi.can_unwind) {
|
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
|
||||||
(Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
|
|
||||||
(None, true) => StackPopUnwind::Skip,
|
|
||||||
(_, false) => StackPopUnwind::NotAllowed,
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
// Sanity-check that `eval_fn_call` either pushed a new frame or
|
// Sanity-check that `eval_fn_call` either pushed a new frame or
|
||||||
// did a jump to another block.
|
// did a jump to another block.
|
||||||
|
@ -137,19 +133,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.drop_in_place(&place, instance, target, unwind)?;
|
self.drop_in_place(&place, instance, target, unwind)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert { ref cond, expected, ref msg, target, cleanup } => {
|
Assert { ref cond, expected, ref msg, target, unwind } => {
|
||||||
let ignored =
|
let ignored =
|
||||||
M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
|
M::ignore_optional_overflow_checks(self) && msg.is_optional_overflow_check();
|
||||||
let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
|
let cond_val = self.read_scalar(&self.eval_operand(cond, None)?)?.to_bool()?;
|
||||||
if ignored || expected == cond_val {
|
if ignored || expected == cond_val {
|
||||||
self.go_to_block(target);
|
self.go_to_block(target);
|
||||||
} else {
|
} else {
|
||||||
M::assert_panic(self, msg, cleanup)?;
|
M::assert_panic(self, msg, unwind)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Abort => {
|
Terminate => {
|
||||||
M::abort(self, "the program aborted execution".to_owned())?;
|
// FIXME: maybe should call `panic_no_unwind` lang item instead.
|
||||||
|
M::abort(self, "panic in a function that cannot unwind".to_owned())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we encounter Resume, we've finished unwinding
|
// When we encounter Resume, we've finished unwinding
|
||||||
|
@ -351,7 +348,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
with_caller_location: bool,
|
with_caller_location: bool,
|
||||||
destination: &PlaceTy<'tcx, M::Provenance>,
|
destination: &PlaceTy<'tcx, M::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
mut unwind: StackPopUnwind,
|
mut unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("eval_fn_call: {:#?}", fn_val);
|
trace!("eval_fn_call: {:#?}", fn_val);
|
||||||
|
|
||||||
|
@ -410,9 +407,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
|
if !callee_fn_abi.can_unwind {
|
||||||
// The callee cannot unwind.
|
// The callee cannot unwind, so force the `Unreachable` unwind handling.
|
||||||
unwind = StackPopUnwind::NotAllowed;
|
unwind = mir::UnwindAction::Unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_stack_frame(
|
self.push_stack_frame(
|
||||||
|
@ -676,7 +673,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
place: &PlaceTy<'tcx, M::Provenance>,
|
place: &PlaceTy<'tcx, M::Provenance>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
target: mir::BasicBlock,
|
target: mir::BasicBlock,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
|
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
|
||||||
// We take the address of the object. This may well be unaligned, which is fine
|
// We take the address of the object. This may well be unaligned, which is fine
|
||||||
|
@ -717,10 +714,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
false,
|
false,
|
||||||
&ret.into(),
|
&ret.into(),
|
||||||
Some(target),
|
Some(target),
|
||||||
match unwind {
|
unwind,
|
||||||
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
|
||||||
None => StackPopUnwind::Skip,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1031,9 +1031,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||||
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
|
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Abort => {
|
TerminatorKind::Terminate => {
|
||||||
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
|
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
|
||||||
span_bug!(self.span, "`Abort` terminator outside of cleanup block")
|
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Assert { .. }
|
TerminatorKind::Assert { .. }
|
||||||
|
|
|
@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::Abort
|
mir::TerminatorKind::Terminate
|
||||||
| mir::TerminatorKind::Call { .. }
|
| mir::TerminatorKind::Call { .. }
|
||||||
| mir::TerminatorKind::Assert { .. }
|
| mir::TerminatorKind::Assert { .. }
|
||||||
| mir::TerminatorKind::FalseEdge { .. }
|
| mir::TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -807,7 +807,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||||
kind: TerminatorKind::Call {
|
kind: TerminatorKind::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
destination: Place::from(new_temp),
|
destination: Place::from(new_temp),
|
||||||
target: Some(new_target),
|
target: Some(new_target),
|
||||||
from_hir_call,
|
from_hir_call,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rustc_middle::mir::{
|
||||||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||||
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
|
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
|
||||||
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
|
||||||
TerminatorKind, UnOp, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
|
TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||||
|
@ -232,6 +232,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_unwind_edge(&mut self, location: Location, unwind: UnwindAction) {
|
||||||
|
let is_cleanup = self.body.basic_blocks[location.block].is_cleanup;
|
||||||
|
match unwind {
|
||||||
|
UnwindAction::Cleanup(unwind) => {
|
||||||
|
if is_cleanup {
|
||||||
|
self.fail(location, "unwind on cleanup block");
|
||||||
|
}
|
||||||
|
self.check_edge(location, unwind, EdgeKind::Unwind);
|
||||||
|
}
|
||||||
|
UnwindAction::Continue => {
|
||||||
|
if is_cleanup {
|
||||||
|
self.fail(location, "unwind on cleanup block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if src can be assigned into dest.
|
/// Check if src can be assigned into dest.
|
||||||
/// This is not precise, it will accept some incorrect assignments.
|
/// This is not precise, it will accept some incorrect assignments.
|
||||||
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
|
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
|
||||||
|
@ -902,11 +920,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
TerminatorKind::Drop { target, unwind, .. } => {
|
TerminatorKind::Drop { target, unwind, .. } => {
|
||||||
self.check_edge(location, *target, EdgeKind::Normal);
|
self.check_edge(location, *target, EdgeKind::Normal);
|
||||||
if let Some(unwind) = unwind {
|
self.check_unwind_edge(location, *unwind);
|
||||||
self.check_edge(location, *unwind, EdgeKind::Unwind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
|
TerminatorKind::Call { func, args, destination, target, unwind, .. } => {
|
||||||
let func_ty = func.ty(&self.body.local_decls, self.tcx);
|
let func_ty = func.ty(&self.body.local_decls, self.tcx);
|
||||||
match func_ty.kind() {
|
match func_ty.kind() {
|
||||||
ty::FnPtr(..) | ty::FnDef(..) => {}
|
ty::FnPtr(..) | ty::FnDef(..) => {}
|
||||||
|
@ -918,9 +934,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
self.check_edge(location, *target, EdgeKind::Normal);
|
self.check_edge(location, *target, EdgeKind::Normal);
|
||||||
}
|
}
|
||||||
if let Some(cleanup) = cleanup {
|
self.check_unwind_edge(location, *unwind);
|
||||||
self.check_edge(location, *cleanup, EdgeKind::Unwind);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The call destination place and Operand::Move place used as an argument might be
|
// The call destination place and Operand::Move place used as an argument might be
|
||||||
// passed by a reference to the callee. Consequently they must be non-overlapping.
|
// passed by a reference to the callee. Consequently they must be non-overlapping.
|
||||||
|
@ -946,7 +960,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cond, target, cleanup, .. } => {
|
TerminatorKind::Assert { cond, target, unwind, .. } => {
|
||||||
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
|
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
|
||||||
if cond_ty != self.tcx.types.bool {
|
if cond_ty != self.tcx.types.bool {
|
||||||
self.fail(
|
self.fail(
|
||||||
|
@ -958,9 +972,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.check_edge(location, *target, EdgeKind::Normal);
|
self.check_edge(location, *target, EdgeKind::Normal);
|
||||||
if let Some(cleanup) = cleanup {
|
self.check_unwind_edge(location, *unwind);
|
||||||
self.check_edge(location, *cleanup, EdgeKind::Unwind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::Yield { resume, drop, .. } => {
|
TerminatorKind::Yield { resume, drop, .. } => {
|
||||||
if self.body.generator.is_none() {
|
if self.body.generator.is_none() {
|
||||||
|
@ -992,17 +1004,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.check_edge(location, *real_target, EdgeKind::Normal);
|
self.check_edge(location, *real_target, EdgeKind::Normal);
|
||||||
if let Some(unwind) = unwind {
|
self.check_unwind_edge(location, *unwind);
|
||||||
self.check_edge(location, *unwind, EdgeKind::Unwind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { destination, cleanup, .. } => {
|
TerminatorKind::InlineAsm { destination, unwind, .. } => {
|
||||||
if let Some(destination) = destination {
|
if let Some(destination) = destination {
|
||||||
self.check_edge(location, *destination, EdgeKind::Normal);
|
self.check_edge(location, *destination, EdgeKind::Normal);
|
||||||
}
|
}
|
||||||
if let Some(cleanup) = cleanup {
|
self.check_unwind_edge(location, *unwind);
|
||||||
self.check_edge(location, *cleanup, EdgeKind::Unwind);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TerminatorKind::GeneratorDrop => {
|
TerminatorKind::GeneratorDrop => {
|
||||||
if self.body.generator.is_none() {
|
if self.body.generator.is_none() {
|
||||||
|
@ -1015,10 +1023,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Resume | TerminatorKind::Abort => {
|
TerminatorKind::Resume | TerminatorKind::Terminate => {
|
||||||
let bb = location.block;
|
let bb = location.block;
|
||||||
if !self.body.basic_blocks[bb].is_cleanup {
|
if !self.body.basic_blocks[bb].is_cleanup {
|
||||||
self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
|
self.fail(
|
||||||
|
location,
|
||||||
|
"Cannot `Resume` or `Terminate` from non-cleanup basic block",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
|
|
|
@ -12,6 +12,9 @@ pub struct MirPatch<'tcx> {
|
||||||
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
||||||
new_locals: Vec<LocalDecl<'tcx>>,
|
new_locals: Vec<LocalDecl<'tcx>>,
|
||||||
resume_block: Option<BasicBlock>,
|
resume_block: Option<BasicBlock>,
|
||||||
|
// Only for unreachable in cleanup path.
|
||||||
|
unreachable_cleanup_block: Option<BasicBlock>,
|
||||||
|
terminate_block: Option<BasicBlock>,
|
||||||
body_span: Span,
|
body_span: Span,
|
||||||
next_local: usize,
|
next_local: usize,
|
||||||
}
|
}
|
||||||
|
@ -25,14 +28,31 @@ impl<'tcx> MirPatch<'tcx> {
|
||||||
new_locals: vec![],
|
new_locals: vec![],
|
||||||
next_local: body.local_decls.len(),
|
next_local: body.local_decls.len(),
|
||||||
resume_block: None,
|
resume_block: None,
|
||||||
|
unreachable_cleanup_block: None,
|
||||||
|
terminate_block: None,
|
||||||
body_span: body.span,
|
body_span: body.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if we already have a resume block
|
|
||||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||||
|
// Check if we already have a resume block
|
||||||
if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
|
if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
|
||||||
result.resume_block = Some(bb);
|
result.resume_block = Some(bb);
|
||||||
break;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we already have an unreachable block
|
||||||
|
if let TerminatorKind::Unreachable = block.terminator().kind
|
||||||
|
&& block.statements.is_empty()
|
||||||
|
&& block.is_cleanup
|
||||||
|
{
|
||||||
|
result.unreachable_cleanup_block = Some(bb);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we already have a terminate block
|
||||||
|
if let TerminatorKind::Terminate = block.terminator().kind && block.statements.is_empty() {
|
||||||
|
result.terminate_block = Some(bb);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +76,40 @@ impl<'tcx> MirPatch<'tcx> {
|
||||||
bb
|
bb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unreachable_cleanup_block(&mut self) -> BasicBlock {
|
||||||
|
if let Some(bb) = self.unreachable_cleanup_block {
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bb = self.new_block(BasicBlockData {
|
||||||
|
statements: vec![],
|
||||||
|
terminator: Some(Terminator {
|
||||||
|
source_info: SourceInfo::outermost(self.body_span),
|
||||||
|
kind: TerminatorKind::Unreachable,
|
||||||
|
}),
|
||||||
|
is_cleanup: true,
|
||||||
|
});
|
||||||
|
self.unreachable_cleanup_block = Some(bb);
|
||||||
|
bb
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate_block(&mut self) -> BasicBlock {
|
||||||
|
if let Some(bb) = self.terminate_block {
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bb = self.new_block(BasicBlockData {
|
||||||
|
statements: vec![],
|
||||||
|
terminator: Some(Terminator {
|
||||||
|
source_info: SourceInfo::outermost(self.body_span),
|
||||||
|
kind: TerminatorKind::Terminate,
|
||||||
|
}),
|
||||||
|
is_cleanup: true,
|
||||||
|
});
|
||||||
|
self.terminate_block = Some(bb);
|
||||||
|
bb
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_patched(&self, bb: BasicBlock) -> bool {
|
pub fn is_patched(&self, bb: BasicBlock) -> bool {
|
||||||
self.patch_map[bb].is_some()
|
self.patch_map[bb].is_some()
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
|
||||||
Goto { .. } => "Goto",
|
Goto { .. } => "Goto",
|
||||||
SwitchInt { .. } => "SwitchInt",
|
SwitchInt { .. } => "SwitchInt",
|
||||||
Resume => "Resume",
|
Resume => "Resume",
|
||||||
Abort => "Abort",
|
Terminate => "Terminate",
|
||||||
Return => "Return",
|
Return => "Return",
|
||||||
Unreachable => "Unreachable",
|
Unreachable => "Unreachable",
|
||||||
Drop { .. } => "Drop",
|
Drop { .. } => "Drop",
|
||||||
|
|
|
@ -515,15 +515,15 @@ pub struct CopyNonOverlapping<'tcx> {
|
||||||
///
|
///
|
||||||
/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
|
/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
|
||||||
/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
|
/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
|
||||||
/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
|
/// terminators have a `unwind: UnwindAction` field on them. If stack unwinding occurs, then
|
||||||
/// once the current function is reached, execution continues at the given basic block, if any. If
|
/// once the current function is reached, an action will be taken based on the `unwind` field.
|
||||||
/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
|
/// If the action is `Cleanup`, then the execution continues at the given basic block. If the
|
||||||
/// equivalent to the execution of a `Resume` terminator.
|
/// action is `Continue` then no cleanup is performed, and the stack continues unwinding.
|
||||||
///
|
///
|
||||||
/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
|
/// The basic block pointed to by a `Cleanup` unwind action must have its `cleanup` flag set.
|
||||||
/// basic blocks have a couple restrictions:
|
/// `cleanup` basic blocks have a couple restrictions:
|
||||||
/// 1. All `cleanup` fields in them must be `None`.
|
/// 1. All `unwind` fields in them must be `UnwindAction::Terminate` or `UnwindAction::Unreachable`.
|
||||||
/// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
|
/// 2. `Return` terminators are not allowed in them. `Terminate` and `Resume` terminators are.
|
||||||
/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
|
/// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
|
||||||
/// must also be `cleanup`. This is a part of the type system and checked statically, so it is
|
/// must also be `cleanup`. This is a part of the type system and checked statically, so it is
|
||||||
/// still an error to have such an edge in the CFG even if it's known that it won't be taken at
|
/// still an error to have such an edge in the CFG even if it's known that it won't be taken at
|
||||||
|
@ -565,11 +565,11 @@ pub enum TerminatorKind<'tcx> {
|
||||||
/// deaggregation runs.
|
/// deaggregation runs.
|
||||||
Resume,
|
Resume,
|
||||||
|
|
||||||
/// Indicates that the landing pad is finished and that the process should abort.
|
/// Indicates that the landing pad is finished and that the process should terminate.
|
||||||
///
|
///
|
||||||
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
|
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
|
||||||
/// cleanup blocks.
|
/// cleanup blocks.
|
||||||
Abort,
|
Terminate,
|
||||||
|
|
||||||
/// Returns from the function.
|
/// Returns from the function.
|
||||||
///
|
///
|
||||||
|
@ -604,7 +604,7 @@ pub enum TerminatorKind<'tcx> {
|
||||||
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
|
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
|
||||||
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
|
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
|
||||||
/// > consider indirect assignments.
|
/// > consider indirect assignments.
|
||||||
Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
|
Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
|
||||||
|
|
||||||
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
|
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
|
||||||
/// the referred to function. The operand types must match the argument types of the function.
|
/// the referred to function. The operand types must match the argument types of the function.
|
||||||
|
@ -628,8 +628,8 @@ pub enum TerminatorKind<'tcx> {
|
||||||
destination: Place<'tcx>,
|
destination: Place<'tcx>,
|
||||||
/// Where to go after this call returns. If none, the call necessarily diverges.
|
/// Where to go after this call returns. If none, the call necessarily diverges.
|
||||||
target: Option<BasicBlock>,
|
target: Option<BasicBlock>,
|
||||||
/// Cleanups to be done if the call unwinds.
|
/// Action to be taken if the call unwinds.
|
||||||
cleanup: Option<BasicBlock>,
|
unwind: UnwindAction,
|
||||||
/// `true` if this is from a call in HIR rather than from an overloaded
|
/// `true` if this is from a call in HIR rather than from an overloaded
|
||||||
/// operator. True for overloaded function call.
|
/// operator. True for overloaded function call.
|
||||||
from_hir_call: bool,
|
from_hir_call: bool,
|
||||||
|
@ -654,7 +654,7 @@ pub enum TerminatorKind<'tcx> {
|
||||||
expected: bool,
|
expected: bool,
|
||||||
msg: AssertMessage<'tcx>,
|
msg: AssertMessage<'tcx>,
|
||||||
target: BasicBlock,
|
target: BasicBlock,
|
||||||
cleanup: Option<BasicBlock>,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Marks a suspend point.
|
/// Marks a suspend point.
|
||||||
|
@ -720,9 +720,8 @@ pub enum TerminatorKind<'tcx> {
|
||||||
/// in practice, but in order to avoid fragility we want to always
|
/// in practice, but in order to avoid fragility we want to always
|
||||||
/// consider it in borrowck. We don't want to accept programs which
|
/// consider it in borrowck. We don't want to accept programs which
|
||||||
/// pass borrowck only when `panic=abort` or some assertions are disabled
|
/// pass borrowck only when `panic=abort` or some assertions are disabled
|
||||||
/// due to release vs. debug mode builds. This needs to be an `Option` because
|
/// due to release vs. debug mode builds.
|
||||||
/// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
|
unwind: UnwindAction,
|
||||||
unwind: Option<BasicBlock>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Block ends with an inline assembly block. This is a terminator since
|
/// Block ends with an inline assembly block. This is a terminator since
|
||||||
|
@ -745,12 +744,31 @@ pub enum TerminatorKind<'tcx> {
|
||||||
/// diverging (InlineAsmOptions::NORETURN).
|
/// diverging (InlineAsmOptions::NORETURN).
|
||||||
destination: Option<BasicBlock>,
|
destination: Option<BasicBlock>,
|
||||||
|
|
||||||
/// Cleanup to be done if the inline assembly unwinds. This is present
|
/// Action to be taken if the inline assembly unwinds. This is present
|
||||||
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
|
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
|
||||||
cleanup: Option<BasicBlock>,
|
unwind: UnwindAction,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Action to be taken when a stack unwind happens.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||||
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
|
pub enum UnwindAction {
|
||||||
|
/// No action is to be taken. Continue unwinding.
|
||||||
|
///
|
||||||
|
/// This is similar to `Cleanup(bb)` where `bb` does nothing but `Resume`, but they are not
|
||||||
|
/// equivalent, as presence of `Cleanup(_)` will make a frame non-POF.
|
||||||
|
Continue,
|
||||||
|
/// Triggers undefined behavior if unwind happens.
|
||||||
|
Unreachable,
|
||||||
|
/// Terminates the execution if unwind happens.
|
||||||
|
///
|
||||||
|
/// Depending on the platform and situation this may cause a non-unwindable panic or abort.
|
||||||
|
Terminate,
|
||||||
|
/// Cleanups to be done.
|
||||||
|
Cleanup(BasicBlock),
|
||||||
|
}
|
||||||
|
|
||||||
/// Information about an assertion failure.
|
/// Information about an assertion failure.
|
||||||
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)]
|
||||||
pub enum AssertKind<O> {
|
pub enum AssertKind<O> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind};
|
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
|
||||||
use rustc_ast::InlineAsmTemplatePiece;
|
use rustc_ast::InlineAsmTemplatePiece;
|
||||||
pub use rustc_ast::Mutability;
|
pub use rustc_ast::Mutability;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
@ -118,11 +118,11 @@ impl<'tcx> Terminator<'tcx> {
|
||||||
self.kind.successors_mut()
|
self.kind.successors_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
pub fn unwind(&self) -> Option<&UnwindAction> {
|
||||||
self.kind.unwind()
|
self.kind.unwind()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
|
||||||
self.kind.unwind_mut()
|
self.kind.unwind_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,34 +135,34 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
pub fn successors(&self) -> Successors<'_> {
|
pub fn successors(&self) -> Successors<'_> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
|
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| Yield { resume: t, drop: Some(ref u), .. }
|
||||||
|
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) }
|
||||||
|
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
|
||||||
|
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
||||||
|
}
|
||||||
|
Goto { target: t }
|
||||||
|
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
|
| Call { target: Some(t), unwind: _, .. }
|
||||||
|
| Yield { resume: t, drop: None, .. }
|
||||||
|
| Drop { target: t, unwind: _, .. }
|
||||||
|
| Assert { target: t, unwind: _, .. }
|
||||||
|
| FalseUnwind { real_target: t, unwind: _ }
|
||||||
|
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
|
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
||||||
|
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||||
|
}
|
||||||
Resume
|
Resume
|
||||||
| Abort
|
| Terminate
|
||||||
| GeneratorDrop
|
| GeneratorDrop
|
||||||
| Return
|
| Return
|
||||||
| Unreachable
|
| Unreachable
|
||||||
| Call { target: None, cleanup: None, .. }
|
| Call { target: None, unwind: _, .. }
|
||||||
| InlineAsm { destination: None, cleanup: None, .. } => {
|
| InlineAsm { destination: None, unwind: _, .. } => {
|
||||||
None.into_iter().chain((&[]).into_iter().copied())
|
None.into_iter().chain((&[]).into_iter().copied())
|
||||||
}
|
}
|
||||||
Goto { target: t }
|
|
||||||
| Call { target: None, cleanup: Some(t), .. }
|
|
||||||
| Call { target: Some(t), cleanup: None, .. }
|
|
||||||
| Yield { resume: t, drop: None, .. }
|
|
||||||
| Drop { target: t, unwind: None, .. }
|
|
||||||
| Assert { target: t, cleanup: None, .. }
|
|
||||||
| FalseUnwind { real_target: t, unwind: None }
|
|
||||||
| InlineAsm { destination: Some(t), cleanup: None, .. }
|
|
||||||
| InlineAsm { destination: None, cleanup: Some(t), .. } => {
|
|
||||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
|
||||||
}
|
|
||||||
Call { target: Some(t), cleanup: Some(ref u), .. }
|
|
||||||
| Yield { resume: t, drop: Some(ref u), .. }
|
|
||||||
| Drop { target: t, unwind: Some(ref u), .. }
|
|
||||||
| Assert { target: t, cleanup: Some(ref u), .. }
|
|
||||||
| FalseUnwind { real_target: t, unwind: Some(ref u) }
|
|
||||||
| InlineAsm { destination: Some(t), cleanup: Some(ref u), .. } => {
|
|
||||||
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
|
||||||
}
|
|
||||||
SwitchInt { ref targets, .. } => {
|
SwitchInt { ref targets, .. } => {
|
||||||
None.into_iter().chain(targets.targets.iter().copied())
|
None.into_iter().chain(targets.targets.iter().copied())
|
||||||
}
|
}
|
||||||
|
@ -175,32 +175,34 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
|
pub fn successors_mut(&mut self) -> SuccessorsMut<'_> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
|
Call { target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||||
|
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
||||||
|
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||||
|
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||||
|
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) }
|
||||||
|
| InlineAsm {
|
||||||
|
destination: Some(ref mut t),
|
||||||
|
unwind: UnwindAction::Cleanup(ref mut u),
|
||||||
|
..
|
||||||
|
} => Some(t).into_iter().chain(slice::from_mut(u)),
|
||||||
|
Goto { target: ref mut t }
|
||||||
|
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
||||||
|
| Call { target: Some(ref mut t), unwind: _, .. }
|
||||||
|
| Yield { resume: ref mut t, drop: None, .. }
|
||||||
|
| Drop { target: ref mut t, unwind: _, .. }
|
||||||
|
| Assert { target: ref mut t, unwind: _, .. }
|
||||||
|
| FalseUnwind { real_target: ref mut t, unwind: _ }
|
||||||
|
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
||||||
|
| InlineAsm { destination: Some(ref mut t), unwind: _, .. } => {
|
||||||
|
Some(t).into_iter().chain(&mut [])
|
||||||
|
}
|
||||||
Resume
|
Resume
|
||||||
| Abort
|
| Terminate
|
||||||
| GeneratorDrop
|
| GeneratorDrop
|
||||||
| Return
|
| Return
|
||||||
| Unreachable
|
| Unreachable
|
||||||
| Call { target: None, cleanup: None, .. }
|
| Call { target: None, unwind: _, .. }
|
||||||
| InlineAsm { destination: None, cleanup: None, .. } => None.into_iter().chain(&mut []),
|
| InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []),
|
||||||
Goto { target: ref mut t }
|
|
||||||
| Call { target: None, cleanup: Some(ref mut t), .. }
|
|
||||||
| Call { target: Some(ref mut t), cleanup: None, .. }
|
|
||||||
| Yield { resume: ref mut t, drop: None, .. }
|
|
||||||
| Drop { target: ref mut t, unwind: None, .. }
|
|
||||||
| Assert { target: ref mut t, cleanup: None, .. }
|
|
||||||
| FalseUnwind { real_target: ref mut t, unwind: None }
|
|
||||||
| InlineAsm { destination: Some(ref mut t), cleanup: None, .. }
|
|
||||||
| InlineAsm { destination: None, cleanup: Some(ref mut t), .. } => {
|
|
||||||
Some(t).into_iter().chain(&mut [])
|
|
||||||
}
|
|
||||||
Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
|
|
||||||
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
|
||||||
| Drop { target: ref mut t, unwind: Some(ref mut u), .. }
|
|
||||||
| Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
|
|
||||||
| FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
|
|
||||||
| InlineAsm { destination: Some(ref mut t), cleanup: Some(ref mut u), .. } => {
|
|
||||||
Some(t).into_iter().chain(slice::from_mut(u))
|
|
||||||
}
|
|
||||||
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
|
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
|
||||||
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||||
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
|
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
|
||||||
|
@ -208,41 +210,41 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwind(&self) -> Option<&Option<BasicBlock>> {
|
pub fn unwind(&self) -> Option<&UnwindAction> {
|
||||||
match *self {
|
match *self {
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::FalseEdge { .. } => None,
|
| TerminatorKind::FalseEdge { .. } => None,
|
||||||
TerminatorKind::Call { cleanup: ref unwind, .. }
|
TerminatorKind::Call { ref unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: ref unwind, .. }
|
| TerminatorKind::Assert { ref unwind, .. }
|
||||||
| TerminatorKind::Drop { ref unwind, .. }
|
| TerminatorKind::Drop { ref unwind, .. }
|
||||||
| TerminatorKind::FalseUnwind { ref unwind, .. }
|
| TerminatorKind::FalseUnwind { ref unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
|
| TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
|
pub fn unwind_mut(&mut self) -> Option<&mut UnwindAction> {
|
||||||
match *self {
|
match *self {
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::FalseEdge { .. } => None,
|
| TerminatorKind::FalseEdge { .. } => None,
|
||||||
TerminatorKind::Call { cleanup: ref mut unwind, .. }
|
TerminatorKind::Call { ref mut unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: ref mut unwind, .. }
|
| TerminatorKind::Assert { ref mut unwind, .. }
|
||||||
| TerminatorKind::Drop { ref mut unwind, .. }
|
| TerminatorKind::Drop { ref mut unwind, .. }
|
||||||
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
|
| TerminatorKind::FalseUnwind { ref mut unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
|
| TerminatorKind::InlineAsm { ref mut unwind, .. } => Some(unwind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,11 +270,17 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||||
let labels = self.fmt_successor_labels();
|
let labels = self.fmt_successor_labels();
|
||||||
assert_eq!(successor_count, labels.len());
|
assert_eq!(successor_count, labels.len());
|
||||||
|
|
||||||
match successor_count {
|
let unwind = match self.unwind() {
|
||||||
0 => Ok(()),
|
// Not needed or included in successors
|
||||||
|
None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None,
|
||||||
1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
|
||||||
|
Some(UnwindAction::Terminate) => Some("unwind terminate"),
|
||||||
|
};
|
||||||
|
|
||||||
|
match (successor_count, unwind) {
|
||||||
|
(0, None) => Ok(()),
|
||||||
|
(0, Some(unwind)) => write!(fmt, " -> {}", unwind),
|
||||||
|
(1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
||||||
_ => {
|
_ => {
|
||||||
write!(fmt, " -> [")?;
|
write!(fmt, " -> [")?;
|
||||||
for (i, target) in self.successors().enumerate() {
|
for (i, target) in self.successors().enumerate() {
|
||||||
|
@ -281,6 +289,9 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||||
}
|
}
|
||||||
write!(fmt, "{}: {:?}", labels[i], target)?;
|
write!(fmt, "{}: {:?}", labels[i], target)?;
|
||||||
}
|
}
|
||||||
|
if let Some(unwind) = unwind {
|
||||||
|
write!(fmt, ", {unwind}")?;
|
||||||
|
}
|
||||||
write!(fmt, "]")
|
write!(fmt, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +310,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
Return => write!(fmt, "return"),
|
Return => write!(fmt, "return"),
|
||||||
GeneratorDrop => write!(fmt, "generator_drop"),
|
GeneratorDrop => write!(fmt, "generator_drop"),
|
||||||
Resume => write!(fmt, "resume"),
|
Resume => write!(fmt, "resume"),
|
||||||
Abort => write!(fmt, "abort"),
|
Terminate => write!(fmt, "abort"),
|
||||||
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
|
Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
|
||||||
Unreachable => write!(fmt, "unreachable"),
|
Unreachable => write!(fmt, "unreachable"),
|
||||||
Drop { place, .. } => write!(fmt, "drop({:?})", place),
|
Drop { place, .. } => write!(fmt, "drop({:?})", place),
|
||||||
|
@ -378,7 +389,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
|
Return | Resume | Terminate | Unreachable | GeneratorDrop => vec![],
|
||||||
Goto { .. } => vec!["".into()],
|
Goto { .. } => vec!["".into()],
|
||||||
SwitchInt { ref targets, .. } => targets
|
SwitchInt { ref targets, .. } => targets
|
||||||
.values
|
.values
|
||||||
|
@ -386,31 +397,35 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||||
.map(|&u| Cow::Owned(u.to_string()))
|
.map(|&u| Cow::Owned(u.to_string()))
|
||||||
.chain(iter::once("otherwise".into()))
|
.chain(iter::once("otherwise".into()))
|
||||||
.collect(),
|
.collect(),
|
||||||
Call { target: Some(_), cleanup: Some(_), .. } => {
|
Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
vec!["return".into(), "unwind".into()]
|
vec!["return".into(), "unwind".into()]
|
||||||
}
|
}
|
||||||
Call { target: Some(_), cleanup: None, .. } => vec!["return".into()],
|
Call { target: Some(_), unwind: _, .. } => vec!["return".into()],
|
||||||
Call { target: None, cleanup: Some(_), .. } => vec!["unwind".into()],
|
Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
|
||||||
Call { target: None, cleanup: None, .. } => vec![],
|
Call { target: None, unwind: _, .. } => vec![],
|
||||||
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
|
Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
|
||||||
Yield { drop: None, .. } => vec!["resume".into()],
|
Yield { drop: None, .. } => vec!["resume".into()],
|
||||||
Drop { unwind: None, .. } => {
|
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
|
||||||
|
Drop { unwind: _, .. } => vec!["return".into()],
|
||||||
|
Assert { unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
|
vec!["success".into(), "unwind".into()]
|
||||||
|
}
|
||||||
|
Assert { unwind: _, .. } => vec!["success".into()],
|
||||||
|
FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
|
||||||
|
FalseUnwind { unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
|
vec!["real".into(), "unwind".into()]
|
||||||
|
}
|
||||||
|
FalseUnwind { unwind: _, .. } => vec!["real".into()],
|
||||||
|
InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
|
vec!["return".into(), "unwind".into()]
|
||||||
|
}
|
||||||
|
InlineAsm { destination: Some(_), unwind: _, .. } => {
|
||||||
vec!["return".into()]
|
vec!["return".into()]
|
||||||
}
|
}
|
||||||
Drop { unwind: Some(_), .. } => {
|
InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
vec!["return".into(), "unwind".into()]
|
vec!["unwind".into()]
|
||||||
}
|
}
|
||||||
Assert { cleanup: None, .. } => vec!["".into()],
|
InlineAsm { destination: None, unwind: _, .. } => vec![],
|
||||||
Assert { .. } => vec!["success".into(), "unwind".into()],
|
|
||||||
FalseEdge { .. } => vec!["real".into(), "imaginary".into()],
|
|
||||||
FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()],
|
|
||||||
FalseUnwind { unwind: None, .. } => vec!["real".into()],
|
|
||||||
InlineAsm { destination: Some(_), cleanup: Some(_), .. } => {
|
|
||||||
vec!["return".into(), "unwind".into()]
|
|
||||||
}
|
|
||||||
InlineAsm { destination: Some(_), cleanup: None, .. } => vec!["return".into()],
|
|
||||||
InlineAsm { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()],
|
|
||||||
InlineAsm { destination: None, cleanup: None, .. } => vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,7 +462,7 @@ macro_rules! make_mir_visitor {
|
||||||
match kind {
|
match kind {
|
||||||
TerminatorKind::Goto { .. } |
|
TerminatorKind::Goto { .. } |
|
||||||
TerminatorKind::Resume |
|
TerminatorKind::Resume |
|
||||||
TerminatorKind::Abort |
|
TerminatorKind::Terminate |
|
||||||
TerminatorKind::GeneratorDrop |
|
TerminatorKind::GeneratorDrop |
|
||||||
TerminatorKind::Unreachable |
|
TerminatorKind::Unreachable |
|
||||||
TerminatorKind::FalseEdge { .. } |
|
TerminatorKind::FalseEdge { .. } |
|
||||||
|
@ -509,7 +509,7 @@ macro_rules! make_mir_visitor {
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _
|
fn_span: _
|
||||||
} => {
|
} => {
|
||||||
|
@ -529,7 +529,7 @@ macro_rules! make_mir_visitor {
|
||||||
expected: _,
|
expected: _,
|
||||||
msg,
|
msg,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.visit_operand(cond, location);
|
self.visit_operand(cond, location);
|
||||||
self.visit_assert_message(msg, location);
|
self.visit_assert_message(msg, location);
|
||||||
|
@ -555,7 +555,7 @@ macro_rules! make_mir_visitor {
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
match op {
|
match op {
|
||||||
|
|
|
@ -56,7 +56,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||||
Ok(TerminatorKind::Drop {
|
Ok(TerminatorKind::Drop {
|
||||||
place: self.parse_place(args[0])?,
|
place: self.parse_place(args[0])?,
|
||||||
target: self.parse_block(args[1])?,
|
target: self.parse_block(args[1])?,
|
||||||
unwind: None,
|
unwind: UnwindAction::Continue,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@call("mir_call", args) => {
|
@call("mir_call", args) => {
|
||||||
|
@ -126,7 +126,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: Some(target),
|
target: Some(target),
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: *from_hir_call,
|
from_hir_call: *from_hir_call,
|
||||||
fn_span: *fn_span,
|
fn_span: *fn_span,
|
||||||
})
|
})
|
||||||
|
|
|
@ -171,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
args: vec![Operand::Move(size), Operand::Move(align)],
|
args: vec![Operand::Move(size), Operand::Move(align)],
|
||||||
destination: storage,
|
destination: storage,
|
||||||
target: Some(success),
|
target: Some(success),
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: expr_span,
|
fn_span: expr_span,
|
||||||
},
|
},
|
||||||
|
@ -702,7 +702,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.cfg.terminate(
|
this.cfg.terminate(
|
||||||
block,
|
block,
|
||||||
outer_source_info,
|
outer_source_info,
|
||||||
TerminatorKind::Drop { place: to_drop, target: success, unwind: None },
|
TerminatorKind::Drop {
|
||||||
|
place: to_drop,
|
||||||
|
target: success,
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
this.diverge_from(block);
|
this.diverge_from(block);
|
||||||
block = success;
|
block = success;
|
||||||
|
|
|
@ -228,7 +228,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
this.cfg.terminate(
|
this.cfg.terminate(
|
||||||
loop_block,
|
loop_block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
|
TerminatorKind::FalseUnwind {
|
||||||
|
real_target: body_block,
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
this.diverge_from(loop_block);
|
this.diverge_from(loop_block);
|
||||||
|
|
||||||
|
@ -264,7 +267,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func: fun,
|
func: fun,
|
||||||
args,
|
args,
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
destination,
|
destination,
|
||||||
// The presence or absence of a return edge affects control-flow sensitive
|
// The presence or absence of a return edge affects control-flow sensitive
|
||||||
// MIR checks and ultimately whether code is accepted or not. We can only
|
// MIR checks and ultimately whether code is accepted or not. We can only
|
||||||
|
@ -466,7 +469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
Some(destination_block)
|
Some(destination_block)
|
||||||
},
|
},
|
||||||
cleanup: None,
|
unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||||
|
UnwindAction::Continue
|
||||||
|
} else {
|
||||||
|
UnwindAction::Unreachable
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||||
|
|
|
@ -263,7 +263,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
args: vec![Operand::Move(ref_string)],
|
args: vec![Operand::Move(ref_string)],
|
||||||
destination: ref_str,
|
destination: ref_str,
|
||||||
target: Some(eq_block),
|
target: Some(eq_block),
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: source_info.span
|
fn_span: source_info.span
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
args: vec![val, expect],
|
args: vec![val, expect],
|
||||||
destination: eq_result,
|
destination: eq_result,
|
||||||
target: Some(eq_block),
|
target: Some(eq_block),
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: source_info.span,
|
fn_span: source_info.span,
|
||||||
},
|
},
|
||||||
|
|
|
@ -369,7 +369,7 @@ impl DropTree {
|
||||||
let terminator = TerminatorKind::Drop {
|
let terminator = TerminatorKind::Drop {
|
||||||
target: blocks[drop_data.1].unwrap(),
|
target: blocks[drop_data.1].unwrap(),
|
||||||
// The caller will handle this if needed.
|
// The caller will handle this if needed.
|
||||||
unwind: None,
|
unwind: UnwindAction::Terminate,
|
||||||
place: drop_data.0.local.into(),
|
place: drop_data.0.local.into(),
|
||||||
};
|
};
|
||||||
cfg.terminate(block, drop_data.0.source_info, terminator);
|
cfg.terminate(block, drop_data.0.source_info, terminator);
|
||||||
|
@ -1141,7 +1141,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.terminate(
|
self.cfg.terminate(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::Drop { place, target: assign, unwind: Some(assign_unwind) },
|
TerminatorKind::Drop {
|
||||||
|
place,
|
||||||
|
target: assign,
|
||||||
|
unwind: UnwindAction::Cleanup(assign_unwind),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
self.diverge_from(block);
|
self.diverge_from(block);
|
||||||
|
|
||||||
|
@ -1165,7 +1169,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.terminate(
|
self.cfg.terminate(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None },
|
TerminatorKind::Assert {
|
||||||
|
cond,
|
||||||
|
expected,
|
||||||
|
msg,
|
||||||
|
target: success_block,
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
self.diverge_from(block);
|
self.diverge_from(block);
|
||||||
|
|
||||||
|
@ -1244,7 +1254,11 @@ fn build_scope_drops<'tcx>(
|
||||||
cfg.terminate(
|
cfg.terminate(
|
||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::Drop { place: local.into(), target: next, unwind: None },
|
TerminatorKind::Drop {
|
||||||
|
place: local.into(),
|
||||||
|
target: next,
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
block = next;
|
block = next;
|
||||||
}
|
}
|
||||||
|
@ -1424,23 +1438,23 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
|
||||||
let term = &mut cfg.block_data_mut(from).terminator_mut();
|
let term = &mut cfg.block_data_mut(from).terminator_mut();
|
||||||
match &mut term.kind {
|
match &mut term.kind {
|
||||||
TerminatorKind::Drop { unwind, .. } => {
|
TerminatorKind::Drop { unwind, .. } => {
|
||||||
if let Some(unwind) = *unwind {
|
if let UnwindAction::Cleanup(unwind) = *unwind {
|
||||||
let source_info = term.source_info;
|
let source_info = term.source_info;
|
||||||
cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to });
|
cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to });
|
||||||
} else {
|
} else {
|
||||||
*unwind = Some(to);
|
*unwind = UnwindAction::Cleanup(to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::FalseUnwind { unwind, .. }
|
TerminatorKind::FalseUnwind { unwind, .. }
|
||||||
| TerminatorKind::Call { cleanup: unwind, .. }
|
| TerminatorKind::Call { unwind, .. }
|
||||||
| TerminatorKind::Assert { cleanup: unwind, .. }
|
| TerminatorKind::Assert { unwind, .. }
|
||||||
| TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
|
| TerminatorKind::InlineAsm { unwind, .. } => {
|
||||||
*unwind = Some(to);
|
*unwind = UnwindAction::Cleanup(to);
|
||||||
}
|
}
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::graph::iterate::{
|
||||||
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||||
};
|
};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
|
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
|
||||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
|
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
|
||||||
use rustc_middle::ty::{self, Instance, TyCtxt};
|
use rustc_middle::ty::{self, Instance, TyCtxt};
|
||||||
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
|
||||||
|
@ -108,7 +108,7 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||||
|
|
||||||
match self.body[bb].terminator().kind {
|
match self.body[bb].terminator().kind {
|
||||||
// These terminators return control flow to the caller.
|
// These terminators return control flow to the caller.
|
||||||
TerminatorKind::Abort
|
TerminatorKind::Terminate
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
|
@ -149,7 +149,9 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
|
||||||
|
|
||||||
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
|
||||||
let terminator = self.body[bb].terminator();
|
let terminator = self.body[bb].terminator();
|
||||||
if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 {
|
if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target))
|
||||||
|
&& terminator.successors().count() > 1
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Don't traverse successors of recursive calls or false CFG edges.
|
// Don't traverse successors of recursive calls or false CFG edges.
|
||||||
|
|
|
@ -77,10 +77,10 @@ impl Unwind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_option(self) -> Option<BasicBlock> {
|
fn into_action(self) -> UnwindAction {
|
||||||
match self {
|
match self {
|
||||||
Unwind::To(bb) => Some(bb),
|
Unwind::To(bb) => UnwindAction::Cleanup(bb),
|
||||||
Unwind::InCleanup => None,
|
Unwind::InCleanup => UnwindAction::Terminate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ where
|
||||||
TerminatorKind::Drop {
|
TerminatorKind::Drop {
|
||||||
place: self.place,
|
place: self.place,
|
||||||
target: self.succ,
|
target: self.succ,
|
||||||
unwind: self.unwind.into_option(),
|
unwind: self.unwind.into_action(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ where
|
||||||
args: vec![Operand::Move(Place::from(ref_place))],
|
args: vec![Operand::Move(Place::from(ref_place))],
|
||||||
destination: unit_temp,
|
destination: unit_temp,
|
||||||
target: Some(succ),
|
target: Some(succ),
|
||||||
cleanup: unwind.into_option(),
|
unwind: unwind.into_action(),
|
||||||
from_hir_call: true,
|
from_hir_call: true,
|
||||||
fn_span: self.source_info.span,
|
fn_span: self.source_info.span,
|
||||||
},
|
},
|
||||||
|
@ -717,7 +717,7 @@ where
|
||||||
TerminatorKind::Drop {
|
TerminatorKind::Drop {
|
||||||
place: tcx.mk_place_deref(ptr),
|
place: tcx.mk_place_deref(ptr),
|
||||||
target: loop_block,
|
target: loop_block,
|
||||||
unwind: unwind.into_option(),
|
unwind: unwind.into_action(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -946,7 +946,11 @@ where
|
||||||
args,
|
args,
|
||||||
destination: unit_temp,
|
destination: unit_temp,
|
||||||
target: Some(target),
|
target: Some(target),
|
||||||
cleanup: None,
|
unwind: if unwind.is_cleanup() {
|
||||||
|
UnwindAction::Terminate
|
||||||
|
} else {
|
||||||
|
UnwindAction::Continue
|
||||||
|
},
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: self.source_info.span,
|
fn_span: self.source_info.span,
|
||||||
}; // FIXME(#43234)
|
}; // FIXME(#43234)
|
||||||
|
@ -959,7 +963,7 @@ where
|
||||||
|
|
||||||
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
|
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
|
||||||
let block =
|
let block =
|
||||||
TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() };
|
TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() };
|
||||||
self.new_block(unwind, block)
|
self.new_block(unwind, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets};
|
use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets, UnwindAction};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
|
@ -474,14 +474,14 @@ impl Direction for Forward {
|
||||||
{
|
{
|
||||||
use mir::TerminatorKind::*;
|
use mir::TerminatorKind::*;
|
||||||
match bb_data.terminator().kind {
|
match bb_data.terminator().kind {
|
||||||
Return | Resume | Abort | GeneratorDrop | Unreachable => {}
|
Return | Resume | Terminate | GeneratorDrop | Unreachable => {}
|
||||||
|
|
||||||
Goto { target } => propagate(target, exit_state),
|
Goto { target } => propagate(target, exit_state),
|
||||||
|
|
||||||
Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
|
Assert { target, unwind, expected: _, msg: _, cond: _ }
|
||||||
| Drop { target, unwind, place: _ }
|
| Drop { target, unwind, place: _ }
|
||||||
| FalseUnwind { real_target: target, unwind } => {
|
| FalseUnwind { real_target: target, unwind } => {
|
||||||
if let Some(unwind) = unwind {
|
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||||
propagate(unwind, exit_state);
|
propagate(unwind, exit_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,7 +503,7 @@ impl Direction for Forward {
|
||||||
}
|
}
|
||||||
|
|
||||||
Call {
|
Call {
|
||||||
cleanup,
|
unwind,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
func: _,
|
func: _,
|
||||||
|
@ -511,7 +511,7 @@ impl Direction for Forward {
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
if let Some(unwind) = cleanup {
|
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||||
propagate(unwind, exit_state);
|
propagate(unwind, exit_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,9 +533,9 @@ impl Direction for Forward {
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination,
|
destination,
|
||||||
cleanup,
|
unwind,
|
||||||
} => {
|
} => {
|
||||||
if let Some(unwind) = cleanup {
|
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||||
propagate(unwind, exit_state);
|
propagate(unwind, exit_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
destination: dummy_place.clone(),
|
destination: dummy_place.clone(),
|
||||||
target: Some(mir::START_BLOCK),
|
target: Some(mir::START_BLOCK),
|
||||||
cleanup: None,
|
unwind: mir::UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
|
@ -53,7 +53,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
destination: dummy_place.clone(),
|
destination: dummy_place.clone(),
|
||||||
target: Some(mir::START_BLOCK),
|
target: Some(mir::START_BLOCK),
|
||||||
cleanup: None,
|
unwind: mir::UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
|
|
|
@ -125,7 +125,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Abort
|
TerminatorKind::Terminate
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -200,7 +200,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
|
|
||||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||||
// variants are added.
|
// variants are added.
|
||||||
TerminatorKind::Abort
|
TerminatorKind::Terminate
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
@ -237,7 +237,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||||
// variants are added.
|
// variants are added.
|
||||||
TerminatorKind::Yield { .. }
|
TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -375,7 +375,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
// need recording.
|
// need recording.
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. } => {}
|
| TerminatorKind::Drop { .. } => {}
|
||||||
|
@ -398,7 +398,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
ref args,
|
ref args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
|
@ -417,7 +417,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
match *op {
|
match *op {
|
||||||
|
|
|
@ -238,7 +238,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
|
|
|
@ -34,11 +34,6 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This pass only runs on functions which themselves cannot unwind,
|
|
||||||
// forcibly changing the body of the function to structurally provide
|
|
||||||
// this guarantee by aborting on an unwind. If this function can unwind,
|
|
||||||
// then there's nothing to do because it already should work correctly.
|
|
||||||
//
|
|
||||||
// Here we test for this function itself whether its ABI allows
|
// Here we test for this function itself whether its ABI allows
|
||||||
// unwinding or not.
|
// unwinding or not.
|
||||||
let body_ty = tcx.type_of(def_id).skip_binder();
|
let body_ty = tcx.type_of(def_id).skip_binder();
|
||||||
|
@ -107,31 +102,14 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For call instructions which need to be terminated, we insert a
|
for id in calls_to_terminate {
|
||||||
// singular basic block which simply terminates, and then configure the
|
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||||
// `cleanup` attribute for all calls we found to this basic block we
|
*cleanup = UnwindAction::Terminate;
|
||||||
// insert which means that any unwinding that happens in the functions
|
|
||||||
// will force an abort of the process.
|
|
||||||
if !calls_to_terminate.is_empty() {
|
|
||||||
let bb = BasicBlockData {
|
|
||||||
statements: Vec::new(),
|
|
||||||
is_cleanup: true,
|
|
||||||
terminator: Some(Terminator {
|
|
||||||
source_info: SourceInfo::outermost(body.span),
|
|
||||||
kind: TerminatorKind::Abort,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
let abort_bb = body.basic_blocks_mut().push(bb);
|
|
||||||
|
|
||||||
for bb in calls_to_terminate {
|
|
||||||
let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
|
|
||||||
*cleanup = Some(abort_bb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for id in cleanups_to_remove {
|
for id in cleanups_to_remove {
|
||||||
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||||
*cleanup = None;
|
*cleanup = UnwindAction::Unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We may have invalidated some `cleanup` blocks so clean those up now.
|
// We may have invalidated some `cleanup` blocks so clean those up now.
|
||||||
|
|
|
@ -50,10 +50,11 @@ impl AddCallGuards {
|
||||||
for block in body.basic_blocks_mut() {
|
for block in body.basic_blocks_mut() {
|
||||||
match block.terminator {
|
match block.terminator {
|
||||||
Some(Terminator {
|
Some(Terminator {
|
||||||
kind: TerminatorKind::Call { target: Some(ref mut destination), cleanup, .. },
|
kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
|
||||||
source_info,
|
source_info,
|
||||||
}) if pred_count[*destination] > 1
|
}) if pred_count[*destination] > 1
|
||||||
&& (cleanup.is_some() || self == &AllCallEdges) =>
|
&& (matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate)
|
||||||
|
|| self == &AllCallEdges) =>
|
||||||
{
|
{
|
||||||
// It's a critical edge, break it
|
// It's a critical edge, break it
|
||||||
let call_guard = BasicBlockData {
|
let call_guard = BasicBlockData {
|
||||||
|
|
|
@ -221,7 +221,7 @@ fn insert_alignment_check<'tcx>(
|
||||||
required: Operand::Copy(alignment),
|
required: Operand::Copy(alignment),
|
||||||
found: Operand::Copy(addr),
|
found: Operand::Copy(addr),
|
||||||
},
|
},
|
||||||
cleanup: None,
|
unwind: UnwindAction::Terminate,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::FalseEdge { .. }
|
| TerminatorKind::FalseEdge { .. }
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::MirPass;
|
||||||
use rustc_const_eval::interpret::{
|
use rustc_const_eval::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
|
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
|
||||||
ImmTy, Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer,
|
ImmTy, Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer,
|
||||||
Scalar, StackPopCleanup, StackPopUnwind,
|
Scalar, StackPopCleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||||
|
@ -209,7 +209,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
_args: &[OpTy<'tcx>],
|
_args: &[OpTy<'tcx>],
|
||||||
_destination: &PlaceTy<'tcx>,
|
_destination: &PlaceTy<'tcx>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: UnwindAction,
|
||||||
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
_args: &[OpTy<'tcx>],
|
_args: &[OpTy<'tcx>],
|
||||||
_destination: &PlaceTy<'tcx>,
|
_destination: &PlaceTy<'tcx>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
|
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
||||||
_unwind: Option<rustc_middle::mir::BasicBlock>,
|
_unwind: rustc_middle::mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
bug!("panics terminators are not evaluated in ConstProp")
|
bug!("panics terminators are not evaluated in ConstProp")
|
||||||
}
|
}
|
||||||
|
@ -959,7 +959,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
// None of these have Operands to const-propagate.
|
// None of these have Operands to const-propagate.
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
|
|
|
@ -686,7 +686,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
// None of these have Operands to const-propagate.
|
// None of these have Operands to const-propagate.
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
|
|
|
@ -818,7 +818,7 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
|
||||||
TerminatorKind::Goto { .. } => "Goto",
|
TerminatorKind::Goto { .. } => "Goto",
|
||||||
TerminatorKind::SwitchInt { .. } => "SwitchInt",
|
TerminatorKind::SwitchInt { .. } => "SwitchInt",
|
||||||
TerminatorKind::Resume => "Resume",
|
TerminatorKind::Resume => "Resume",
|
||||||
TerminatorKind::Abort => "Abort",
|
TerminatorKind::Terminate => "Terminate",
|
||||||
TerminatorKind::Return => "Return",
|
TerminatorKind::Return => "Return",
|
||||||
TerminatorKind::Unreachable => "Unreachable",
|
TerminatorKind::Unreachable => "Unreachable",
|
||||||
TerminatorKind::Drop { .. } => "Drop",
|
TerminatorKind::Drop { .. } => "Drop",
|
||||||
|
|
|
@ -122,7 +122,7 @@ impl CoverageGraph {
|
||||||
|
|
||||||
match term.kind {
|
match term.kind {
|
||||||
TerminatorKind::Return { .. }
|
TerminatorKind::Return { .. }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::SwitchInt { .. } => {
|
| TerminatorKind::SwitchInt { .. } => {
|
||||||
// The `bb` has more than one _outgoing_ edge, or exits the function. Save the
|
// The `bb` has more than one _outgoing_ edge, or exits the function. Save the
|
||||||
|
@ -136,7 +136,7 @@ impl CoverageGraph {
|
||||||
debug!(" because term.kind = {:?}", term.kind);
|
debug!(" because term.kind = {:?}", term.kind);
|
||||||
// Note that this condition is based on `TerminatorKind`, even though it
|
// Note that this condition is based on `TerminatorKind`, even though it
|
||||||
// theoretically boils down to `successors().len() != 1`; that is, either zero
|
// theoretically boils down to `successors().len() != 1`; that is, either zero
|
||||||
// (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but
|
// (e.g., `Return`, `Terminate`) or multiple successors (e.g., `SwitchInt`), but
|
||||||
// since the BCB CFG ignores things like unwind branches (which exist in the
|
// since the BCB CFG ignores things like unwind branches (which exist in the
|
||||||
// `Terminator`s `successors()` list) checking the number of successors won't
|
// `Terminator`s `successors()` list) checking the number of successors won't
|
||||||
// work.
|
// work.
|
||||||
|
|
|
@ -869,7 +869,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
|
||||||
|
|
||||||
// Retain spans from all other terminators
|
// Retain spans from all other terminators
|
||||||
TerminatorKind::Resume
|
TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl<'tcx> MockBlocks<'tcx> {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
destination: self.dummy_place.clone(),
|
destination: self.dummy_place.clone(),
|
||||||
target: Some(TEMP_BLOCK),
|
target: Some(TEMP_BLOCK),
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
from_hir_call: false,
|
from_hir_call: false,
|
||||||
fn_span: DUMMY_SP,
|
fn_span: DUMMY_SP,
|
||||||
},
|
},
|
||||||
|
|
|
@ -567,7 +567,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
||||||
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
||||||
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: rustc_const_eval::interpret::StackPopUnwind,
|
_unwind: UnwindAction,
|
||||||
) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -578,7 +578,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
||||||
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
||||||
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: rustc_const_eval::interpret::StackPopUnwind,
|
_unwind: UnwindAction,
|
||||||
) -> interpret::InterpResult<'tcx> {
|
) -> interpret::InterpResult<'tcx> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -586,7 +586,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
_msg: &rustc_middle::mir::AssertMessage<'tcx>,
|
||||||
_unwind: Option<BasicBlock>,
|
_unwind: UnwindAction,
|
||||||
) -> interpret::InterpResult<'tcx> {
|
) -> interpret::InterpResult<'tcx> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -645,8 +645,8 @@ impl WriteInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Resume { .. }
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort { .. }
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable { .. } => (),
|
| TerminatorKind::Unreachable { .. } => (),
|
||||||
TerminatorKind::Drop { .. } => {
|
TerminatorKind::Drop { .. } => {
|
||||||
|
|
|
@ -120,7 +120,7 @@ fn remove_dead_unwinds<'tcx>(
|
||||||
.into_results_cursor(body);
|
.into_results_cursor(body);
|
||||||
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
|
||||||
let place = match bb_data.terminator().kind {
|
let place = match bb_data.terminator().kind {
|
||||||
TerminatorKind::Drop { ref place, unwind: Some(_), .. } => {
|
TerminatorKind::Drop { ref place, unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
und.derefer(place.as_ref(), body).unwrap_or(*place)
|
und.derefer(place.as_ref(), body).unwrap_or(*place)
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
|
@ -160,7 +160,7 @@ fn remove_dead_unwinds<'tcx>(
|
||||||
let basic_blocks = body.basic_blocks.as_mut();
|
let basic_blocks = body.basic_blocks.as_mut();
|
||||||
for &bb in dead_unwinds.iter() {
|
for &bb in dead_unwinds.iter() {
|
||||||
if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() {
|
if let Some(unwind) = basic_blocks[bb].terminator_mut().unwind_mut() {
|
||||||
*unwind = None;
|
*unwind = UnwindAction::Unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
let loc = Location { block: bb, statement_index: data.statements.len() };
|
let loc = Location { block: bb, statement_index: data.statements.len() };
|
||||||
let terminator = data.terminator();
|
let terminator = data.terminator();
|
||||||
|
|
||||||
let resume_block = self.patch.resume_block();
|
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Drop { mut place, target, unwind } => {
|
TerminatorKind::Drop { mut place, target, unwind } => {
|
||||||
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
|
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
|
||||||
|
@ -408,19 +407,31 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
|
|
||||||
self.init_data.seek_before(loc);
|
self.init_data.seek_before(loc);
|
||||||
match self.move_data().rev_lookup.find(place.as_ref()) {
|
match self.move_data().rev_lookup.find(place.as_ref()) {
|
||||||
LookupResult::Exact(path) => elaborate_drop(
|
LookupResult::Exact(path) => {
|
||||||
&mut Elaborator { ctxt: self },
|
let unwind = if data.is_cleanup {
|
||||||
terminator.source_info,
|
|
||||||
place,
|
|
||||||
path,
|
|
||||||
target,
|
|
||||||
if data.is_cleanup {
|
|
||||||
Unwind::InCleanup
|
Unwind::InCleanup
|
||||||
} else {
|
} else {
|
||||||
Unwind::To(Option::unwrap_or(unwind, resume_block))
|
match unwind {
|
||||||
},
|
UnwindAction::Cleanup(cleanup) => Unwind::To(cleanup),
|
||||||
bb,
|
UnwindAction::Continue => Unwind::To(self.patch.resume_block()),
|
||||||
),
|
UnwindAction::Unreachable => {
|
||||||
|
Unwind::To(self.patch.unreachable_cleanup_block())
|
||||||
|
}
|
||||||
|
UnwindAction::Terminate => {
|
||||||
|
Unwind::To(self.patch.terminate_block())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
elaborate_drop(
|
||||||
|
&mut Elaborator { ctxt: self },
|
||||||
|
terminator.source_info,
|
||||||
|
place,
|
||||||
|
path,
|
||||||
|
target,
|
||||||
|
unwind,
|
||||||
|
bb,
|
||||||
|
)
|
||||||
|
}
|
||||||
LookupResult::Parent(..) => {
|
LookupResult::Parent(..) => {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
terminator.source_info.span.desugaring_kind(),
|
terminator.source_info.span.desugaring_kind(),
|
||||||
|
@ -474,7 +485,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let TerminatorKind::Call {
|
if let TerminatorKind::Call {
|
||||||
destination, target: Some(tgt), cleanup: Some(_), ..
|
destination,
|
||||||
|
target: Some(tgt),
|
||||||
|
unwind: UnwindAction::Cleanup(_),
|
||||||
|
..
|
||||||
} = data.terminator().kind
|
} = data.terminator().kind
|
||||||
{
|
{
|
||||||
assert!(!self.patch.is_patched(bb));
|
assert!(!self.patch.is_patched(bb));
|
||||||
|
@ -543,8 +557,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
// There may be a critical edge after this call,
|
// There may be a critical edge after this call,
|
||||||
// so mark the return as initialized *before* the
|
// so mark the return as initialized *before* the
|
||||||
// call.
|
// call.
|
||||||
if let TerminatorKind::Call { destination, target: Some(_), cleanup: None, .. } =
|
if let TerminatorKind::Call {
|
||||||
data.terminator().kind
|
destination,
|
||||||
|
target: Some(_),
|
||||||
|
unwind: UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate,
|
||||||
|
..
|
||||||
|
} = data.terminator().kind
|
||||||
{
|
{
|
||||||
assert!(!self.patch.is_patched(bb));
|
assert!(!self.patch.is_patched(bb));
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
|
||||||
args,
|
args,
|
||||||
destination: _,
|
destination: _,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} = &terminator.kind
|
} = &terminator.kind
|
||||||
|
|
|
@ -1060,7 +1060,12 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||||
let unwind = if block_data.is_cleanup {
|
let unwind = if block_data.is_cleanup {
|
||||||
Unwind::InCleanup
|
Unwind::InCleanup
|
||||||
} else {
|
} else {
|
||||||
Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block()))
|
Unwind::To(match *unwind {
|
||||||
|
UnwindAction::Cleanup(tgt) => tgt,
|
||||||
|
UnwindAction::Continue => elaborator.patch.resume_block(),
|
||||||
|
UnwindAction::Unreachable => elaborator.patch.unreachable_cleanup_block(),
|
||||||
|
UnwindAction::Terminate => elaborator.patch.terminate_block(),
|
||||||
|
})
|
||||||
};
|
};
|
||||||
elaborate_drop(
|
elaborate_drop(
|
||||||
&mut elaborator,
|
&mut elaborator,
|
||||||
|
@ -1147,7 +1152,7 @@ fn insert_panic_block<'tcx>(
|
||||||
expected: true,
|
expected: true,
|
||||||
msg: message,
|
msg: message,
|
||||||
target: assert_block,
|
target: assert_block,
|
||||||
cleanup: None,
|
unwind: UnwindAction::Continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let source_info = SourceInfo::outermost(body.span);
|
let source_info = SourceInfo::outermost(body.span);
|
||||||
|
@ -1189,7 +1194,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||||
// These never unwind.
|
// These never unwind.
|
||||||
TerminatorKind::Goto { .. }
|
TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
|
@ -1248,8 +1253,8 @@ fn create_generator_resume_function<'tcx>(
|
||||||
} else if !block.is_cleanup {
|
} else if !block.is_cleanup {
|
||||||
// Any terminators that *can* unwind but don't have an unwind target set are also
|
// Any terminators that *can* unwind but don't have an unwind target set are also
|
||||||
// pointed at our poisoning block (unless they're part of the cleanup path).
|
// pointed at our poisoning block (unless they're part of the cleanup path).
|
||||||
if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
|
if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
|
||||||
*unwind = Some(poison_block);
|
*unwind = UnwindAction::Cleanup(poison_block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1294,8 +1299,11 @@ fn create_generator_resume_function<'tcx>(
|
||||||
fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
|
fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
|
||||||
let return_block = insert_term_block(body, TerminatorKind::Return);
|
let return_block = insert_term_block(body, TerminatorKind::Return);
|
||||||
|
|
||||||
let term =
|
let term = TerminatorKind::Drop {
|
||||||
TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
|
place: Place::from(SELF_ARG),
|
||||||
|
target: return_block,
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
};
|
||||||
let source_info = SourceInfo::outermost(body.span);
|
let source_info = SourceInfo::outermost(body.span);
|
||||||
|
|
||||||
// Create a block to destroy an unresumed generators. This can only destroy upvars.
|
// Create a block to destroy an unresumed generators. This can only destroy upvars.
|
||||||
|
@ -1670,7 +1678,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: Some(_),
|
target: Some(_),
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
|
@ -1693,7 +1701,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||||
| TerminatorKind::Goto { .. }
|
| TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::SwitchInt { .. }
|
| TerminatorKind::SwitchInt { .. }
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Drop { .. }
|
| TerminatorKind::Drop { .. }
|
||||||
|
|
|
@ -453,7 +453,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
|
|
||||||
// If the place doesn't actually need dropping, treat it like a regular goto.
|
// If the place doesn't actually need dropping, treat it like a regular goto.
|
||||||
let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
|
let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
|
||||||
if ty.needs_drop(tcx, self.param_env) && let Some(unwind) = unwind {
|
if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
|
||||||
work_list.push(unwind);
|
work_list.push(unwind);
|
||||||
}
|
}
|
||||||
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
|
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
|
||||||
|
@ -500,7 +500,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
) {
|
) {
|
||||||
let terminator = caller_body[callsite.block].terminator.take().unwrap();
|
let terminator = caller_body[callsite.block].terminator.take().unwrap();
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Call { args, destination, cleanup, .. } => {
|
TerminatorKind::Call { args, destination, unwind, .. } => {
|
||||||
// If the call is something like `a[*i] = f(i)`, where
|
// If the call is something like `a[*i] = f(i)`, where
|
||||||
// `i : &mut usize`, then just duplicating the `a[*i]`
|
// `i : &mut usize`, then just duplicating the `a[*i]`
|
||||||
// Place could result in two different locations if `f`
|
// Place could result in two different locations if `f`
|
||||||
|
@ -571,7 +571,7 @@ impl<'tcx> Inliner<'tcx> {
|
||||||
destination: destination_local,
|
destination: destination_local,
|
||||||
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
|
||||||
callsite,
|
callsite,
|
||||||
cleanup_block: cleanup,
|
cleanup_block: unwind,
|
||||||
in_cleanup_block: false,
|
in_cleanup_block: false,
|
||||||
tcx: self.tcx,
|
tcx: self.tcx,
|
||||||
expn_data,
|
expn_data,
|
||||||
|
@ -813,14 +813,14 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
||||||
let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
|
let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
|
||||||
if ty.needs_drop(tcx, self.param_env) {
|
if ty.needs_drop(tcx, self.param_env) {
|
||||||
self.cost += CALL_PENALTY;
|
self.cost += CALL_PENALTY;
|
||||||
if unwind.is_some() {
|
if let UnwindAction::Cleanup(_) = unwind {
|
||||||
self.cost += LANDINGPAD_PENALTY;
|
self.cost += LANDINGPAD_PENALTY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.cost += INSTR_COST;
|
self.cost += INSTR_COST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => {
|
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
|
||||||
let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty());
|
let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty());
|
||||||
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
|
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
|
||||||
// Don't give intrinsics the extra penalty for calls
|
// Don't give intrinsics the extra penalty for calls
|
||||||
|
@ -828,20 +828,20 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
CALL_PENALTY
|
CALL_PENALTY
|
||||||
};
|
};
|
||||||
if cleanup.is_some() {
|
if let UnwindAction::Cleanup(_) = unwind {
|
||||||
self.cost += LANDINGPAD_PENALTY;
|
self.cost += LANDINGPAD_PENALTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { cleanup, .. } => {
|
TerminatorKind::Assert { unwind, .. } => {
|
||||||
self.cost += CALL_PENALTY;
|
self.cost += CALL_PENALTY;
|
||||||
if cleanup.is_some() {
|
if let UnwindAction::Cleanup(_) = unwind {
|
||||||
self.cost += LANDINGPAD_PENALTY;
|
self.cost += LANDINGPAD_PENALTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Resume => self.cost += RESUME_PENALTY,
|
TerminatorKind::Resume => self.cost += RESUME_PENALTY,
|
||||||
TerminatorKind::InlineAsm { cleanup, .. } => {
|
TerminatorKind::InlineAsm { unwind, .. } => {
|
||||||
self.cost += INSTR_COST;
|
self.cost += INSTR_COST;
|
||||||
if cleanup.is_some() {
|
if let UnwindAction::Cleanup(_) = unwind {
|
||||||
self.cost += LANDINGPAD_PENALTY;
|
self.cost += LANDINGPAD_PENALTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -979,7 +979,7 @@ struct Integrator<'a, 'tcx> {
|
||||||
destination: Local,
|
destination: Local,
|
||||||
callsite_scope: SourceScopeData<'tcx>,
|
callsite_scope: SourceScopeData<'tcx>,
|
||||||
callsite: &'a CallSite<'tcx>,
|
callsite: &'a CallSite<'tcx>,
|
||||||
cleanup_block: Option<BasicBlock>,
|
cleanup_block: UnwindAction,
|
||||||
in_cleanup_block: bool,
|
in_cleanup_block: bool,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
expn_data: LocalExpnId,
|
expn_data: LocalExpnId,
|
||||||
|
@ -1014,18 +1014,21 @@ impl Integrator<'_, '_> {
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_unwind(&self, unwind: Option<BasicBlock>) -> Option<BasicBlock> {
|
fn map_unwind(&self, unwind: UnwindAction) -> UnwindAction {
|
||||||
if self.in_cleanup_block {
|
if self.in_cleanup_block {
|
||||||
if unwind.is_some() {
|
match unwind {
|
||||||
bug!("cleanup on cleanup block");
|
UnwindAction::Cleanup(_) | UnwindAction::Continue => {
|
||||||
|
bug!("cleanup on cleanup block");
|
||||||
|
}
|
||||||
|
UnwindAction::Unreachable | UnwindAction::Terminate => return unwind,
|
||||||
}
|
}
|
||||||
return unwind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match unwind {
|
match unwind {
|
||||||
Some(target) => Some(self.map_block(target)),
|
UnwindAction::Unreachable | UnwindAction::Terminate => unwind,
|
||||||
|
UnwindAction::Cleanup(target) => UnwindAction::Cleanup(self.map_block(target)),
|
||||||
// Add an unwind edge to the original call's cleanup block
|
// Add an unwind edge to the original call's cleanup block
|
||||||
None => self.cleanup_block,
|
UnwindAction::Continue => self.cleanup_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,15 +1119,15 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||||
*target = self.map_block(*target);
|
*target = self.map_block(*target);
|
||||||
*unwind = self.map_unwind(*unwind);
|
*unwind = self.map_unwind(*unwind);
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { ref mut target, ref mut cleanup, .. } => {
|
TerminatorKind::Call { ref mut target, ref mut unwind, .. } => {
|
||||||
if let Some(ref mut tgt) = *target {
|
if let Some(ref mut tgt) = *target {
|
||||||
*tgt = self.map_block(*tgt);
|
*tgt = self.map_block(*tgt);
|
||||||
}
|
}
|
||||||
*cleanup = self.map_unwind(*cleanup);
|
*unwind = self.map_unwind(*unwind);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
|
TerminatorKind::Assert { ref mut target, ref mut unwind, .. } => {
|
||||||
*target = self.map_block(*target);
|
*target = self.map_block(*target);
|
||||||
*cleanup = self.map_unwind(*cleanup);
|
*unwind = self.map_unwind(*unwind);
|
||||||
}
|
}
|
||||||
TerminatorKind::Return => {
|
TerminatorKind::Return => {
|
||||||
terminator.kind = if let Some(tgt) = self.callsite.target {
|
terminator.kind = if let Some(tgt) = self.callsite.target {
|
||||||
|
@ -1134,11 +1137,14 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Resume => {
|
TerminatorKind::Resume => {
|
||||||
if let Some(tgt) = self.cleanup_block {
|
terminator.kind = match self.cleanup_block {
|
||||||
terminator.kind = TerminatorKind::Goto { target: tgt }
|
UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt },
|
||||||
}
|
UnwindAction::Continue => TerminatorKind::Resume,
|
||||||
|
UnwindAction::Unreachable => TerminatorKind::Unreachable,
|
||||||
|
UnwindAction::Terminate => TerminatorKind::Terminate,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
TerminatorKind::Abort => {}
|
TerminatorKind::Terminate => {}
|
||||||
TerminatorKind::Unreachable => {}
|
TerminatorKind::Unreachable => {}
|
||||||
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||||
*real_target = self.map_block(*real_target);
|
*real_target = self.map_block(*real_target);
|
||||||
|
@ -1149,11 +1155,11 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
||||||
{
|
{
|
||||||
bug!("False unwinds should have been removed before inlining")
|
bug!("False unwinds should have been removed before inlining")
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { ref mut destination, ref mut cleanup, .. } => {
|
TerminatorKind::InlineAsm { ref mut destination, ref mut unwind, .. } => {
|
||||||
if let Some(ref mut tgt) = *destination {
|
if let Some(ref mut tgt) = *destination {
|
||||||
*tgt = self.map_block(*tgt);
|
*tgt = self.map_block(*tgt);
|
||||||
}
|
}
|
||||||
*cleanup = self.map_unwind(*cleanup);
|
*unwind = self.map_unwind(*unwind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
||||||
ref mut args,
|
ref mut args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
cleanup,
|
unwind,
|
||||||
fn_span,
|
fn_span,
|
||||||
..
|
..
|
||||||
} if let ty::FnDef(def_id, _) = *literal.ty().kind()
|
} if let ty::FnDef(def_id, _) = *literal.ty().kind()
|
||||||
|
@ -196,7 +196,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
||||||
};
|
};
|
||||||
method(place)
|
method(place)
|
||||||
}).collect();
|
}).collect();
|
||||||
terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span };
|
terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, from_hir_call: false, fn_span };
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ fn lower_slice_len_call<'tcx>(
|
||||||
args,
|
args,
|
||||||
destination,
|
destination,
|
||||||
target: Some(bb),
|
target: Some(bb),
|
||||||
cleanup: None,
|
|
||||||
from_hir_call: true,
|
from_hir_call: true,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl RemoveNoopLandingPads {
|
||||||
TerminatorKind::GeneratorDrop
|
TerminatorKind::GeneratorDrop
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
|
@ -103,11 +103,11 @@ impl RemoveNoopLandingPads {
|
||||||
for bb in postorder {
|
for bb in postorder {
|
||||||
debug!(" processing {:?}", bb);
|
debug!(" processing {:?}", bb);
|
||||||
if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
|
if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
|
||||||
if let Some(unwind_bb) = *unwind {
|
if let UnwindAction::Cleanup(unwind_bb) = *unwind {
|
||||||
if nop_landing_pads.contains(unwind_bb) {
|
if nop_landing_pads.contains(unwind_bb) {
|
||||||
debug!(" removing noop landing pad");
|
debug!(" removing noop landing pad");
|
||||||
landing_pads_removed += 1;
|
landing_pads_removed += 1;
|
||||||
*unwind = None;
|
*unwind = UnwindAction::Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||||
| TerminatorKind::Assert { .. }
|
| TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::Yield { .. }
|
| TerminatorKind::Yield { .. }
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::InlineAsm { .. }
|
| TerminatorKind::InlineAsm { .. }
|
||||||
|
@ -164,7 +164,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::Resume
|
TerminatorKind::Resume
|
||||||
| TerminatorKind::Abort
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Unreachable
|
| TerminatorKind::Unreachable
|
||||||
| TerminatorKind::GeneratorDrop
|
| TerminatorKind::GeneratorDrop
|
||||||
|
|
|
@ -499,7 +499,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
||||||
args: vec![Operand::Move(ref_loc)],
|
args: vec![Operand::Move(ref_loc)],
|
||||||
destination: dest,
|
destination: dest,
|
||||||
target: Some(next),
|
target: Some(next),
|
||||||
cleanup: Some(cleanup),
|
unwind: UnwindAction::Cleanup(cleanup),
|
||||||
from_hir_call: true,
|
from_hir_call: true,
|
||||||
fn_span: self.span,
|
fn_span: self.span,
|
||||||
},
|
},
|
||||||
|
@ -540,7 +540,11 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
||||||
self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
|
self.make_clone_call(dest_field, src_field, ity, next_block, unwind);
|
||||||
self.block(
|
self.block(
|
||||||
vec![],
|
vec![],
|
||||||
TerminatorKind::Drop { place: dest_field, target: unwind, unwind: None },
|
TerminatorKind::Drop {
|
||||||
|
place: dest_field,
|
||||||
|
target: unwind,
|
||||||
|
unwind: UnwindAction::Terminate,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
unwind = next_unwind;
|
unwind = next_unwind;
|
||||||
|
@ -776,10 +780,10 @@ fn build_call_shim<'tcx>(
|
||||||
args,
|
args,
|
||||||
destination: Place::return_place(),
|
destination: Place::return_place(),
|
||||||
target: Some(BasicBlock::new(1)),
|
target: Some(BasicBlock::new(1)),
|
||||||
cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment {
|
||||||
Some(BasicBlock::new(3))
|
UnwindAction::Cleanup(BasicBlock::new(3))
|
||||||
} else {
|
} else {
|
||||||
None
|
UnwindAction::Continue
|
||||||
},
|
},
|
||||||
from_hir_call: true,
|
from_hir_call: true,
|
||||||
fn_span: span,
|
fn_span: span,
|
||||||
|
@ -792,7 +796,11 @@ fn build_call_shim<'tcx>(
|
||||||
block(
|
block(
|
||||||
&mut blocks,
|
&mut blocks,
|
||||||
vec![],
|
vec![],
|
||||||
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None },
|
TerminatorKind::Drop {
|
||||||
|
place: rcvr_place(),
|
||||||
|
target: BasicBlock::new(2),
|
||||||
|
unwind: UnwindAction::Continue,
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -803,7 +811,11 @@ fn build_call_shim<'tcx>(
|
||||||
block(
|
block(
|
||||||
&mut blocks,
|
&mut blocks,
|
||||||
vec![],
|
vec![],
|
||||||
TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
|
TerminatorKind::Drop {
|
||||||
|
place: rcvr_place(),
|
||||||
|
target: BasicBlock::new(4),
|
||||||
|
unwind: UnwindAction::Terminate,
|
||||||
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -852,7 +852,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||||
self.output.push(create_fn_mono_item(tcx, instance, source));
|
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::Abort { .. } => {
|
mir::TerminatorKind::Terminate { .. } => {
|
||||||
let instance = Instance::mono(
|
let instance = Instance::mono(
|
||||||
tcx,
|
tcx,
|
||||||
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
|
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
|
||||||
|
@ -872,6 +872,16 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||||
| mir::TerminatorKind::FalseUnwind { .. } => bug!(),
|
| mir::TerminatorKind::FalseUnwind { .. } => bug!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(mir::UnwindAction::Terminate) = terminator.unwind() {
|
||||||
|
let instance = Instance::mono(
|
||||||
|
tcx,
|
||||||
|
tcx.require_lang_item(LangItem::PanicCannotUnwind, Some(source)),
|
||||||
|
);
|
||||||
|
if should_codegen_locally(tcx, &instance) {
|
||||||
|
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.super_terminator(terminator, location);
|
self.super_terminator(terminator, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ fn rustc_terminator_to_terminator(
|
||||||
otherwise: targets.otherwise().as_usize(),
|
otherwise: targets.otherwise().as_usize(),
|
||||||
},
|
},
|
||||||
Resume => Terminator::Resume,
|
Resume => Terminator::Resume,
|
||||||
Abort => Terminator::Abort,
|
Terminate => Terminator::Abort,
|
||||||
Return => Terminator::Return,
|
Return => Terminator::Return,
|
||||||
Unreachable => Terminator::Unreachable,
|
Unreachable => Terminator::Unreachable,
|
||||||
Drop { .. } => todo!(),
|
Drop { .. } => todo!(),
|
||||||
|
|
|
@ -301,13 +301,13 @@ fn check_terminator<'tcx>(
|
||||||
| TerminatorKind::Goto { .. }
|
| TerminatorKind::Goto { .. }
|
||||||
| TerminatorKind::Return
|
| TerminatorKind::Return
|
||||||
| TerminatorKind::Resume
|
| TerminatorKind::Resume
|
||||||
|
| TerminatorKind::Terminate
|
||||||
| TerminatorKind::Unreachable => Ok(()),
|
| TerminatorKind::Unreachable => Ok(()),
|
||||||
|
|
||||||
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
|
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
|
||||||
|
|
||||||
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
|
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
|
||||||
|
|
||||||
TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
|
|
||||||
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
||||||
Err((span, "const fn generators are unstable".into()))
|
Err((span, "const fn generators are unstable".into()))
|
||||||
},
|
},
|
||||||
|
@ -318,7 +318,7 @@ fn check_terminator<'tcx>(
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
destination: _,
|
destination: _,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
fn_span: _,
|
fn_span: _,
|
||||||
} => {
|
} => {
|
||||||
let fn_ty = func.ty(body, tcx);
|
let fn_ty = func.ty(body, tcx);
|
||||||
|
@ -361,7 +361,7 @@ fn check_terminator<'tcx>(
|
||||||
expected: _,
|
expected: _,
|
||||||
msg: _,
|
msg: _,
|
||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
unwind: _,
|
||||||
} => check_operand(tcx, cond, span, body),
|
} => check_operand(tcx, cond, span, body),
|
||||||
|
|
||||||
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
||||||
|
|
|
@ -951,7 +951,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
if this.machine.panic_on_unsupported {
|
if this.machine.panic_on_unsupported {
|
||||||
// message is slightly different here to make automated analysis easier
|
// message is slightly different here to make automated analysis easier
|
||||||
let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref());
|
let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref());
|
||||||
this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?;
|
this.start_panic(error_msg.as_ref(), mir::UnwindAction::Continue)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
throw_unsup_format!("{}", error_msg.as_ref());
|
throw_unsup_format!("{}", error_msg.as_ref());
|
||||||
|
|
|
@ -834,7 +834,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind)
|
ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind)
|
||||||
}
|
}
|
||||||
|
@ -847,7 +847,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
ecx.call_dlsym(fn_val, abi, args, dest, ret)
|
ecx.call_dlsym(fn_val, abi, args, dest, ret)
|
||||||
}
|
}
|
||||||
|
@ -859,7 +859,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
ecx.call_intrinsic(instance, args, dest, ret, unwind)
|
ecx.call_intrinsic(instance, args, dest, ret, unwind)
|
||||||
}
|
}
|
||||||
|
@ -868,7 +868,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
ecx: &mut MiriInterpCx<'mir, 'tcx>,
|
ecx: &mut MiriInterpCx<'mir, 'tcx>,
|
||||||
msg: &mir::AssertMessage<'tcx>,
|
msg: &mir::AssertMessage<'tcx>,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
ecx.assert_panic(msg, unwind)
|
ecx.assert_panic(msg, unwind)
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let link_name = this.item_link_name(def_id);
|
let link_name = this.item_link_name(def_id);
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
_unwind: StackPopUnwind,
|
_unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
trace!("eval_fn_call: {:#?}, {:?}", instance, dest);
|
trace!("eval_fn_call: {:#?}, {:?}", instance, dest);
|
||||||
|
@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
align_op: &OpTy<'tcx, Provenance>,
|
align_op: &OpTy<'tcx, Provenance>,
|
||||||
dest: &PlaceTy<'tcx, Provenance>,
|
dest: &PlaceTy<'tcx, Provenance>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx, bool> {
|
) -> InterpResult<'tcx, bool> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let ret = ret.unwrap();
|
let ret = ret.unwrap();
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
abi: Abi,
|
abi: Abi,
|
||||||
link_name: Symbol,
|
link_name: Symbol,
|
||||||
args: &[OpTy<'tcx, Provenance>],
|
args: &[OpTy<'tcx, Provenance>],
|
||||||
unwind: StackPopUnwind,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
&[data.into()],
|
&[data.into()],
|
||||||
None,
|
None,
|
||||||
// Directly return to caller.
|
// Directly return to caller.
|
||||||
StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip },
|
StackPopCleanup::Goto { ret: Some(ret), unwind: mir::UnwindAction::Continue },
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
|
// We ourselves will return `0`, eventually (will be overwritten if we catch a panic).
|
||||||
|
@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
&[catch_unwind.data.into(), payload.into()],
|
&[catch_unwind.data.into(), payload.into()],
|
||||||
None,
|
None,
|
||||||
// Directly return to caller of `try`.
|
// Directly return to caller of `try`.
|
||||||
StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip },
|
StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: mir::UnwindAction::Continue },
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// We pushed a new stack frame, the engine should not do any jumping now!
|
// We pushed a new stack frame, the engine should not do any jumping now!
|
||||||
|
@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a panic in the interpreter with the given message as payload.
|
/// Start a panic in the interpreter with the given message as payload.
|
||||||
fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> {
|
fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// First arg: message.
|
// First arg: message.
|
||||||
|
@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
&mut self,
|
&mut self,
|
||||||
msg: &mir::AssertMessage<'tcx>,
|
msg: &mir::AssertMessage<'tcx>,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: mir::UnwindAction,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
use rustc_middle::mir::AssertKind::*;
|
use rustc_middle::mir::AssertKind::*;
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
@ -213,10 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
None,
|
None,
|
||||||
StackPopCleanup::Goto {
|
StackPopCleanup::Goto {
|
||||||
ret: None,
|
ret: None,
|
||||||
unwind: match unwind {
|
unwind,
|
||||||
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
|
||||||
None => StackPopUnwind::Skip,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -240,10 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
None,
|
None,
|
||||||
StackPopCleanup::Goto {
|
StackPopCleanup::Goto {
|
||||||
ret: None,
|
ret: None,
|
||||||
unwind: match unwind {
|
unwind,
|
||||||
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
|
||||||
None => StackPopUnwind::Skip,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -252,10 +246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
// Forward everything else to `panic` lang item.
|
// Forward everything else to `panic` lang item.
|
||||||
this.start_panic(
|
this.start_panic(
|
||||||
msg.description(),
|
msg.description(),
|
||||||
match unwind {
|
unwind,
|
||||||
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
|
||||||
None => StackPopUnwind::Skip,
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
error: abnormal termination: the program aborted execution
|
error: abnormal termination: panic in a function that cannot unwind
|
||||||
--> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
--> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | / extern "C-unwind" fn nounwind() {
|
LL | / extern "C-unwind" fn nounwind() {
|
||||||
|
@ -8,7 +8,7 @@ LL | |
|
||||||
LL | |
|
LL | |
|
||||||
LL | | panic!();
|
LL | | panic!();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^ the program aborted execution
|
| |_^ panic in a function that cannot unwind
|
||||||
|
|
|
|
||||||
= note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
= note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
note: inside `main`
|
note: inside `main`
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
error: abnormal termination: the program aborted execution
|
error: abnormal termination: panic in a function that cannot unwind
|
||||||
--> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
--> $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | / extern "C-unwind" fn nounwind() {
|
LL | / extern "C-unwind" fn nounwind() {
|
||||||
|
@ -8,7 +8,7 @@ LL | |
|
||||||
LL | |
|
LL | |
|
||||||
LL | | panic!();
|
LL | | panic!();
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^ the program aborted execution
|
| |_^ panic in a function that cannot unwind
|
||||||
|
|
|
|
||||||
= note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
= note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC
|
||||||
note: inside `main`
|
note: inside `main`
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
#[cfg_attr(any(definition, both), rustc_nounwind)]
|
#[cfg_attr(any(definition, both), rustc_nounwind)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C-unwind" fn nounwind() {
|
extern "C-unwind" fn nounwind() {
|
||||||
//~[definition]^ ERROR: abnormal termination: the program aborted execution
|
//~[definition]^ ERROR: abnormal termination: panic in a function that cannot unwind
|
||||||
//~[both]^^ ERROR: abnormal termination: the program aborted execution
|
//~[both]^^ ERROR: abnormal termination: panic in a function that cannot unwind
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
src/tools/miri/tests/fail/terminate-terminator.rs
Normal file
27
src/tools/miri/tests/fail/terminate-terminator.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
//@compile-flags: -Zmir-opt-level=3
|
||||||
|
// Enable MIR inlining to ensure that `TerminatorKind::Terminate` is generated
|
||||||
|
// instead of just `UnwindAction::Terminate`.
|
||||||
|
|
||||||
|
#![feature(c_unwind)]
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn has_cleanup() {
|
||||||
|
//~^ ERROR: panic in a function that cannot unwind
|
||||||
|
// FIXME(nbdd0121): The error should be reported at the call site.
|
||||||
|
let _f = Foo;
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn panic_abort() {
|
||||||
|
has_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
panic_abort();
|
||||||
|
}
|
27
src/tools/miri/tests/fail/terminate-terminator.stderr
Normal file
27
src/tools/miri/tests/fail/terminate-terminator.stderr
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
thread 'main' panicked at 'explicit panic', $DIR/terminate-terminator.rs:LL:CC
|
||||||
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
error: abnormal termination: panic in a function that cannot unwind
|
||||||
|
--> $DIR/terminate-terminator.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | / fn has_cleanup() {
|
||||||
|
LL | |
|
||||||
|
LL | | // FIXME(nbdd0121): The error should be reported at the call site.
|
||||||
|
LL | | let _f = Foo;
|
||||||
|
LL | | panic!();
|
||||||
|
LL | | }
|
||||||
|
| |_^ panic in a function that cannot unwind
|
||||||
|
...
|
||||||
|
LL | has_cleanup();
|
||||||
|
| ------------- in this inlined function call
|
||||||
|
|
|
||||||
|
= note: inside `panic_abort` at $DIR/terminate-terminator.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/terminate-terminator.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | panic_abort();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
|
|
||||||
extern "C" fn panic_abort() {
|
extern "C" fn panic_abort() {
|
||||||
//~^ ERROR: the program aborted
|
//~^ ERROR: panic in a function that cannot unwind
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
thread 'main' panicked at 'explicit panic', $DIR/abort-terminator.rs:LL:CC
|
thread 'main' panicked at 'explicit panic', $DIR/unwind-action-terminate.rs:LL:CC
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
error: abnormal termination: the program aborted execution
|
error: abnormal termination: panic in a function that cannot unwind
|
||||||
--> $DIR/abort-terminator.rs:LL:CC
|
--> $DIR/unwind-action-terminate.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | / extern "C" fn panic_abort() {
|
LL | / extern "C" fn panic_abort() {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | panic!()
|
LL | | panic!()
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^ the program aborted execution
|
| |_^ panic in a function that cannot unwind
|
||||||
|
|
|
|
||||||
= note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC
|
= note: inside `panic_abort` at $DIR/unwind-action-terminate.rs:LL:CC
|
||||||
note: inside `main`
|
note: inside `main`
|
||||||
--> $DIR/abort-terminator.rs:LL:CC
|
--> $DIR/unwind-action-terminate.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | panic_abort();
|
LL | panic_abort();
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
|
@ -38,7 +38,7 @@ fn main() -> () {
|
||||||
_6 = _3; // scope 4 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
|
_6 = _3; // scope 4 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
|
||||||
_5 = foo(move _6) -> bb1; // scope 4 at $DIR/array_index_is_temporary.rs:+4:21: +4:27
|
_5 = foo(move _6) -> bb1; // scope 4 at $DIR/array_index_is_temporary.rs:+4:21: +4:27
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/array_index_is_temporary.rs:16:21: 16:24
|
// + span: $DIR/array_index_is_temporary.rs:17:21: 17:24
|
||||||
// + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
|
// + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// Retagging (from Stacked Borrows) relies on the array index being a fresh
|
// Retagging (from Stacked Borrows) relies on the array index being a fresh
|
||||||
// temporary, so that side-effects cannot change it.
|
// temporary, so that side-effects cannot change it.
|
||||||
// Test that this is indeed the case.
|
// Test that this is indeed the case.
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() -> () {
|
||||||
bb0: {
|
bb0: {
|
||||||
StorageLive(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
StorageLive(_1); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
||||||
_1 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
_1 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
||||||
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate]; // scope 1 at $DIR/asm_unwind_panic_abort.rs:+2:9: +2:49
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
@ -17,8 +17,4 @@ fn main() -> () {
|
||||||
_0 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+1:5: +3:6
|
_0 = const (); // scope 1 at $DIR/asm_unwind_panic_abort.rs:+1:5: +3:6
|
||||||
return; // scope 0 at $DIR/asm_unwind_panic_abort.rs:+4:2: +4:2
|
return; // scope 0 at $DIR/asm_unwind_panic_abort.rs:+4:2: +4:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2 (cleanup): {
|
|
||||||
abort; // scope 0 at $DIR/asm_unwind_panic_abort.rs:+0:1: +4:2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
bb2 (cleanup): {
|
bb2 (cleanup): {
|
||||||
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
|
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
|
||||||
drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
|
drop(_6) -> [return: bb6, unwind terminate]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
|
@ -70,16 +70,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6 (cleanup): {
|
bb6 (cleanup): {
|
||||||
drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
|
drop(_5) -> [return: bb7, unwind terminate]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7 (cleanup): {
|
bb7 (cleanup): {
|
||||||
- drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
- drop(_4) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
||||||
+ goto -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
+ goto -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8 (cleanup): {
|
bb8 (cleanup): {
|
||||||
resume; // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
|
resume; // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bb9 (cleanup): {
|
||||||
|
+ unreachable; // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ fn main() -> () {
|
||||||
|
|
||||||
bb2 (cleanup): {
|
bb2 (cleanup): {
|
||||||
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
|
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
|
||||||
drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
|
drop(_6) -> [return: bb6, unwind terminate]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
|
@ -73,11 +73,11 @@ fn main() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6 (cleanup): {
|
bb6 (cleanup): {
|
||||||
drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
|
drop(_5) -> [return: bb7, unwind terminate]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7 (cleanup): {
|
bb7 (cleanup): {
|
||||||
drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
drop(_4) -> [return: bb8, unwind terminate]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8 (cleanup): {
|
bb8 (cleanup): {
|
||||||
|
|
|
@ -63,15 +63,15 @@ fn main() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6 (cleanup): {
|
bb6 (cleanup): {
|
||||||
drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:+3:11: +3:12
|
drop(_7) -> [return: bb7, unwind terminate]; // scope 1 at $DIR/box_expr.rs:+3:11: +3:12
|
||||||
}
|
}
|
||||||
|
|
||||||
bb7 (cleanup): {
|
bb7 (cleanup): {
|
||||||
drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:+4:1: +4:2
|
drop(_1) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/box_expr.rs:+4:1: +4:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb8 (cleanup): {
|
bb8 (cleanup): {
|
||||||
drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:+2:22: +2:23
|
drop(_5) -> [return: bb9, unwind terminate]; // scope 0 at $DIR/box_expr.rs:+2:22: +2:23
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9 (cleanup): {
|
bb9 (cleanup): {
|
||||||
|
|
|
@ -98,14 +98,14 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
StorageLive(_3); // scope 0 at $DIR/async_await.rs:+1:5: +1:14
|
StorageLive(_3); // scope 0 at $DIR/async_await.rs:+1:5: +1:14
|
||||||
StorageLive(_4); // scope 0 at $DIR/async_await.rs:+1:8: +1:14
|
StorageLive(_4); // scope 0 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
StorageLive(_5); // scope 0 at $DIR/async_await.rs:+1:5: +1:8
|
StorageLive(_5); // scope 0 at $DIR/async_await.rs:+1:5: +1:8
|
||||||
_5 = a() -> bb2; // scope 0 at $DIR/async_await.rs:+1:5: +1:8
|
_5 = a() -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+1:5: +1:8
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:15:5: 15:6
|
// + span: $DIR/async_await.rs:15:5: 15:6
|
||||||
// + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
_4 = <impl Future<Output = ()> as IntoFuture>::into_future(move _5) -> bb3; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
|
_4 = <impl Future<Output = ()> as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:15:8: 15:14
|
// + span: $DIR/async_await.rs:15:8: 15:14
|
||||||
// + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
|
||||||
|
@ -126,7 +126,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
StorageLive(_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
StorageLive(_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
_12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future<Output = ()>); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
_12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#3).0: impl std::future::Future<Output = ()>); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
_11 = &mut (*_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
_11 = &mut (*_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
_10 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _11) -> bb5; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
_10 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:15:8: 15:14
|
// + span: $DIR/async_await.rs:15:8: 15:14
|
||||||
// + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
|
// + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
|
||||||
|
@ -145,7 +145,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
bb6: {
|
bb6: {
|
||||||
_13 = &mut (*_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14
|
_13 = &mut (*_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14
|
||||||
StorageDead(_15); // scope 2 at $DIR/async_await.rs:+1:13: +1:14
|
StorageDead(_15); // scope 2 at $DIR/async_await.rs:+1:13: +1:14
|
||||||
_9 = <impl Future<Output = ()> as Future>::poll(move _10, move _13) -> bb7; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
_9 = <impl Future<Output = ()> as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:15:8: 15:14
|
// + span: $DIR/async_await.rs:15:8: 15:14
|
||||||
// + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
|
// + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
|
||||||
|
@ -206,14 +206,14 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
StorageDead(_3); // scope 0 at $DIR/async_await.rs:+1:14: +1:15
|
StorageDead(_3); // scope 0 at $DIR/async_await.rs:+1:14: +1:15
|
||||||
StorageLive(_21); // scope 0 at $DIR/async_await.rs:+2:8: +2:14
|
StorageLive(_21); // scope 0 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
StorageLive(_22); // scope 0 at $DIR/async_await.rs:+2:5: +2:8
|
StorageLive(_22); // scope 0 at $DIR/async_await.rs:+2:5: +2:8
|
||||||
_22 = a() -> bb14; // scope 0 at $DIR/async_await.rs:+2:5: +2:8
|
_22 = a() -> [return: bb14, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+2:5: +2:8
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:16:5: 16:6
|
// + span: $DIR/async_await.rs:16:5: 16:6
|
||||||
// + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn() -> impl Future<Output = ()> {a}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
bb14: {
|
bb14: {
|
||||||
_21 = <impl Future<Output = ()> as IntoFuture>::into_future(move _22) -> bb15; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
|
_21 = <impl Future<Output = ()> as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; // scope 0 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:16:8: 16:14
|
// + span: $DIR/async_await.rs:16:8: 16:14
|
||||||
// + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn(impl Future<Output = ()>) -> <impl Future<Output = ()> as IntoFuture>::IntoFuture {<impl Future<Output = ()> as IntoFuture>::into_future}, val: Value(<ZST>) }
|
||||||
|
@ -234,7 +234,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
StorageLive(_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
StorageLive(_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
_28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future<Output = ()>); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
_28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:14:18: 17:2])) as variant#4).0: impl std::future::Future<Output = ()>); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
_27 = &mut (*_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
_27 = &mut (*_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
_26 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _27) -> bb17; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
_26 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:16:8: 16:14
|
// + span: $DIR/async_await.rs:16:8: 16:14
|
||||||
// + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
|
// + literal: Const { ty: unsafe fn(&mut impl Future<Output = ()>) -> Pin<&mut impl Future<Output = ()>> {Pin::<&mut impl Future<Output = ()>>::new_unchecked}, val: Value(<ZST>) }
|
||||||
|
@ -253,7 +253,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
|
||||||
bb18: {
|
bb18: {
|
||||||
_29 = &mut (*_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14
|
_29 = &mut (*_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14
|
||||||
StorageDead(_31); // scope 5 at $DIR/async_await.rs:+2:13: +2:14
|
StorageDead(_31); // scope 5 at $DIR/async_await.rs:+2:13: +2:14
|
||||||
_25 = <impl Future<Output = ()> as Future>::poll(move _26, move _29) -> bb19; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
_25 = <impl Future<Output = ()> as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/async_await.rs:16:8: 16:14
|
// + span: $DIR/async_await.rs:16:8: 16:14
|
||||||
// + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
|
// + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future<Output = ()>>, &'b mut Context<'c>) -> Poll<<impl Future<Output = ()> as Future>::Output> {<impl Future<Output = ()> as Future>::poll}, val: Value(<ZST>) }
|
||||||
|
|
|
@ -63,7 +63,7 @@ fn droppy() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4 (cleanup): {
|
bb4 (cleanup): {
|
||||||
drop(_2) -> bb5; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
|
drop(_2) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb5 (cleanup): {
|
bb5 (cleanup): {
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn main() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
|
falseUnwind -> [real: bb2, unwind: bb11]; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
|
|
|
@ -95,15 +95,15 @@ fn move_out_by_subslice() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9 (cleanup): {
|
bb9 (cleanup): {
|
||||||
drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
|
drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb10 (cleanup): {
|
bb10 (cleanup): {
|
||||||
drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
drop(_7) -> [return: bb11, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb11 (cleanup): {
|
bb11 (cleanup): {
|
||||||
drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb12 (cleanup): {
|
bb12 (cleanup): {
|
||||||
|
|
|
@ -95,15 +95,15 @@ fn move_out_from_end() -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb9 (cleanup): {
|
bb9 (cleanup): {
|
||||||
drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
|
drop(_1) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+8:1: +8:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb10 (cleanup): {
|
bb10 (cleanup): {
|
||||||
drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
drop(_7) -> [return: bb11, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb11 (cleanup): {
|
bb11 (cleanup): {
|
||||||
drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
drop(_2) -> [return: bb12, unwind terminate]; // scope 0 at $DIR/uniform_array_move_out.rs:+6:5: +6:6
|
||||||
}
|
}
|
||||||
|
|
||||||
bb12 (cleanup): {
|
bb12 (cleanup): {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: InstCombine
|
// unit-test: InstCombine
|
||||||
// EMIT_MIR combine_array_len.norm2.InstCombine.diff
|
// EMIT_MIR combine_array_len.norm2.InstCombine.diff
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4 (cleanup): {
|
bb4 (cleanup): {
|
||||||
drop(_2) -> bb5; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
|
drop(_2) -> [return: bb5, unwind terminate]; // scope 0 at $DIR/combine_clone_of_primitives.rs:+0:14: +0:15
|
||||||
}
|
}
|
||||||
|
|
||||||
bb5 (cleanup): {
|
bb5 (cleanup): {
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
StorageDead(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:47: +11:48
|
StorageDead(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:47: +11:48
|
||||||
StorageLive(_23); // scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11
|
StorageLive(_23); // scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11
|
||||||
StorageLive(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
|
StorageLive(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
|
||||||
_24 = MaybeUninit::<String>::uninit() -> bb1; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
|
_24 = MaybeUninit::<String>::uninit() -> [return: bb1, unwind unreachable]; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/combine_transmutes.rs:46:46: 46:75
|
// + span: $DIR/combine_transmutes.rs:46:46: 46:75
|
||||||
// + user_ty: UserType(23)
|
// + user_ty: UserType(23)
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
+ _1 = const 1_i32; // scope 0 at $DIR/combine_transmutes.rs:+2:14: +2:38
|
+ _1 = const 1_i32; // scope 0 at $DIR/combine_transmutes.rs:+2:14: +2:38
|
||||||
StorageLive(_2); // scope 1 at $DIR/combine_transmutes.rs:+3:9: +3:11
|
StorageLive(_2); // scope 1 at $DIR/combine_transmutes.rs:+3:9: +3:11
|
||||||
StorageLive(_3); // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
|
StorageLive(_3); // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
|
||||||
_3 = Vec::<i32>::new() -> bb1; // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
|
_3 = Vec::<i32>::new() -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/combine_transmutes.rs:+3:46: +3:56
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/combine_transmutes.rs:15:46: 15:54
|
// + span: $DIR/combine_transmutes.rs:15:46: 15:54
|
||||||
// + user_ty: UserType(0)
|
// + user_ty: UserType(0)
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
+ _2 = move _3; // scope 1 at $DIR/combine_transmutes.rs:+3:14: +3:57
|
+ _2 = move _3; // scope 1 at $DIR/combine_transmutes.rs:+3:14: +3:57
|
||||||
StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+3:56: +3:57
|
StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+3:56: +3:57
|
||||||
_0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:37: +4:2
|
_0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:37: +4:2
|
||||||
drop(_2) -> bb2; // scope 1 at $DIR/combine_transmutes.rs:+4:1: +4:2
|
drop(_2) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/combine_transmutes.rs:+4:1: +4:2
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
bb2: {
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
+ _5 = const 1_u8; // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
|
+ _5 = const 1_u8; // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
|
||||||
_4 = foo(move _5) -> bb1; // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
|
_4 = foo(move _5) -> bb1; // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/aggregate.rs:8:5: 8:8
|
// + span: $DIR/aggregate.rs:9:5: 9:8
|
||||||
// + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ fn main() -> () {
|
||||||
_5 = const 1_u8; // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
|
_5 = const 1_u8; // scope 1 at $DIR/aggregate.rs:+2:9: +2:10
|
||||||
_4 = foo(move _5) -> bb1; // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
|
_4 = foo(move _5) -> bb1; // scope 1 at $DIR/aggregate.rs:+2:5: +2:11
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/aggregate.rs:8:5: 8:8
|
// + span: $DIR/aggregate.rs:9:5: 9:8
|
||||||
// + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn(u8) {foo}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: ConstProp
|
// unit-test: ConstProp
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: ConstProp
|
// unit-test: ConstProp
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: ConstProp
|
// unit-test: ConstProp
|
||||||
// EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
|
// EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
|
// EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
|
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
|
||||||
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
|
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
|
||||||
_2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
StorageLive(_2); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_8 = const _; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
|
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
|
||||||
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
|
// + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
|
||||||
_2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_2 = &raw const (*_8); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
// EMIT_MIR_FOR_EACH_BIT_WIDTH
|
||||||
// EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
|
// EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
|
||||||
#[allow(unconditional_panic)]
|
#[allow(unconditional_panic)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: ConstProp
|
// unit-test: ConstProp
|
||||||
// compile-flags: -C overflow-checks=on
|
// compile-flags: -C overflow-checks=on
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
||||||
_3 = const _; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
_3 = const _; // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/const_prop_fails_gracefully.rs:8:13: 8:16
|
// + span: $DIR/const_prop_fails_gracefully.rs:9:13: 9:16
|
||||||
// + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
|
// + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
|
||||||
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:16
|
||||||
_1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39
|
_1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:+2:13: +2:39
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
_5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11
|
_5 = _1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:10: +3:11
|
||||||
_4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12
|
_4 = read(move _5) -> bb1; // scope 1 at $DIR/const_prop_fails_gracefully.rs:+3:5: +3:12
|
||||||
// mir::Constant
|
// mir::Constant
|
||||||
// + span: $DIR/const_prop_fails_gracefully.rs:9:5: 9:9
|
// + span: $DIR/const_prop_fails_gracefully.rs:10:5: 10:9
|
||||||
// + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) }
|
// + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-wasm32 compiled with panic=abort by default
|
||||||
// unit-test: ConstProp
|
// unit-test: ConstProp
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn read(_: usize) { }
|
fn read(_: usize) { }
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue