Add attributes for #[global_allocator] functions

Emit `#[rustc_allocator]` etc. attributes on the functions generated
by the `#[global_allocator]` macro, which will emit LLVM attributes
like `"alloc-family"`. If the module with the global allocator
participates in LTO, this ensures that the attributes typically
emitted on the allocator declarations are not lost if the
definition is imported.
This commit is contained in:
Nikita Popov 2025-09-18 17:09:14 +02:00
parent 32e3d9f59b
commit bc7986ec79
2 changed files with 54 additions and 3 deletions

View file

@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> {
body,
define_opaque: None,
}));
let item = self.cx.item(self.span, self.attrs(), kind);
let item = self.cx.item(self.span, self.attrs(method), kind);
self.cx.stmt_item(self.ty_span, item)
}
@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> {
self.cx.expr_call(self.ty_span, method, args)
}
fn attrs(&self) -> AttrVec {
thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
fn attrs(&self, method: &AllocatorMethod) -> AttrVec {
let alloc_attr = match method.name {
sym::alloc => sym::rustc_allocator,
sym::dealloc => sym::rustc_deallocator,
sym::realloc => sym::rustc_reallocator,
sym::alloc_zeroed => sym::rustc_allocator_zeroed,
_ => unreachable!("Unknown allocator method!"),
};
thin_vec![
self.cx.attr_word(sym::rustc_std_internal_symbol, self.span),
self.cx.attr_word(alloc_attr, self.span)
]
}
fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> {

View file

@ -0,0 +1,41 @@
//@ compile-flags: -C opt-level=3
#![crate_type = "lib"]
mod foobar {
use std::alloc::{GlobalAlloc, Layout};
struct Allocator;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// CHECK-LABEL: ; __rustc::__rust_alloc
// CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,uninitialized,aligned") allocsize(0){{.*}}
// CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc(i[[SIZE:[0-9]+]] {{.*}}%size, i[[SIZE]] allocalign{{.*}} %align)
panic!()
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
// CHECK-LABEL: ; __rustc::__rust_dealloc
// CHECK-NEXT: ; Function Attrs: {{.*}}allockind("free"){{.*}}
// CHECK-NEXT: define{{.*}} void @{{.*}}__rust_dealloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] {{.*}} %align)
panic!()
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
// CHECK-LABEL: ; __rustc::__rust_realloc
// CHECK-NEXT: ; Function Attrs: {{.*}}allockind("realloc,aligned") allocsize(3){{.*}}
// CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_realloc(ptr allocptr{{.*}} %ptr, i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align, i[[SIZE]] {{.*}} %new_size)
panic!()
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
// CHECK-LABEL: ; __rustc::__rust_alloc_zeroed
// CHECK-NEXT: ; Function Attrs: {{.*}}allockind("alloc,zeroed,aligned") allocsize(0){{.*}}
// CHECK-NEXT: define{{.*}} noalias{{.*}} ptr @{{.*}}__rust_alloc_zeroed(i[[SIZE]] {{.*}} %size, i[[SIZE]] allocalign{{.*}} %align)
panic!()
}
}
#[global_allocator]
static GLOBAL: Allocator = Allocator;
}