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/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/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..cbb092aa4eb 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={})", @@ -210,7 +211,9 @@ 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 } @@ -489,8 +492,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 diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 868fef06aa4..774d13966bd 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -242,6 +242,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/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", 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(); +}