Skip to content

Commit 239ec7d

Browse files
committed
Implement #[alloc_error_handler]
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`.
1 parent 872effa commit 239ec7d

16 files changed

+224
-7
lines changed

src/libcore/alloc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ fn size_align<T>() -> (usize, usize) {
4848
/// use specific allocators with looser requirements.)
4949
#[stable(feature = "alloc_layout", since = "1.28.0")]
5050
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
51+
#[cfg_attr(not(stage0), lang = "alloc_layout")]
5152
pub struct Layout {
5253
// size of the requested block of memory, measured in bytes.
5354
size_: usize,

src/librustc/middle/dead.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
288288
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
289289
id: ast::NodeId,
290290
attrs: &[ast::Attribute]) -> bool {
291-
if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") {
291+
if attr::contains_name(attrs, "lang") {
292+
return true;
293+
}
294+
295+
// (To be) stable attribute for #[lang = "panic_impl"]
296+
if attr::contains_name(attrs, "panic_implementation") {
297+
return true;
298+
}
299+
300+
// (To be) stable attribute for #[lang = "oom"]
301+
if attr::contains_name(attrs, "alloc_error_handler") {
292302
return true;
293303
}
294304

src/librustc/middle/lang_items.rs

+3
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
187187
}
188188
} else if attribute.check_name("panic_implementation") {
189189
return Some((Symbol::intern("panic_impl"), attribute.span))
190+
} else if attribute.check_name("alloc_error_handler") {
191+
return Some((Symbol::intern("oom"), attribute.span))
190192
}
191193
}
192194

@@ -308,6 +310,7 @@ language_item_table! {
308310
BoxFreeFnLangItem, "box_free", box_free_fn;
309311
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
310312
OomLangItem, "oom", oom;
313+
AllocLayoutLangItem, "alloc_layout", alloc_layout;
311314

312315
StartFnLangItem, "start", start_fn;
313316

src/librustc/middle/weak_lang_items.rs

+3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
115115
if lang_items::$item == lang_items::PanicImplLangItem {
116116
tcx.sess.err(&format!("`#[panic_implementation]` function required, \
117117
but not found"));
118+
} else if lang_items::$item == lang_items::OomLangItem {
119+
tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
120+
but not found"));
118121
} else {
119122
tcx.sess.err(&format!("language item required, but not found: `{}`",
120123
stringify!($name)));

src/librustc_typeck/check/mod.rs

+47
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,54 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
11821182
fcx.tcx.sess.err("language item required, but not found: `panic_info`");
11831183
}
11841184
}
1185+
}
1186+
1187+
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
1188+
if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() {
1189+
if alloc_error_handler_did == fcx.tcx.hir.local_def_id(fn_id) {
1190+
if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() {
1191+
if declared_ret_ty.sty != ty::TyNever {
1192+
fcx.tcx.sess.span_err(
1193+
decl.output.span(),
1194+
"return type should be `!`",
1195+
);
1196+
}
1197+
1198+
let inputs = fn_sig.inputs();
1199+
let span = fcx.tcx.hir.span(fn_id);
1200+
if inputs.len() == 1 {
1201+
let arg_is_alloc_layout = match inputs[0].sty {
1202+
ty::TyAdt(ref adt, _) => {
1203+
adt.did == alloc_layout_did
1204+
},
1205+
_ => false,
1206+
};
1207+
1208+
if !arg_is_alloc_layout {
1209+
fcx.tcx.sess.span_err(
1210+
decl.inputs[0].span,
1211+
"argument should be `Layout`",
1212+
);
1213+
}
11851214

1215+
if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
1216+
if let Item_::ItemFn(_, _, ref generics, _) = item.node {
1217+
if !generics.params.is_empty() {
1218+
fcx.tcx.sess.span_err(
1219+
span,
1220+
"`#[alloc_error_handler]` function should have no type \
1221+
parameters",
1222+
);
1223+
}
1224+
}
1225+
}
1226+
} else {
1227+
fcx.tcx.sess.span_err(span, "function should have one argument");
1228+
}
1229+
} else {
1230+
fcx.tcx.sess.err("language item required, but not found: `alloc_layout`");
1231+
}
1232+
}
11861233
}
11871234

11881235
(fcx, gen_ty)

src/libstd/alloc.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ fn default_alloc_error_hook(layout: Layout) {
125125

126126
#[cfg(not(test))]
127127
#[doc(hidden)]
128-
#[lang = "oom"]
128+
#[cfg_attr(stage0, lang = "oom")]
129+
#[cfg_attr(not(stage0), alloc_error_handler)]
129130
#[unstable(feature = "alloc_internals", issue = "0")]
130131
pub fn rust_oom(layout: Layout) -> ! {
131132
let hook = HOOK.load(Ordering::SeqCst);

src/libstd/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,9 @@
233233
// std is implemented with unstable features, many of which are internal
234234
// compiler details that will never be stable
235235
#![feature(alloc)]
236-
#![feature(allocator_api)]
236+
#![feature(alloc_error_handler)]
237237
#![feature(alloc_system)]
238+
#![feature(allocator_api)]
238239
#![feature(allocator_internals)]
239240
#![feature(allow_internal_unsafe)]
240241
#![feature(allow_internal_unstable)]

src/libsyntax/feature_gate.rs

+8
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,9 @@ declare_features! (
481481

482482
// Allows async and await syntax
483483
(active, async_await, "1.28.0", Some(50547), None),
484+
485+
// #[alloc_error_handler]
486+
(active, alloc_error_handler, "1.29.0", Some(51540), None),
484487
);
485488

486489
declare_features! (
@@ -1083,6 +1086,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
10831086
"#[panic_implementation] is an unstable feature",
10841087
cfg_fn!(panic_implementation))),
10851088

1089+
("alloc_error_handler", Normal, Gated(Stability::Unstable,
1090+
"alloc_error_handler",
1091+
"#[alloc_error_handler] is an unstable feature",
1092+
cfg_fn!(alloc_error_handler))),
1093+
10861094
// Crate level attributes
10871095
("crate_name", CrateLevel, Ungated),
10881096
("crate_type", CrateLevel, Ungated),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C panic=abort
12+
13+
#![feature(alloc_error_handler, panic_implementation)]
14+
#![no_std]
15+
#![no_main]
16+
17+
use core::alloc::Layout;
18+
19+
#[alloc_error_handler]
20+
fn oom(
21+
info: &Layout, //~ ERROR argument should be `Layout`
22+
) -> () //~ ERROR return type should be `!`
23+
{
24+
loop {}
25+
}
26+
27+
#[panic_implementation]
28+
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C panic=abort
12+
13+
#![feature(alloc_error_handler, panic_implementation)]
14+
#![no_std]
15+
#![no_main]
16+
17+
struct Layout;
18+
19+
#[alloc_error_handler]
20+
fn oom(
21+
info: Layout, //~ ERROR argument should be `Layout`
22+
) { //~ ERROR return type should be `!`
23+
loop {}
24+
}
25+
26+
#[panic_implementation]
27+
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C panic=abort
12+
13+
#![feature(alloc_error_handler, panic_implementation)]
14+
#![no_std]
15+
#![no_main]
16+
17+
struct Layout;
18+
19+
#[alloc_error_handler]
20+
fn oom() -> ! { //~ ERROR function should have one argument
21+
loop {}
22+
}
23+
24+
#[panic_implementation]
25+
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-C panic=abort
12+
13+
#![no_std]
14+
#![no_main]
15+
16+
use core::alloc::Layout;
17+
18+
#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540)
19+
fn oom(info: Layout) -> ! {
20+
loop {}
21+
}

src/test/run-make-fulldeps/issue-51671/app.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![no_main]
1515
#![no_std]
1616

17+
use core::alloc::Layout;
1718
use core::panic::PanicInfo;
1819

1920
#[panic_implementation]
@@ -25,4 +26,6 @@ fn panic(_: &PanicInfo) -> ! {
2526
fn eh() {}
2627

2728
#[lang = "oom"]
28-
fn oom() {}
29+
fn oom(_: Layout) -> ! {
30+
loop {}
31+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: -C panic=abort
12+
// no-prefer-dynamic
13+
14+
#![no_std]
15+
#![crate_type = "staticlib"]
16+
#![feature(panic_implementation, alloc_error_handler, alloc)]
17+
18+
#[panic_implementation]
19+
fn panic(_: &core::panic::PanicInfo) -> ! {
20+
loop {}
21+
}
22+
23+
extern crate alloc;
24+
25+
#[global_allocator]
26+
static A: MyAlloc = MyAlloc;
27+
28+
struct MyAlloc;
29+
30+
unsafe impl core::alloc::GlobalAlloc for MyAlloc {
31+
unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ }
32+
unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: `#[alloc_error_handler]` function required, but not found
2+
3+
error: aborting due to previous error
4+

src/test/ui/missing-allocator.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313

1414
#![no_std]
1515
#![crate_type = "staticlib"]
16-
#![feature(panic_implementation, lang_items, alloc)]
16+
#![feature(panic_implementation, alloc_error_handler, alloc)]
1717

1818
#[panic_implementation]
1919
fn panic(_: &core::panic::PanicInfo) -> ! {
2020
loop {}
2121
}
2222

23-
#[lang = "oom"]
24-
fn oom() {}
23+
#[alloc_error_handler]
24+
fn oom(_: core::alloc::Layout) -> ! {
25+
loop {}
26+
}
2527

2628
extern crate alloc;

0 commit comments

Comments
 (0)