Skip to content

Commit 11af4fc

Browse files
Rollup merge of rust-lang#156554 - guybedford:wasm-use-legacy-eh, r=alexcrichton
Allow user-provided `llvm_args` to override target spec arguments This switches the order in which `-Cllvm-args` is applied between target-spec arguments and user-provided LLVM arguments. This came up in rust-lang#156061, where the target passing `-Cllvm-args=-wasm-use-legacy-eh=false` means that a user passing `-Cllvm-args=-wasm-use-legacy-eh=true` cannot override this value since the LLVM arguments support the last argument overriding the previous, and user arguments were chained first. With this change, it is possible for Wasm targets to opt into legacy EH for compatibility with runtimes that don't yet implement the modern exnref/try_table instructions, such as Node.js 20 on V8 11.3 and older browsers. While Node.js 20 is formally EOL, many libraries will still need to support this version for a few months yet, so this would ease the transition path to modern exception handling having an opt-out. Originally this PR added support for a dedicated `-Z` flag for switching to legacy exception handling, but fine-grained control over the arguments would be a preferable solution provided it does not conflict with other behaviours. //cc @alexcrichton
2 parents a29e5e1 + 45adab8 commit 11af4fc

2 files changed

Lines changed: 84 additions & 1 deletion

File tree

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ unsafe fn configure_llvm(sess: &Session) {
6666

6767
let cg_opts = sess.opts.cg.llvm_args.iter().map(AsRef::as_ref);
6868
let tg_opts = sess.target.llvm_args.iter().map(AsRef::as_ref);
69-
let sess_args = cg_opts.chain(tg_opts);
69+
// Target-spec args are passed to LLVM before user `-Cllvm-args`. LLVM's
70+
// `cl::opt` parser is last-wins, so this lets `-Cllvm-args=...` override
71+
// a value already set in the target spec (e.g. `-wasm-use-legacy-eh`).
72+
let sess_args = tg_opts.chain(cg_opts);
7073

7174
let user_specified_args: FxHashSet<_> =
7275
sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//@ only-wasm32
2+
//@ assembly-output: emit-asm
3+
//@ compile-flags: -C target-feature=+exception-handling
4+
//@ compile-flags: -C panic=unwind
5+
//@ compile-flags: -C llvm-args=-wasm-use-legacy-eh=true
6+
7+
// Verifies that user-supplied `-Cllvm-args` can override an LLVM argument that
8+
// was set in the target spec. The `wasm32-unknown-unknown` target spec pins
9+
// `-wasm-use-legacy-eh=false`; this test asserts that passing the opposite
10+
// value via `-Cllvm-args` switches code generation back to the legacy
11+
// exception-handling instructions.
12+
13+
#![crate_type = "lib"]
14+
#![feature(core_intrinsics)]
15+
16+
extern "C-unwind" {
17+
fn may_panic();
18+
}
19+
20+
extern "C" {
21+
fn log_number(number: usize);
22+
}
23+
24+
struct LogOnDrop;
25+
26+
impl Drop for LogOnDrop {
27+
fn drop(&mut self) {
28+
unsafe {
29+
log_number(0);
30+
}
31+
}
32+
}
33+
34+
// CHECK-LABEL: test_cleanup:
35+
#[no_mangle]
36+
pub fn test_cleanup() {
37+
let _log_on_drop = LogOnDrop;
38+
unsafe {
39+
may_panic();
40+
}
41+
42+
// CHECK-NOT: try_table
43+
// CHECK-NOT: catch_all_ref
44+
// CHECK-NOT: throw_ref
45+
// CHECK-NOT: call
46+
// CHECK: try
47+
// CHECK: call may_panic
48+
// CHECK: catch_all
49+
// CHECK: rethrow
50+
// CHECK: end_try
51+
}
52+
53+
// CHECK-LABEL: test_rtry:
54+
#[no_mangle]
55+
pub fn test_rtry() {
56+
unsafe {
57+
core::intrinsics::catch_unwind(
58+
|_| {
59+
may_panic();
60+
},
61+
core::ptr::null_mut(),
62+
|data, exception| {
63+
log_number(data as usize);
64+
log_number(exception as usize);
65+
},
66+
);
67+
}
68+
69+
// CHECK-NOT: try_table
70+
// CHECK-NOT: catch_all_ref
71+
// CHECK-NOT: throw_ref
72+
// CHECK-NOT: call
73+
// CHECK: try
74+
// CHECK: call may_panic
75+
// CHECK: catch
76+
// CHECK: call log_number
77+
// CHECK: call log_number
78+
// CHECK-NOT: rethrow
79+
// CHECK: end_try
80+
}

0 commit comments

Comments
 (0)