about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-07-27 23:05:48 +0000
committerbors <bors@rust-lang.org>2025-07-27 23:05:48 +0000
commit2b5e239c6b86cde974b0ef0f8e23754fb08ff3c5 (patch)
treede89cecf7dc22a8aef5a0e27d1d173a1a5c3cee7
parentf8e355c230c6eb7b78ffce6a92fd81f78c890524 (diff)
parent17519aeaef0b4b9c1a6bcb6d558aba4b26d044a8 (diff)
downloadrust-2b5e239c6b86cde974b0ef0f8e23754fb08ff3c5.tar.gz
rust-2b5e239c6b86cde974b0ef0f8e23754fb08ff3c5.zip
Auto merge of #144225 - purplesyringa:unwinding-intrinsics, r=nikic
Don't special-case llvm.* as nounwind

Certain LLVM intrinsics, such as `llvm.wasm.throw`, can unwind. Marking them as nounwind causes us to skip cleanup of locals and optimize out `catch_unwind` under inlining or when `llvm.wasm.throw` is used directly by user code.

The motivation for forcibly marking llvm.* as nounwind is no longer present: most intrinsics are linked as `extern "C"` or other non-unwinding ABIs, so we won't codegen `invoke` for them anyway.

Closes rust-lang/rust#132416.

`@rustbot` label +T-compiler +A-panic
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--library/stdarch/crates/core_arch/src/wasm32/mod.rs10
-rw-r--r--tests/codegen-llvm/wasm_exceptions.rs16
3 files changed, 25 insertions, 10 deletions
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index dd49db26689..3f456fa115a 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -511,15 +511,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         err.emit();
     }
 
-    // Any linkage to LLVM intrinsics for now forcibly marks them all as never
-    // unwinds since LLVM sometimes can't handle codegen which `invoke`s
-    // intrinsic functions.
-    if let Some(name) = &codegen_fn_attrs.link_name
-        && name.as_str().starts_with("llvm.")
-    {
-        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
-    }
-
     if let Some(features) = check_tied_features(
         tcx.sess,
         &codegen_fn_attrs
diff --git a/library/stdarch/crates/core_arch/src/wasm32/mod.rs b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
index 2c4361f1639..60049c73295 100644
--- a/library/stdarch/crates/core_arch/src/wasm32/mod.rs
+++ b/library/stdarch/crates/core_arch/src/wasm32/mod.rs
@@ -191,6 +191,16 @@ unsafe extern "C-unwind" {
 // #[cfg_attr(test, assert_instr(throw, TAG = 0, ptr = core::ptr::null_mut()))]
 #[inline]
 #[unstable(feature = "wasm_exception_handling_intrinsics", issue = "122465")]
+// FIXME: Since this instruction unwinds, `core` built with `-C panic=unwind`
+//        cannot be linked with `-C panic=abort` programs. But that's not
+//        entirely supported anyway, because runtimes without EH support won't
+//        be able to handle `try` blocks in `-C panic=unwind` crates either.
+//        We ship `-C panic=abort` `core`, so this doesn't affect users
+//        directly. Resolving this will likely require patching out both `try`
+//        and `throw` instructions, at which point we can look into whitelisting
+//        this function in the compiler to allow linking.
+//        See https://github.com/rust-lang/rust/issues/118168.
+#[allow(ffi_unwind_calls)]
 pub unsafe fn throw<const TAG: i32>(ptr: *mut u8) -> ! {
     static_assert!(TAG == 0); // LLVM only supports tag 0 == C++ right now.
     wasm_throw(TAG, ptr)
diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs
index 07b8ae6e9d7..796b69b722b 100644
--- a/tests/codegen-llvm/wasm_exceptions.rs
+++ b/tests/codegen-llvm/wasm_exceptions.rs
@@ -2,7 +2,7 @@
 //@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh
 
 #![crate_type = "lib"]
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, wasm_exception_handling_intrinsics)]
 
 extern "C-unwind" {
     fn may_panic();
@@ -57,3 +57,17 @@ pub fn test_rtry() {
     // CHECK: {{.*}} = catchpad within {{.*}} [ptr null]
     // CHECK: catchret
 }
+
+// Make sure the intrinsic is not inferred as nounwind. This is a regression test for #132416.
+// CHECK-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0
+#[no_mangle]
+pub fn test_intrinsic() {
+    let _log_on_drop = LogOnDrop;
+    unsafe {
+        core::arch::wasm32::throw::<0>(core::ptr::null_mut());
+    }
+
+    // CHECK-NOT: call
+    // CHECK: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null)
+    // CHECK: %cleanuppad = cleanuppad within none []
+}