diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 811e32e747dfd..2e157ac8743f4 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -70,6 +70,7 @@
 #![feature(lang_items, unsafe_destructor)]
 #![feature(box_syntax)]
 #![feature(optin_builtin_traits)]
+#![feature(unwinding_attributes)]
 #![allow(unknown_features)] #![feature(int_uint)]
 
 #[macro_use]
@@ -97,6 +98,7 @@ pub mod rc;
 /// Common out-of-memory routine
 #[cold]
 #[inline(never)]
+#[unsafe_no_unwind]
 pub fn oom() -> ! {
     // FIXME(#14674): This really needs to do something other than just abort
     //                here, but any printing done must be *guaranteed* to not
diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs
index 61b4284e1dd9c..10b022b2e7cc5 100644
--- a/src/libcore/panicking.rs
+++ b/src/libcore/panicking.rs
@@ -51,7 +51,7 @@ fn panic_bounds_check(file_line: &(&'static str, uint),
 pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
     #[allow(improper_ctypes)]
     extern {
-        #[lang = "panic_fmt"]
+        #[lang = "panic_fmt"] #[can_unwind]
         fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: uint) -> !;
     }
     let (file, line) = *file_line;
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 8a27cfc510f4a..3ce82a167213d 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -653,6 +653,8 @@ impl LintPass for UnusedAttributes {
             "no_debug",
             "omit_gdb_pretty_printer_section",
             "unsafe_no_drop_flag",
+            "can_unwind",
+            "unsafe_no_unwind",
 
             // used in resolve
             "prelude_import",
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index eed61ae59a259..35a2f98cdde60 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -56,7 +56,7 @@ use trans::cleanup;
 use trans::closure;
 use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_integral};
 use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
-use trans::common::{CrateContext, ExternMap, FunctionContext};
+use trans::common::{CrateContext, ExprId, ExternMap, FunctionContext};
 use trans::common::{NodeInfo, Result};
 use trans::common::{node_id_type, return_type_is_void};
 use trans::common::{tydesc_info, type_is_immediate};
@@ -431,11 +431,6 @@ pub fn set_no_inline(f: ValueRef) {
     llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute)
 }
 
-#[allow(dead_code)] // useful
-pub fn set_no_unwind(f: ValueRef) {
-    llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute)
-}
-
 // Tell LLVM to emit the information necessary to unwind the stack for the
 // function f.
 pub fn set_uwtable(f: ValueRef) {
@@ -470,6 +465,7 @@ pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: Val
                                                llvm::FunctionIndex as c_uint,
                                                llvm::ColdAttribute as uint64_t)
             },
+            "unsafe_no_unwind" => llvm::SetFunctionAttribute(llfn, llvm::NoUnwindAttribute),
             _ => used = false,
         }
         if used {
@@ -941,9 +937,12 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 RustIntrinsic => {
                     ccx.sess().bug("unexpected intrinsic in trans_external_path")
                 }
-                _ => {
-                    foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
-                                                      &name[])
+                abi => {
+                    let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
+                    let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
+                                                                 &name[]);
+                    foreign::add_abi_attributes(ccx, llfn, abi, &attrs[]);
+                    llfn
                 }
             }
         }
@@ -1011,6 +1010,37 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
+pub fn get_eh_personality<'a, 'tcx>(ccx: &CrateContext<'a,'tcx>) -> ValueRef {
+    // The exception handling personality function.
+    //
+    // If our compilation unit has the `eh_personality` lang item somewhere
+    // within it, then we just need to translate that. Otherwise, we're
+    // building an rlib which will depend on some upstream implementation of
+    // this function, so we just codegen a generic reference to it. We don't
+    // specify any of the types for the function, we just make it a symbol
+    // that LLVM can later use.
+    match ccx.tcx().lang_items.eh_personality() {
+        Some(def_id) => {
+            callee::trans_fn_ref(ccx, def_id, ExprId(0), &Substs::trans_empty()).val
+        }
+        None => {
+            let mut personality = ccx.eh_personality().borrow_mut();
+            match *personality {
+                Some(llpersonality) => llpersonality,
+                None => {
+                    let fty = Type::variadic_func(&[], &Type::i32(ccx));
+                    let f = decl_cdecl_fn(ccx,
+                                          "rust_eh_personality",
+                                          fty,
+                                          ccx.tcx().types.i32);
+                    *personality = Some(f);
+                    f
+                }
+            }
+        }
+    }
+}
+
 pub fn need_invoke(bcx: Block) -> bool {
     if bcx.sess().no_landing_pads() {
         return false;
@@ -2870,7 +2900,10 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
                     let abi = ccx.tcx().map.get_foreign_abi(id);
                     let ty = ty::node_id_to_type(ccx.tcx(), ni.id);
                     let name = foreign::link_name(&*ni);
-                    foreign::register_foreign_item_fn(ccx, abi, ty, &name.get()[])
+                    let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name.get()[]);
+                    // FIXME(aatch) Re-enable pending RFC
+                    //foreign::add_abi_attributes(ccx, llfn, abi, &ni.attrs[]);
+                    llfn
                 }
                 ast::ForeignItemStatic(..) => {
                     foreign::register_static(ccx, &*ni)
diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs
index 1f77f625c9db3..37d6a82da671a 100644
--- a/src/librustc_trans/trans/build.rs
+++ b/src/librustc_trans/trans/build.rs
@@ -126,6 +126,25 @@ pub fn Invoke(cx: Block,
     B(cx).invoke(fn_, args, then, catch, attributes)
 }
 
+pub fn InvokeWithConv(cx: Block,
+                      fn_: ValueRef,
+                      args: &[ValueRef],
+                      then: BasicBlockRef,
+                      catch: BasicBlockRef,
+                      conv: CallConv,
+                      attributes: Option<AttrBuilder>)
+                      -> ValueRef {
+    if cx.unreachable.get() {
+        return C_null(Type::i8(cx.ccx()));
+    }
+    check_not_terminated(cx);
+    terminate(cx, "InvokeWithConv");
+    debug!("InvokeWithConv({} with arguments ({}))",
+           cx.val_to_string(fn_),
+           args.iter().map(|a| cx.val_to_string(*a)).collect::<Vec<String>>().connect(", "));
+    B(cx).invoke_with_conv(fn_, args, then, catch, conv, attributes)
+}
+
 pub fn Unreachable(cx: Block) {
     if cx.unreachable.get() {
         return
diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs
index 187b3e2cf2188..1a96345dfd814 100644
--- a/src/librustc_trans/trans/builder.rs
+++ b/src/librustc_trans/trans/builder.rs
@@ -184,6 +184,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    pub fn invoke_with_conv(&self,
+                            llfn: ValueRef,
+                            args: &[ValueRef],
+                            then: BasicBlockRef,
+                            catch: BasicBlockRef,
+                            conv: CallConv,
+                            attributes: Option<AttrBuilder>)
+                            -> ValueRef {
+        self.count_insn("invokewithconv");
+
+        debug!("Invoke {} with args ({})",
+               self.ccx.tn().val_to_string(llfn),
+               args.iter()
+                   .map(|&v| self.ccx.tn().val_to_string(v))
+                   .collect::<Vec<String>>()
+                   .connect(", "));
+
+        unsafe {
+            let v = llvm::LLVMBuildInvoke(self.llbuilder,
+                                          llfn,
+                                          args.as_ptr(),
+                                          args.len() as c_uint,
+                                          then,
+                                          catch,
+                                          noname());
+            match attributes {
+                Some(a) => a.apply_callsite(v),
+                None => {}
+            }
+            llvm::SetInstructionCallConv(v, conv);
+            v
+        }
+    }
+
     pub fn unreachable(&self) {
         self.count_insn("unreachable");
         unsafe {
@@ -952,6 +986,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
+        self.count_insn("addclause");
+        unsafe {
+            llvm::LLVMAddClause(landing_pad, clause);
+        }
+    }
+
     pub fn resume(&self, exn: ValueRef) -> ValueRef {
         self.count_insn("resume");
         unsafe {
diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs
index 5658889aaf368..f94d7721bc5de 100644
--- a/src/librustc_trans/trans/cleanup.rs
+++ b/src/librustc_trans/trans/cleanup.rs
@@ -19,9 +19,8 @@ pub use self::Heap::*;
 use llvm::{BasicBlockRef, ValueRef};
 use trans::base;
 use trans::build;
-use trans::callee;
 use trans::common;
-use trans::common::{Block, FunctionContext, ExprId, NodeInfo};
+use trans::common::{Block, FunctionContext, NodeInfo};
 use trans::debuginfo;
 use trans::glue;
 use middle::region;
@@ -715,35 +714,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
                                     &[Type::i8p(self.ccx), Type::i32(self.ccx)],
                                     false);
 
-        // The exception handling personality function.
-        //
-        // If our compilation unit has the `eh_personality` lang item somewhere
-        // within it, then we just need to translate that. Otherwise, we're
-        // building an rlib which will depend on some upstream implementation of
-        // this function, so we just codegen a generic reference to it. We don't
-        // specify any of the types for the function, we just make it a symbol
-        // that LLVM can later use.
-        let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
-            Some(def_id) => {
-                callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
-                                     pad_bcx.fcx.param_substs).val
-            }
-            None => {
-                let mut personality = self.ccx.eh_personality().borrow_mut();
-                match *personality {
-                    Some(llpersonality) => llpersonality,
-                    None => {
-                        let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
-                        let f = base::decl_cdecl_fn(self.ccx,
-                                                    "rust_eh_personality",
-                                                    fty,
-                                                    self.ccx.tcx().types.i32);
-                        *personality = Some(f);
-                        f
-                    }
-                }
-            }
-        };
+        let llpersonality = base::get_eh_personality(pad_bcx.ccx());
 
         // The only landing pad clause will be 'cleanup'
         let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index c989d2311be36..e9053a3537acb 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -17,6 +17,7 @@ use trans::base::{llvm_linkage_by_name, push_ctxt};
 use trans::base;
 use trans::build::*;
 use trans::cabi;
+use trans::cleanup::CleanupMethods;
 use trans::common::*;
 use trans::machine;
 use trans::monomorphize;
@@ -366,11 +367,27 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         arg_idx += 1;
     }
 
-    let llforeign_retval = CallWithConv(bcx,
-                                        llfn,
-                                        &llargs_foreign[],
-                                        cc,
-                                        Some(attrs));
+    // Foreign functions *can* unwind, albeit rarely, so use invoke instead of call.
+    // We shouldn't really be emitting an invoke all the time, LLVM can optimise them
+    // out, but we should be able avoid it most of the time
+    let (llforeign_retval, bcx) = if base::need_invoke(bcx) {
+        let normal_bcx = bcx.fcx.new_temp_block("normal-return");
+        let landing_pad = bcx.fcx.get_landing_pad();
+
+        let ret = InvokeWithConv(bcx, llfn, &llargs_foreign[],
+                                 normal_bcx.llbb,
+                                 landing_pad,
+                                 cc,
+                                 Some(attrs));
+        (ret, normal_bcx)
+    } else {
+        let ret = CallWithConv(bcx,
+                               llfn,
+                               &llargs_foreign[],
+                               cc,
+                               Some(attrs));
+        (ret, bcx)
+    };
 
     // If the function we just called does not use an outpointer,
     // store the result into the rust outpointer. Cast the outpointer
@@ -460,6 +477,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
             match foreign_mod.abi {
                 Rust | RustIntrinsic => {}
                 abi => {
+
                     let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
                     match ty.sty {
                         ty::ty_bare_fn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft),
@@ -467,8 +485,11 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
                                                      "foreign fn's sty isn't a bare_fn_ty?")
                     }
 
-                    register_foreign_item_fn(ccx, abi, ty,
-                                             &lname.get()[]);
+                    let llfn = register_foreign_item_fn(ccx, abi, ty,
+                                                        &lname.get()[]);
+
+                    add_abi_attributes(ccx, llfn, abi, &foreign_item.attrs[]);
+
                     // Unlike for other items, we shouldn't call
                     // `base::update_linkage` here.  Foreign items have
                     // special linkage requirements, which are handled
@@ -568,7 +589,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
 
         // Build up the foreign wrapper (`foo` above).
-        return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
+        return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty, attrs);
     }
 
     fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@@ -618,7 +639,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                       llrustfn: ValueRef,
                                       llwrapfn: ValueRef,
                                       tys: &ForeignTypes<'tcx>,
-                                      t: Ty<'tcx>) {
+                                      t: Ty<'tcx>, _attrs: &[ast::Attribute]) {
         let _icx = push_ctxt(
             "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
         let tcx = ccx.tcx();
@@ -635,11 +656,19 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         //
         //     S foo(T i) {
         //         S r;
-        //         foo0(&r, NULL, i);
+        //         try {
+        //           foo0(&r, NULL, i);
+        //         } catch (..) {
+        //           abort();
+        //         }
         //         return r;
         //     }
+        //
+        // Because we mark extern "C" functions as nounwind, we need to
+        // enforce this for Rust functions that have a non-rust ABI. Hence
+        // the try-catch we emulate below.
 
-        let ptr = "the block\0".as_ptr();
+        let ptr = "entry\0".as_ptr();
         let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn,
                                                             ptr as *const _);
 
@@ -787,6 +816,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // Perform the call itself
         debug!("calling llrustfn = {}, t = {}",
                ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx()));
+        // FIXME(aatch) Wrap the call in a try-catch and handle unwinding
+        //              pending RFC
         let attributes = base::get_fn_llvm_attributes(ccx, t);
         let llrust_ret_val = builder.call(llrustfn, llrust_args.as_slice(), Some(attributes));
 
@@ -1004,3 +1035,15 @@ fn add_argument_attributes(tys: &ForeignTypes,
         i += 1;
     }
 }
+
+pub fn add_abi_attributes(ccx: &CrateContext, llfn: ValueRef, abi: Abi, attrs: &[ast::Attribute]) {
+
+    match ccx.sess().target.target.adjust_abi(abi) {
+        Rust | RustCall | RustIntrinsic => {}
+        _ => {
+            if !attr::contains_name(attrs, "can_unwind") {
+                llvm::SetFunctionAttribute(llfn, llvm::NoUnwindAttribute);
+            }
+        }
+    }
+}
diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs
index f52e7c0ec94c0..03cc1c0f9504c 100644
--- a/src/librustc_trans/trans/monomorphize.rs
+++ b/src/librustc_trans/trans/monomorphize.rs
@@ -181,7 +181,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                   if needs_body {
                       if abi != abi::Rust {
                           foreign::trans_rust_fn_with_foreign_abi(
-                              ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
+                              ccx, &**decl, &**body, &i.attrs[], d, psubsts, fn_id.node,
                               Some(&hash[]));
                       } else {
                           trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index ddb8129630f75..e21ce66c800b2 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -104,6 +104,7 @@
        html_root_url = "http://doc.rust-lang.org/nightly/",
        html_playground_url = "http://play.rust-lang.org/")]
 
+#![allow(unstable)]
 #![allow(unknown_features)]
 #![feature(linkage, thread_local, asm)]
 #![feature(lang_items, unsafe_destructor)]
@@ -112,8 +113,7 @@
 #![feature(old_impl_check)]
 #![feature(optin_builtin_traits)]
 #![feature(int_uint)]
-#![feature(int_uint)]
-#![allow(unstable)]
+#![feature(unwinding_attributes)]
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs
index dd9923307d6f0..9f83ea5100531 100644
--- a/src/libstd/rt/libunwind.rs
+++ b/src/libstd/rt/libunwind.rs
@@ -113,13 +113,16 @@ 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")))]
+    #[can_unwind]
     pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
                                   -> _Unwind_Reason_Code;
 
     #[cfg(all(target_os = "ios", target_arch = "arm"))]
+    #[can_unwind]
     fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception)
                                    -> _Unwind_Reason_Code;
 
+    #[can_unwind]
     pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
 }
 
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
index 73b8f104c2369..e402d360e14c3 100644
--- a/src/libstd/rt/unwind.rs
+++ b/src/libstd/rt/unwind.rs
@@ -133,6 +133,7 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
         Err(cause.unwrap())
     };
 
+    #[can_unwind]
     extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
         let opt_closure = opt_closure as *mut Option<F>;
         unsafe { (*opt_closure).take().unwrap()(); }
@@ -251,6 +252,7 @@ pub mod eabi {
         }
     }
 
+    #[can_unwind]
     #[no_mangle] // referenced from rust_try.ll
     pub extern "C" fn rust_eh_personality_catch(
         _version: c_int,
@@ -479,7 +481,7 @@ pub mod eabi {
 
 #[cfg(not(test))]
 /// Entry point of panic from the libcore crate.
-#[lang = "panic_fmt"]
+#[lang = "panic_fmt"] #[can_unwind]
 pub extern fn rust_begin_unwind(msg: fmt::Arguments,
                                 file: &'static str, line: uint) -> ! {
     begin_unwind_fmt(msg, &(file, line))
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 13b7944998ad8..bad8746a44855 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -73,6 +73,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     ("box_syntax", Active),
     ("on_unimplemented", Active),
     ("simd_ffi", Active),
+    ("unwinding_attributes", Active),
 
     ("if_let", Accepted),
     ("while_let", Accepted),
@@ -259,6 +260,12 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                 self.gate_feature("on_unimplemented", i.span,
                                   "the `#[rustc_on_unimplemented]` attribute \
                                   is an experimental feature")
+            } else if attr.name() == "can_unwind" {
+                self.gate_feature("unwinding_attributes", i.span,
+                                  "the `#[can_unwind]` attribute is an experimental feature")
+            } else if attr.name() == "unsafe_no_unwind" {
+                self.gate_feature("unwinding_attributes", i.span,
+                                  "the `#[unsafe_no_unwind]` attribute is an experimental feature")
             }
         }
         match i.node {
diff --git a/src/test/compile-fail/feature-gate-unwinding.rs b/src/test/compile-fail/feature-gate-unwinding.rs
new file mode 100644
index 0000000000000..e277c03f203c8
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-unwinding.rs
@@ -0,0 +1,17 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+#[can_unwind]
+extern fn foo() { } //~ ERROR the `#[can_unwind]` attribute is an experimental feature
+
+#[unsafe_no_unwind]
+fn main() {} //~ ERROR the `#[unsafe_no_unwind]` attribute is an experimental feature