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 f8b60ebdea56..1359252e0351 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 9781fd037d75..9a5612495949 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 a1f4ed5c20d3..c77cb4914481 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 47f248563030..abc041029505 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 78a467e36579..94408072932e 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 b443ae0636fa..93ddfa72f63c 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 9a5612495949..cbb092aa4eb3 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 fca4c66112eb..dc370d8382a4 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 fde612014e99..c6bffb0f733e 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 ff93d0526b7e..738681c3cfed 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 a201e406a23e..a89e8b499acc 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 4d23794de244..9478678fda99 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 000000000000..4c30b5ce02f4 --- /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(); +}