Skip to content

Commit 4363467

Browse files
authored
Rollup merge of rust-lang#103061 - Amanieu:rewrite_alloc_error_handler, r=bjorn3
Rewrite implementation of `#[alloc_error_handler]` The new implementation doesn't use weak lang items and instead changes `#[alloc_error_handler]` to an attribute macro just like `#[global_allocator]`. The attribute will generate the `__rg_oom` function which is called by the compiler-generated `__rust_alloc_error_handler`. If no `__rg_oom` function is defined in any crate then the compiler shim will call `__rdl_oom` in the alloc crate which will simply panic. This also fixes link errors with `-C link-dead-code` with `default_alloc_error_handler`: `__rg_oom` was previously defined in the alloc crate and would attempt to reference the `oom` lang item, even if it didn't exist. This worked as long as `__rg_oom` was excluded from linking since it was not called. This is a prerequisite for the stabilization of `default_alloc_error_handler` (rust-lang#102318).
2 parents dc05f60 + 56074b5 commit 4363467

File tree

40 files changed

+441
-166
lines changed

40 files changed

+441
-166
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use crate::util::check_builtin_macro_attribute;
2+
3+
use rustc_ast::ptr::P;
4+
use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
5+
use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
6+
use rustc_expand::base::{Annotatable, ExtCtxt};
7+
use rustc_span::symbol::{kw, sym, Ident};
8+
use rustc_span::Span;
9+
use thin_vec::thin_vec;
10+
11+
pub fn expand(
12+
ecx: &mut ExtCtxt<'_>,
13+
_span: Span,
14+
meta_item: &ast::MetaItem,
15+
item: Annotatable,
16+
) -> Vec<Annotatable> {
17+
check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
18+
19+
let orig_item = item.clone();
20+
let not_function = || {
21+
ecx.sess
22+
.parse_sess
23+
.span_diagnostic
24+
.span_err(item.span(), "alloc_error_handler must be a function");
25+
vec![orig_item.clone()]
26+
};
27+
28+
// Allow using `#[alloc_error_handler]` on an item statement
29+
// FIXME - if we get deref patterns, use them to reduce duplication here
30+
let (item, is_stmt, sig_span) = match &item {
31+
Annotatable::Item(item) => match item.kind {
32+
ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
33+
_ => return not_function(),
34+
},
35+
Annotatable::Stmt(stmt) => match &stmt.kind {
36+
StmtKind::Item(item_) => match item_.kind {
37+
ItemKind::Fn(ref fn_kind) => {
38+
(item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
39+
}
40+
_ => return not_function(),
41+
},
42+
_ => return not_function(),
43+
},
44+
_ => return not_function(),
45+
};
46+
47+
// Generate a bunch of new items using the AllocFnFactory
48+
let span = ecx.with_def_site_ctxt(item.span);
49+
50+
// Generate item statements for the allocator methods.
51+
let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)];
52+
53+
// Generate anonymous constant serving as container for the allocator methods.
54+
let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new()));
55+
let const_body = ecx.expr_block(ecx.block(span, stmts));
56+
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
57+
let const_item = if is_stmt {
58+
Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
59+
} else {
60+
Annotatable::Item(const_item)
61+
};
62+
63+
// Return the original item and the new methods.
64+
vec![orig_item, const_item]
65+
}
66+
67+
// #[rustc_std_internal_symbol]
68+
// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
69+
// handler(core::alloc::Layout::from_size_align_unchecked(size, align))
70+
// }
71+
fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
72+
let usize = cx.path_ident(span, Ident::new(sym::usize, span));
73+
let ty_usize = cx.ty_path(usize);
74+
let size = Ident::from_str_and_span("size", span);
75+
let align = Ident::from_str_and_span("align", span);
76+
77+
let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
78+
let layout_new = cx.expr_path(cx.path(span, layout_new));
79+
let layout =
80+
cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]);
81+
82+
let call = cx.expr_call_ident(sig_span, handler, vec![layout]);
83+
84+
let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
85+
let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
86+
let decl = cx.fn_decl(params, never);
87+
let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
88+
let sig = FnSig { decl, header, span: span };
89+
90+
let body = Some(cx.block_expr(call));
91+
let kind = ItemKind::Fn(Box::new(Fn {
92+
defaultness: ast::Defaultness::Final,
93+
sig,
94+
generics: Generics::default(),
95+
body,
96+
}));
97+
98+
let special = sym::rustc_std_internal_symbol;
99+
let special = cx.meta_word(span, special);
100+
let attrs = thin_vec![cx.attribute(special)];
101+
102+
let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
103+
cx.stmt_item(sig_span, item)
104+
}

compiler/rustc_builtin_macros/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
2525
use rustc_expand::proc_macro::BangProcMacro;
2626
use rustc_span::symbol::sym;
2727

28+
mod alloc_error_handler;
2829
mod assert;
2930
mod cfg;
3031
mod cfg_accessible;
@@ -94,6 +95,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
9495
}
9596

9697
register_attr! {
98+
alloc_error_handler: alloc_error_handler::expand,
9799
bench: test::expand_bench,
98100
cfg_accessible: cfg_accessible::Expander,
99101
cfg_eval: cfg_eval::expand,

compiler/rustc_codegen_cranelift/src/allocator.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::prelude::*;
55

66
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
77
use rustc_session::config::OomStrategy;
8+
use rustc_span::symbol::sym;
89

910
/// Returns whether an allocator shim was created
1011
pub(crate) fn codegen(
@@ -23,7 +24,7 @@ pub(crate) fn codegen(
2324
module,
2425
unwind_context,
2526
kind,
26-
tcx.lang_items().oom().is_some(),
27+
tcx.alloc_error_handler_kind(()).unwrap(),
2728
tcx.sess.opts.unstable_opts.oom,
2829
);
2930
true
@@ -36,7 +37,7 @@ fn codegen_inner(
3637
module: &mut impl Module,
3738
unwind_context: &mut UnwindContext,
3839
kind: AllocatorKind,
39-
has_alloc_error_handler: bool,
40+
alloc_error_handler_kind: AllocatorKind,
4041
oom_strategy: OomStrategy,
4142
) {
4243
let usize_ty = module.target_config().pointer_type();
@@ -108,12 +109,12 @@ fn codegen_inner(
108109
returns: vec![],
109110
};
110111

111-
let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
112+
let callee_name = alloc_error_handler_kind.fn_name(sym::oom);
112113

113114
let func_id =
114115
module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
115116

116-
let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
117+
let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
117118

118119
let mut ctx = Context::new();
119120
ctx.func.signature = sig;

compiler/rustc_codegen_gcc/src/allocator.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_span::symbol::sym;
77

88
use crate::GccContext;
99

10-
pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
10+
pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
1111
let context = &mods.context;
1212
let usize =
1313
match tcx.sess.target.pointer_width {
@@ -90,14 +90,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
9090
.collect();
9191
let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
9292

93-
let kind =
94-
if has_alloc_error_handler {
95-
AllocatorKind::Global
96-
}
97-
else {
98-
AllocatorKind::Default
99-
};
100-
let callee = kind.fn_name(sym::oom);
93+
let callee = alloc_error_handler_kind.fn_name(sym::oom);
10194
let args: Vec<_> = types.iter().enumerate()
10295
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
10396
.collect();

compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,11 @@ impl CodegenBackend for GccCodegenBackend {
153153
}
154154

155155
impl ExtraBackendMethods for GccCodegenBackend {
156-
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
156+
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
157157
let mut mods = GccContext {
158158
context: Context::default(),
159159
};
160-
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
160+
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
161161
mods
162162
}
163163

compiler/rustc_codegen_llvm/src/allocator.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub(crate) unsafe fn codegen(
1515
module_llvm: &mut ModuleLlvm,
1616
module_name: &str,
1717
kind: AllocatorKind,
18-
has_alloc_error_handler: bool,
18+
alloc_error_handler_kind: AllocatorKind,
1919
) {
2020
let llcx = &*module_llvm.llcx;
2121
let llmod = module_llvm.llmod();
@@ -117,8 +117,7 @@ pub(crate) unsafe fn codegen(
117117
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
118118
}
119119

120-
let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
121-
let callee = kind.fn_name(sym::oom);
120+
let callee = alloc_error_handler_kind.fn_name(sym::oom);
122121
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
123122
// -> ! DIFlagNoReturn
124123
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);

compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
108108
tcx: TyCtxt<'tcx>,
109109
module_name: &str,
110110
kind: AllocatorKind,
111-
has_alloc_error_handler: bool,
111+
alloc_error_handler_kind: AllocatorKind,
112112
) -> ModuleLlvm {
113113
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
114114
unsafe {
115-
allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
115+
allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
116116
}
117117
module_llvm
118118
}

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,11 @@ fn exported_symbols_provider_local<'tcx>(
193193
}
194194

195195
if tcx.allocator_kind(()).is_some() {
196-
for method in ALLOCATOR_METHODS {
197-
let symbol_name = format!("__rust_{}", method.name);
196+
for symbol_name in ALLOCATOR_METHODS
197+
.iter()
198+
.map(|method| format!("__rust_{}", method.name))
199+
.chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
200+
{
198201
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
199202

200203
symbols.push((

compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
638638
let llmod_id =
639639
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
640640
let module_llvm = tcx.sess.time("write_allocator_module", || {
641-
backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
641+
backend.codegen_allocator(
642+
tcx,
643+
&llmod_id,
644+
kind,
645+
// If allocator_kind is Some then alloc_error_handler_kind must
646+
// also be Some.
647+
tcx.alloc_error_handler_kind(()).unwrap(),
648+
)
642649
});
643650

644651
Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })

compiler/rustc_codegen_ssa/src/traits/backend.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
119119
tcx: TyCtxt<'tcx>,
120120
module_name: &str,
121121
kind: AllocatorKind,
122-
has_alloc_error_handler: bool,
122+
alloc_error_handler_kind: AllocatorKind,
123123
) -> Self::Module;
124124
/// This generates the codegen unit and returns it along with
125125
/// a `u64` giving an estimate of the unit's processing cost.

0 commit comments

Comments
 (0)