]> git.lizzy.rs Git - rust.git/commitdiff
Implement #[alloc_error_handler]
authorSimon Sapin <simon.sapin@exyr.org>
Fri, 6 Jul 2018 13:49:52 +0000 (15:49 +0200)
committerSimon Sapin <simon.sapin@exyr.org>
Mon, 9 Jul 2018 21:13:24 +0000 (23:13 +0200)
This to-be-stable attribute is equivalent to `#[lang = "oom"]`.
It is required when using the alloc crate without the std crate.
It is called by `handle_alloc_error`, which is in turned called
by "infallible" allocations APIs such as `Vec::push`.

16 files changed:
src/libcore/alloc.rs
src/librustc/middle/dead.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/weak_lang_items.rs
src/librustc_typeck/check/mod.rs
src/libstd/alloc.rs
src/libstd/lib.rs
src/libsyntax/feature_gate.rs
src/test/compile-fail/alloc-error-handler-bad-signature-1.rs [new file with mode: 0644]
src/test/compile-fail/alloc-error-handler-bad-signature-2.rs [new file with mode: 0644]
src/test/compile-fail/alloc-error-handler-bad-signature-3.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-alloc-error-handler.rs [new file with mode: 0644]
src/test/run-make-fulldeps/issue-51671/app.rs
src/test/ui/missing-alloc_error_handler.rs [new file with mode: 0644]
src/test/ui/missing-alloc_error_handler.stderr [new file with mode: 0644]
src/test/ui/missing-allocator.rs

index 01221aecb6284651aee6a4bf9189b90ec5ca0281..b6ac248b79f8666331ab77c82d7aa9d311b188ff 100644 (file)
@@ -48,6 +48,7 @@ fn size_align<T>() -> (usize, usize) {
 /// use specific allocators with looser requirements.)
 #[stable(feature = "alloc_layout", since = "1.28.0")]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(not(stage0), lang = "alloc_layout")]
 pub struct Layout {
     // size of the requested block of memory, measured in bytes.
     size_: usize,
index 226d19a91240f3d081670b1f7661e9a90445394b..42775e3a1837ff4f63d1e62fb2185efec8afd8d8 100644 (file)
@@ -288,7 +288,17 @@ fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) {
 fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
                                     id: ast::NodeId,
                                     attrs: &[ast::Attribute]) -> bool {
-    if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") {
+    if attr::contains_name(attrs, "lang") {
+        return true;
+    }
+
+    // (To be) stable attribute for #[lang = "panic_impl"]
+    if attr::contains_name(attrs, "panic_implementation") {
+        return true;
+    }
+
+    // (To be) stable attribute for #[lang = "oom"]
+    if attr::contains_name(attrs, "alloc_error_handler") {
         return true;
     }
 
index fe676919a7d14d23aa08e0050e01869bcfdfb7e2..6c1ef851cbeca6fe4e2abac010e76a84c9602571 100644 (file)
@@ -187,6 +187,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
             }
         } else if attribute.check_name("panic_implementation") {
             return Some((Symbol::intern("panic_impl"), attribute.span))
+        } else if attribute.check_name("alloc_error_handler") {
+            return Some((Symbol::intern("oom"), attribute.span))
         }
     }
 
@@ -308,6 +310,7 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
     BoxFreeFnLangItem,               "box_free",                box_free_fn;
     DropInPlaceFnLangItem,           "drop_in_place",           drop_in_place_fn;
     OomLangItem,                     "oom",                     oom;
+    AllocLayoutLangItem,             "alloc_layout",            alloc_layout;
 
     StartFnLangItem,                 "start",                   start_fn;
 
index 180e75df1a66ec55545fbae6c6f97807c020a132..d8570b43fbe276dc32d86cf4baaa582cb0915da7 100644 (file)
@@ -115,6 +115,9 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             if lang_items::$item == lang_items::PanicImplLangItem {
                 tcx.sess.err(&format!("`#[panic_implementation]` function required, \
                                         but not found"));
+            } else if lang_items::$item == lang_items::OomLangItem {
+                tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
+                                        but not found"));
             } else {
                 tcx.sess.err(&format!("language item required, but not found: `{}`",
                                         stringify!($name)));
index 646c4f17568f05c3aab5e20b309d7ff14c58b7ff..c7ad3398873eabc00e12491b7ad70d74bd629a54 100644 (file)
@@ -1182,7 +1182,54 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                 fcx.tcx.sess.err("language item required, but not found: `panic_info`");
             }
         }
+    }
+
+    // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+    if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() {
+        if alloc_error_handler_did == fcx.tcx.hir.local_def_id(fn_id) {
+            if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() {
+                if declared_ret_ty.sty != ty::TyNever {
+                    fcx.tcx.sess.span_err(
+                        decl.output.span(),
+                        "return type should be `!`",
+                    );
+                }
+
+                let inputs = fn_sig.inputs();
+                let span = fcx.tcx.hir.span(fn_id);
+                if inputs.len() == 1 {
+                    let arg_is_alloc_layout = match inputs[0].sty {
+                        ty::TyAdt(ref adt, _) => {
+                            adt.did == alloc_layout_did
+                        },
+                        _ => false,
+                    };
+
+                    if !arg_is_alloc_layout {
+                        fcx.tcx.sess.span_err(
+                            decl.inputs[0].span,
+                            "argument should be `Layout`",
+                        );
+                    }
 
+                    if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
+                        if let Item_::ItemFn(_, _, ref generics, _) = item.node {
+                            if !generics.params.is_empty() {
+                                fcx.tcx.sess.span_err(
+                                    span,
+                                    "`#[alloc_error_handler]` function should have no type \
+                                     parameters",
+                                );
+                            }
+                        }
+                    }
+                } else {
+                    fcx.tcx.sess.span_err(span, "function should have one argument");
+                }
+            } else {
+                fcx.tcx.sess.err("language item required, but not found: `alloc_layout`");
+            }
+        }
     }
 
     (fcx, gen_ty)
index cfdfbe1357d5ded136b80946476e0cc5391670fd..8db365cd21d67938be2bbca12cfee14a3fded4cd 100644 (file)
@@ -125,7 +125,8 @@ fn default_alloc_error_hook(layout: Layout) {
 
 #[cfg(not(test))]
 #[doc(hidden)]
-#[lang = "oom"]
+#[cfg_attr(stage0, lang = "oom")]
+#[cfg_attr(not(stage0), alloc_error_handler)]
 #[unstable(feature = "alloc_internals", issue = "0")]
 pub fn rust_oom(layout: Layout) -> ! {
     let hook = HOOK.load(Ordering::SeqCst);
index d73cb1f8349a655ca5414a42445b93360bc31cc8..fec14b8d67d359c0322a449439e000878fe99d60 100644 (file)
 // std is implemented with unstable features, many of which are internal
 // compiler details that will never be stable
 #![feature(alloc)]
-#![feature(allocator_api)]
+#![feature(alloc_error_handler)]
 #![feature(alloc_system)]
+#![feature(allocator_api)]
 #![feature(allocator_internals)]
 #![feature(allow_internal_unsafe)]
 #![feature(allow_internal_unstable)]
index cbc421dbd328c281c58b075a89b8073a02542fdd..e70d93ae85a1d1dca16bd4708a03cb80a1b44964 100644 (file)
@@ -481,6 +481,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
 
     // Allows async and await syntax
     (active, async_await, "1.28.0", Some(50547), None),
+
+    // #[alloc_error_handler]
+    (active, alloc_error_handler, "1.29.0", Some(51540), None),
 );
 
 declare_features! (
@@ -1083,6 +1086,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                            "#[panic_implementation] is an unstable feature",
                            cfg_fn!(panic_implementation))),
 
+    ("alloc_error_handler", Normal, Gated(Stability::Unstable,
+                           "alloc_error_handler",
+                           "#[alloc_error_handler] is an unstable feature",
+                           cfg_fn!(alloc_error_handler))),
+
     // Crate level attributes
     ("crate_name", CrateLevel, Ungated),
     ("crate_type", CrateLevel, Ungated),
diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs
new file mode 100644 (file)
index 0000000..e398f16
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2018 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.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler]
+fn oom(
+    info: &Layout, //~ ERROR argument should be `Layout`
+) -> () //~ ERROR return type should be `!`
+{
+    loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs
new file mode 100644 (file)
index 0000000..4fee9d2
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 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.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom(
+    info: Layout, //~ ERROR argument should be `Layout`
+) { //~ ERROR return type should be `!`
+    loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs
new file mode 100644 (file)
index 0000000..828a780
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2018 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.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom() -> ! { //~ ERROR function should have one argument
+    loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/compile-fail/feature-gate-alloc-error-handler.rs b/src/test/compile-fail/feature-gate-alloc-error-handler.rs
new file mode 100644 (file)
index 0000000..66691af
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2018 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.
+
+// compile-flags:-C panic=abort
+
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540)
+fn oom(info: Layout) -> ! {
+    loop {}
+}
index 720ce1512f26a8120c0beae2193bb0c441afdb4b..453602b800b5e546d7cecb9d7e4069885a04a8dd 100644 (file)
@@ -14,6 +14,7 @@
 #![no_main]
 #![no_std]
 
+use core::alloc::Layout;
 use core::panic::PanicInfo;
 
 #[panic_implementation]
@@ -25,4 +26,6 @@ fn panic(_: &PanicInfo) -> ! {
 fn eh() {}
 
 #[lang = "oom"]
-fn oom() {}
+fn oom(_: Layout) -> ! {
+    loop {}
+}
diff --git a/src/test/ui/missing-alloc_error_handler.rs b/src/test/ui/missing-alloc_error_handler.rs
new file mode 100644 (file)
index 0000000..3842d48
--- /dev/null
@@ -0,0 +1,33 @@
+// 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.
+
+// compile-flags: -C panic=abort
+// no-prefer-dynamic
+
+#![no_std]
+#![crate_type = "staticlib"]
+#![feature(panic_implementation, alloc_error_handler, alloc)]
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+extern crate alloc;
+
+#[global_allocator]
+static A: MyAlloc = MyAlloc;
+
+struct MyAlloc;
+
+unsafe impl core::alloc::GlobalAlloc for MyAlloc {
+    unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ }
+    unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {}
+}
diff --git a/src/test/ui/missing-alloc_error_handler.stderr b/src/test/ui/missing-alloc_error_handler.stderr
new file mode 100644 (file)
index 0000000..5489b2c
--- /dev/null
@@ -0,0 +1,4 @@
+error: `#[alloc_error_handler]` function required, but not found
+
+error: aborting due to previous error
+
index 24282631b7eead69381a764e5c5f34852b39ed05..c949dcb635aad5ccbc0bf998cb06531515e109b1 100644 (file)
 
 #![no_std]
 #![crate_type = "staticlib"]
-#![feature(panic_implementation, lang_items, alloc)]
+#![feature(panic_implementation, alloc_error_handler, alloc)]
 
 #[panic_implementation]
 fn panic(_: &core::panic::PanicInfo) -> ! {
     loop {}
 }
 
-#[lang = "oom"]
-fn oom() {}
+#[alloc_error_handler]
+fn oom(_: core::alloc::Layout) -> ! {
+    loop {}
+}
 
 extern crate alloc;