From 90c48bed25751f4c171b1555f8114234ca0a81c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 11 Sep 2015 20:07:12 +0200 Subject: [PATCH 1/3] Centralise the handling of attributes on extern functions --- src/librustc_trans/trans/base.rs | 9 ++------- src/librustc_trans/trans/foreign.rs | 7 ++++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f8b60ebdea5..1359252e035 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -677,11 +677,8 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().bug("unexpected intrinsic in trans_external_path") } _ => { - let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, - t, &name); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - attributes::from_fn_attrs(ccx, &attrs, llfn); - llfn + foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs) } } } @@ -2418,9 +2415,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let abi = ccx.tcx().map.get_foreign_abi(id); let ty = ccx.tcx().node_id_to_type(ni.id); let name = foreign::link_name(&*ni); - let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - attributes::from_fn_attrs(ccx, &ni.attrs, llfn); - llfn + foreign::register_foreign_item_fn(ccx, abi, ty, &name, &ni.attrs) } hir::ForeignItemStatic(..) => { foreign::register_static(ccx, &*ni) diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 9781fd037d7..9a561249594 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -187,7 +187,8 @@ pub fn get_extern_fn(ccx: &CrateContext, /// Registers a foreign function found in a library. Just adds a LLVM global. pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, abi: Abi, fty: Ty<'tcx>, - name: &str) -> ValueRef { + name: &str, + attrs: &[hir::Attribute])-> ValueRef { debug!("register_foreign_item_fn(abi={:?}, \ ty={:?}, \ name={})", @@ -211,6 +212,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); add_argument_attributes(&tys, llfn); + attributes::from_fn_attrs(ccx, attrs, llfn); llfn } @@ -489,8 +491,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) { "foreign fn's sty isn't a bare_fn_ty?") } - let llfn = register_foreign_item_fn(ccx, abi, ty, &lname); - attributes::from_fn_attrs(ccx, &foreign_item.attrs, llfn); + register_foreign_item_fn(ccx, abi, ty, &lname, &foreign_item.attrs); // Unlike for other items, we shouldn't call // `base::update_linkage` here. Foreign items have // special linkage requirements, which are handled From e4e67bd489934702e4958a03bb4c948919d38920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 11 Sep 2015 20:09:19 +0200 Subject: [PATCH 2/3] Add an attribute to mark function as unwinding --- src/librustc_trans/trans/attributes.rs | 3 ++- src/libsyntax/feature_gate.rs | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index a1f4ed5c20d..c77cb491448 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -59,7 +59,6 @@ pub fn emit_uwtable(val: ValueRef, emit: bool) { /// Tell LLVM whether the function can or cannot unwind. #[inline] -#[allow(dead_code)] // possibly useful function pub fn unwind(val: ValueRef, can_unwind: bool) { if can_unwind { unsafe { @@ -118,6 +117,8 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[hir::Attribute], llfn: ValueRe } } else if attr.check_name("allocator") { llvm::Attribute::NoAlias.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } else if attr.check_name("unwind") { + unwind(llfn, true); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 47f24856303..abc04102950 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -188,6 +188,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // allow `extern "platform-intrinsic" { ... }` ("platform_intrinsics", "1.4.0", Some(27731), Active), + + // allow `#[unwind]` + ("unwind_attributes", "1.4.0", None, Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -316,6 +319,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag", "unsafe_no_drop_flag has unstable semantics \ and may be removed in the future")), + ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")), // used in resolve ("prelude_import", Whitelisted, Gated("prelude_import", From 3ef75d5774cb9a7cf839a69341c620b98fa9c7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 11 Sep 2015 20:10:43 +0200 Subject: [PATCH 3/3] Mark all extern functions as nounwind Unwinding across an FFI boundary is undefined behaviour, so we can mark all external function as nounwind. The obvious exception are those functions that actually perform the unwinding. --- src/libcore/lib.rs | 1 + src/libcore/panicking.rs | 1 + src/librustc_trans/trans/foreign.rs | 1 + src/libstd/lib.rs | 1 + src/libstd/sys/common/libunwind.rs | 2 ++ src/libstd/sys/common/unwind/mod.rs | 1 + src/libstd/sys/common/unwind/seh.rs | 1 + src/libstd/sys/common/unwind/seh64_gnu.rs | 2 ++ src/test/codegen/extern-functions.rs | 23 +++++++++++++++++++++++ 9 files changed, 33 insertions(+) create mode 100644 src/test/codegen/extern-functions.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 78a467e3657..94408072932 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -79,6 +79,7 @@ #![feature(optin_builtin_traits)] #![feature(reflect)] #![feature(rustc_attrs)] +#![feature(unwind_attributes)] #![cfg_attr(stage0, feature(simd))] #![cfg_attr(not(stage0), feature(repr_simd, platform_intrinsics))] #![feature(staged_api)] diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index b443ae0636f..93ddfa72f63 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -62,6 +62,7 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] + #[unwind] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !; } let (file, line) = *file_line; diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 9a561249594..cbb092aa4eb 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -211,6 +211,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); + attributes::unwind(llfn, false); add_argument_attributes(&tys, llfn); attributes::from_fn_attrs(ccx, attrs, llfn); llfn diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fca4c66112e..dc370d8382a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -243,6 +243,7 @@ #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(decode_utf16)] +#![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(vec_resize)] #![feature(wrapping)] diff --git a/src/libstd/sys/common/libunwind.rs b/src/libstd/sys/common/libunwind.rs index fde612014e9..c6bffb0f733 100644 --- a/src/libstd/sys/common/libunwind.rs +++ b/src/libstd/sys/common/libunwind.rs @@ -124,10 +124,12 @@ extern "C" { // iOS on armv7 uses SjLj exceptions and requires to link // against corresponding routine (..._SjLj_...) #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + #[unwind] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; #[cfg(all(target_os = "ios", target_arch = "arm"))] + #[unwind] fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; diff --git a/src/libstd/sys/common/unwind/mod.rs b/src/libstd/sys/common/unwind/mod.rs index ff93d0526b7..738681c3cfe 100644 --- a/src/libstd/sys/common/unwind/mod.rs +++ b/src/libstd/sys/common/unwind/mod.rs @@ -192,6 +192,7 @@ fn rust_panic(cause: Box) -> ! { #[cfg(not(test))] /// Entry point of panic from the libcore crate. #[lang = "panic_fmt"] +#[unwind] pub extern fn rust_begin_unwind(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { begin_unwind_fmt(msg, &(file, line)) diff --git a/src/libstd/sys/common/unwind/seh.rs b/src/libstd/sys/common/unwind/seh.rs index a201e406a23..a89e8b499ac 100644 --- a/src/libstd/sys/common/unwind/seh.rs +++ b/src/libstd/sys/common/unwind/seh.rs @@ -62,6 +62,7 @@ static PANIC_DATA: StaticKey = StaticKey::new(None); // This function is provided by kernel32.dll extern "system" { + #[unwind] fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, diff --git a/src/libstd/sys/common/unwind/seh64_gnu.rs b/src/libstd/sys/common/unwind/seh64_gnu.rs index 4d23794de24..9478678fda9 100644 --- a/src/libstd/sys/common/unwind/seh64_gnu.rs +++ b/src/libstd/sys/common/unwind/seh64_gnu.rs @@ -93,6 +93,7 @@ pub enum EXCEPTION_DISPOSITION { // From kernel32.dll extern "system" { + #[unwind] fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, @@ -198,6 +199,7 @@ unsafe extern fn rust_eh_personality( #[lang = "eh_unwind_resume"] #[cfg(not(test))] +#[unwind] unsafe extern fn rust_eh_unwind_resume(panic_ctx: LPVOID) { let params = [panic_ctx as ULONG_PTR]; RaiseException(RUST_PANIC, diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs new file mode 100644 index 00000000000..4c30b5ce02f --- /dev/null +++ b/src/test/codegen/extern-functions.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +#![feature(unwind_attributes)] + +extern { +// CHECK: Function Attrs: nounwind +// CHECK-NEXT: declare void @extern_fn + fn extern_fn(); +// CHECK-NOT: Function Attrs: nounwind +// CHECK: declare void @unwinding_extern_fn + #[unwind] + fn unwinding_extern_fn(); +}