diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 01221aecb6284..b6ac248b79f86 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -48,6 +48,7 @@ fn size_align() -> (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, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 226d19a91240f..42775e3a1837f 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -288,7 +288,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { 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; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index fe676919a7d14..6c1ef851cbeca 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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 @@ language_item_table! { 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; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 180e75df1a66e..d8570b43fbe27 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -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))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 646c4f17568f0..c7ad3398873ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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) diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index f6cecbea11f8d..8db365cd21d67 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -125,9 +125,10 @@ 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 extern fn rust_oom(layout: Layout) -> ! { +pub fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { default_alloc_error_hook diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d73cb1f8349a6..fec14b8d67d35 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,8 +233,9 @@ // 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)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cbc421dbd328c..e70d93ae85a1d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -481,6 +481,9 @@ declare_features! ( // 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 const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "#[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 index 0000000000000..e398f16a065bd --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs @@ -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 or the MIT license +// , 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 index 0000000000000..4fee9d27e5175 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs @@ -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 or the MIT license +// , 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 index 0000000000000..828a78055d5f2 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs @@ -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 or the MIT license +// , 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 index 0000000000000..66691af2d0325 --- /dev/null +++ b/src/test/compile-fail/feature-gate-alloc-error-handler.rs @@ -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 or the MIT license +// , 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 {} +} diff --git a/src/test/run-make-fulldeps/issue-51671/app.rs b/src/test/run-make-fulldeps/issue-51671/app.rs index 720ce1512f26a..453602b800b5e 100644 --- a/src/test/run-make-fulldeps/issue-51671/app.rs +++ b/src/test/run-make-fulldeps/issue-51671/app.rs @@ -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/run-pass/default-alloc-error-hook.rs b/src/test/run-pass/default-alloc-error-hook.rs new file mode 100644 index 0000000000000..5f6b60a5a8d99 --- /dev/null +++ b/src/test/run-pass/default-alloc-error-hook.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-cloudabi no processes +// ignore-emscripten no processes + +use std::alloc::{Layout, handle_alloc_error}; +use std::env; +use std::process::Command; +use std::str; + +fn main() { + if env::args().len() > 1 { + handle_alloc_error(Layout::new::<[u8; 42]>()) + } + + let me = env::current_exe().unwrap(); + let output = Command::new(&me).arg("next").output().unwrap(); + assert!(!output.status.success(), "{:?} is a success", output.status); + assert_eq!(str::from_utf8(&output.stderr).unwrap(), "memory allocation of 42 bytes failed"); +} diff --git a/src/test/ui/missing-alloc_error_handler.rs b/src/test/ui/missing-alloc_error_handler.rs new file mode 100644 index 0000000000000..3842d48f8fab1 --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.rs @@ -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 or the MIT license +// , 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 index 0000000000000..5489b2cbbfad8 --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.stderr @@ -0,0 +1,4 @@ +error: `#[alloc_error_handler]` function required, but not found + +error: aborting due to previous error + diff --git a/src/test/ui/missing-allocator.rs b/src/test/ui/missing-allocator.rs index 24282631b7eea..c949dcb635aad 100644 --- a/src/test/ui/missing-allocator.rs +++ b/src/test/ui/missing-allocator.rs @@ -13,14 +13,16 @@ #![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;