diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 3eb0fd95284a..1d6d77604411 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1656,10 +1656,6 @@ fn catch_switch( unimplemented!(); } - fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { - unimplemented!(); - } - // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f3508c10d1f6..4e79e4fafac5 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1297,10 +1297,6 @@ fn catch_switch( ret } - fn get_funclet_cleanuppad(&self, funclet: &Funclet<'ll>) -> &'ll Value { - funclet.cleanuppad() - } - // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index dcbd7f7e7708..1b96be12f71d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -214,18 +214,19 @@ fn do_call>( mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) { - // For wasm, we need to generate a nested `cleanuppad within %outer_pad` - // to catch exceptions during cleanup and call `panic_in_cleanup`. - Some(fx.terminate_block(reason, Some(self.bb))) - } else if fx.mir[self.bb].is_cleanup - && base::wants_new_eh_instructions(fx.cx.tcx().sess) - { + if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) { // MSVC SEH will abort automatically if an exception tries to // propagate out from cleanup. + + // FIXME(@mirkootter): For wasm, we currently do not support terminate during + // cleanup, because this requires a few more changes: The current code + // caches the `terminate_block` for each function; funclet based code - however - + // requires a different terminate_block for each funclet + // Until this is implemented, we just do not unwind inside cleanup blocks + None } else { - Some(fx.terminate_block(reason, None)) + Some(fx.terminate_block(reason)) } } }; @@ -237,7 +238,7 @@ fn do_call>( if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { - self.llbb_with_cleanup(fx, target) + fx.llbb(target) } else { fx.unreachable_block() }; @@ -308,7 +309,7 @@ fn do_inlineasm>( ) -> MergingSucc { let unwind_target = match unwind { mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason, None)), + mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)), mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, }; @@ -316,7 +317,7 @@ fn do_inlineasm>( if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { assert!(unwind_target.is_none()); let ret_llbb = if let Some(target) = destination { - self.llbb_with_cleanup(fx, target) + fx.llbb(target) } else { fx.unreachable_block() }; @@ -333,7 +334,7 @@ fn do_inlineasm>( MergingSucc::False } else if let Some(cleanup) = unwind_target { let ret_llbb = if let Some(target) = destination { - self.llbb_with_cleanup(fx, target) + fx.llbb(target) } else { fx.unreachable_block() }; @@ -1895,39 +1896,8 @@ fn unreachable_block(&mut self) -> Bx::BasicBlock { }) } - fn terminate_block( - &mut self, - reason: UnwindTerminateReason, - outer_catchpad_bb: Option, - ) -> Bx::BasicBlock { - // mb_funclet_bb should be present if and only if the target is wasm and - // we're terminating because of an unwind in a cleanup block. In that - // case we have nested funclets and the inner catch_switch needs to know - // what outer catch_pad it is contained in. - debug_assert!( - outer_catchpad_bb.is_some() - == (base::wants_wasm_eh(self.cx.tcx().sess) - && reason == UnwindTerminateReason::InCleanup) - ); - - // When we aren't in a wasm InCleanup block, there's only one terminate - // block needed so we cache at START_BLOCK index. - let mut cache_bb = mir::START_BLOCK; - // In wasm eh InCleanup, use the outer funclet's cleanup BB as the cache - // key. - if let Some(outer_bb) = outer_catchpad_bb { - let cleanup_kinds = - self.cleanup_kinds.as_ref().expect("cleanup_kinds required for funclets"); - cache_bb = cleanup_kinds[outer_bb] - .funclet_bb(outer_bb) - .expect("funclet_bb should be in a funclet"); - - // Ensure the outer funclet is created first - if self.funclets[cache_bb].is_none() { - self.landing_pad_for(cache_bb); - } - } - if let Some((cached_bb, cached_reason)) = self.terminate_blocks[cache_bb] + fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { + if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason { return cached_bb; @@ -1965,35 +1935,12 @@ fn terminate_block( // cp_terminate: // %cp = catchpad within %cs [null, i32 64, null] // ... - // - // By contrast, on WebAssembly targets, we specifically _do_ want to - // catch foreign exceptions. The situation with MSVC is a - // regrettable hack which we don't want to extend to other targets - // unless necessary. For WebAssembly, to generate catch(...) and - // catch only C++ exception instead of generating a catch_all, we - // need to call the intrinsics @llvm.wasm.get.exception and - // @llvm.wasm.get.ehselector in the catch pad. Since we don't do - // this, we generate a catch_all. We originally got this behavior - // by accident but it luckily matches our intention. 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); - - // For wasm InCleanup blocks, our catch_switch is nested within the - // outer catchpad, so we need to provide it as the parent value to - // catch_switch. - let mut outer_cleanuppad = None; - if outer_catchpad_bb.is_some() { - // Get the outer funclet's catchpad - let outer_funclet = self.funclets[cache_bb] - .as_ref() - .expect("landing_pad_for didn't create funclet"); - outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet)); - } - let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); - let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]); - drop(cs_bx); + let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); bx = Bx::build(self.cx, cp_llbb); let null = @@ -2014,18 +1961,13 @@ fn terminate_block( } else { // Specifying more arguments than necessary usually doesn't // hurt, but the `WasmEHPrepare` LLVM pass does not recognize - // anything other than a single `null` as a `catch_all` block, + // anything other than a single `null` as a `catch (...)` block, // leading to problems down the line during instruction // selection. &[null] as &[_] }; funclet = Some(bx.catch_pad(cs, args)); - // On wasm, if we wanted to generate a catch(...) and only catch C++ - // exceptions, we'd call @llvm.wasm.get.exception and - // @llvm.wasm.get.ehselector selectors here. We want a catch_all so - // we leave them out. This is intentionally diverging from the MSVC - // behavior. } else { llbb = Bx::append_block(self.cx, self.llfn, "terminate"); bx = Bx::build(self.cx, llbb); @@ -2051,7 +1993,7 @@ fn terminate_block( bx.unreachable(); - self.terminate_blocks[cache_bb] = Some((llbb, reason)); + self.terminate_block = Some((llbb, reason)); llbb } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 5c14d6f2c093..93da12107bab 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -90,11 +90,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached unreachable block unreachable_block: Option, - /// Cached terminate upon unwinding block and its reason. For non-wasm - /// targets, there is at most one such block per function, stored at index - /// `START_BLOCK`. For wasm targets, each funclet needs its own terminate - /// block, indexed by the cleanup block that is the funclet's head. - terminate_blocks: IndexVec>, + /// Cached terminate upon unwinding block and its reason + terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, /// A bool flag for each basic block indicating whether it is a cold block. /// A cold block is a block that is unlikely to be executed at runtime. @@ -230,7 +227,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( personality_slot: None, cached_llbbs, unreachable_block: None, - terminate_blocks: IndexVec::from_elem(None, &mir.basic_blocks), + terminate_block: None, cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 05e94b8019f4..2076e2bb2627 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -552,12 +552,12 @@ fn select( fn set_personality_fn(&mut self, personality: Self::Function); - // These are used by everyone except msvc and wasm EH + // These are used by everyone except msvc fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); - // These are used by msvc and wasm EH + // These are used only by msvc fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option); fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; @@ -567,7 +567,6 @@ fn catch_switch( unwind: Option, handlers: &[Self::BasicBlock], ) -> Self::Value; - fn get_funclet_cleanuppad(&self, funclet: &Self::Funclet) -> Self::Value; fn atomic_cmpxchg( &mut self, diff --git a/tests/codegen-llvm/double_panic_wasm.rs b/tests/codegen-llvm/double_panic_wasm.rs deleted file mode 100644 index 1eafe6050380..000000000000 --- a/tests/codegen-llvm/double_panic_wasm.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ compile-flags: -C panic=unwind -Copt-level=0 -//@ needs-unwind -//@ only-wasm32 - -#![crate_type = "lib"] - -// Test that `panic_in_cleanup` is called on webassembly targets when a panic -// occurs in a destructor during unwinding. - -extern "Rust" { - fn may_panic(); -} - -struct PanicOnDrop; - -impl Drop for PanicOnDrop { - fn drop(&mut self) { - unsafe { may_panic() } - } -} - -// CHECK-LABEL: @double_panic -// CHECK: invoke void @may_panic() -// CHECK: invoke void @{{.+}}drop_in_place{{.+}} -// CHECK: unwind label %[[TERMINATE:.*]] -// -// CHECK: [[TERMINATE]]: -// CHECK: call void @{{.*panic_in_cleanup}} -// CHECK: unreachable -#[no_mangle] -pub fn double_panic() { - let _guard = PanicOnDrop; - unsafe { may_panic() } -} diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs index 7c98ea94fdc1..a2ec19871d1f 100644 --- a/tests/codegen-llvm/terminating-catchpad.rs +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -9,10 +9,6 @@ // Ensure a catch-all generates: // - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) // - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) -// -// Unlike on windows, on Wasm, we specifically do want to catch foreign -// exceptions. To catch only C++ exceptions we'd need to call -// @llvm.wasm.get.exception and @llvm.wasm.get.ehselector in the catchpad. #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "lib"] @@ -40,14 +36,8 @@ fn panic_cannot_unwind() -> ! { #[no_mangle] #[rustc_nounwind] pub fn doesnt_unwind() { - // CHECK: catchswitch within none [label %{{.*}}] unwind to caller // emscripten: %catchpad = catchpad within %catchswitch [ptr null] // wasi: %catchpad = catchpad within %catchswitch [ptr null] // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] - // - // We don't call these intrinsics on wasm targets so we generate a catch_all - // instruction which also picks up foreign exceptions - // NOT: @llvm.wasm.get.exception - // NOT: @llvm.wasm.get.ehselector unwinds(); }