Skip to content

Commit b5c8046

Browse files
committed
Generate correct terminate block under Wasm EH
This fixes failing LLVM assertions during insnsel. Partially fixes rust-lang#135665.
1 parent 66d6064 commit b5c8046

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -1703,15 +1703,32 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
17031703
let mut cs_bx = Bx::build(self.cx, llbb);
17041704
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
17051705

1706-
// The "null" here is actually a RTTI type descriptor for the
1707-
// C++ personality function, but `catch (...)` has no type so
1708-
// it's null. The 64 here is actually a bitfield which
1709-
// represents that this is a catch-all block.
17101706
bx = Bx::build(self.cx, cp_llbb);
17111707
let null =
17121708
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
1713-
let sixty_four = bx.const_i32(64);
1714-
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
1709+
1710+
// The `null` in first argument here is actually a RTTI type
1711+
// descriptor for the C++ personality function, but `catch (...)`
1712+
// has no type so it's null.
1713+
let args = if base::wants_msvc_seh(self.cx.sess()) {
1714+
// This bitmask is a single `HT_IsStdDotDot` flag, which
1715+
// represents that this is a C++-style `catch (...)` block that
1716+
// only captures programmatic exceptions, not all SEH
1717+
// exceptions. The second `null` points to a non-existent
1718+
// `alloca` instruction, which an LLVM pass would inline into
1719+
// the initial SEH frame allocation.
1720+
let adjectives = bx.const_i32(0x40);
1721+
&[null, adjectives, null] as &[_]
1722+
} else {
1723+
// Specifying more arguments than necessary usually doesn't
1724+
// hurt, but the `WasmEHPrepare` LLVM pass does not recognize
1725+
// anything other than a single `null` as a `catch (...)` block,
1726+
// leading to problems down the line during instruction
1727+
// selection.
1728+
&[null] as &[_]
1729+
};
1730+
1731+
funclet = Some(bx.catch_pad(cs, args));
17151732
} else {
17161733
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
17171734
bx = Bx::build(self.cx, llbb);

tests/codegen/terminating-catchpad.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ revisions: wasm seh
2+
//@[wasm] compile-flags: --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
3+
//@[seh] compile-flags: --target x86_64-pc-windows-msvc
4+
//@[wasm] needs-llvm-components: webassembly
5+
//@[seh] needs-llvm-components: x86
6+
7+
// Ensure a catch-all generates:
8+
// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused)
9+
// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions)
10+
11+
#![feature(no_core, lang_items, rustc_attrs)]
12+
#![crate_type = "lib"]
13+
#![no_std]
14+
#![no_core]
15+
16+
#[lang = "sized"]
17+
trait Sized {}
18+
19+
unsafe extern "C-unwind" {
20+
safe fn unwinds();
21+
}
22+
23+
#[lang = "panic_cannot_unwind"]
24+
fn panic_cannot_unwind() -> ! {
25+
loop {}
26+
}
27+
28+
#[no_mangle]
29+
#[rustc_nounwind]
30+
pub fn doesnt_unwind() {
31+
// wasm: %catchpad = catchpad within %catchswitch [ptr null]
32+
// seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null]
33+
unwinds();
34+
}

0 commit comments

Comments
 (0)