]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use crate::util::check_builtin_macro_attribute; |
2 | ||
74b04a01 | 3 | use rustc_ast::expand::allocator::{ |
49aad941 | 4 | global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS, |
74b04a01 XL |
5 | }; |
6 | use rustc_ast::ptr::P; | |
f2b60f7d | 7 | use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; |
3c0e092e | 8 | use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; |
dfeec247 | 9 | use rustc_expand::base::{Annotatable, ExtCtxt}; |
f9f354fc | 10 | use rustc_span::symbol::{kw, sym, Ident, Symbol}; |
dfeec247 | 11 | use rustc_span::Span; |
9ffffee4 | 12 | use thin_vec::{thin_vec, ThinVec}; |
416331ca XL |
13 | |
14 | pub fn expand( | |
15 | ecx: &mut ExtCtxt<'_>, | |
16 | _span: Span, | |
17 | meta_item: &ast::MetaItem, | |
cdc7bbd5 | 18 | item: Annotatable, |
416331ca XL |
19 | ) -> Vec<Annotatable> { |
20 | check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator); | |
21 | ||
cdc7bbd5 | 22 | let orig_item = item.clone(); |
fc512014 XL |
23 | |
24 | // Allow using `#[global_allocator]` on an item statement | |
cdc7bbd5 | 25 | // FIXME - if we get deref patterns, use them to reduce duplication here |
487cf647 FG |
26 | let (item, is_stmt, ty_span) = |
27 | if let Annotatable::Item(item) = &item | |
353b0b11 | 28 | && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind |
487cf647 FG |
29 | { |
30 | (item, false, ecx.with_def_site_ctxt(ty.span)) | |
31 | } else if let Annotatable::Stmt(stmt) = &item | |
32 | && let StmtKind::Item(item) = &stmt.kind | |
353b0b11 | 33 | && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind |
487cf647 FG |
34 | { |
35 | (item, true, ecx.with_def_site_ctxt(ty.span)) | |
36 | } else { | |
37 | ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics"); | |
9c376795 | 38 | return vec![orig_item]; |
487cf647 | 39 | }; |
416331ca XL |
40 | |
41 | // Generate a bunch of new items using the AllocFnFactory | |
e1599b0c | 42 | let span = ecx.with_def_site_ctxt(item.span); |
49aad941 | 43 | let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx }; |
416331ca XL |
44 | |
45 | // Generate item statements for the allocator methods. | |
46 | let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); | |
47 | ||
48 | // Generate anonymous constant serving as container for the allocator methods. | |
9ffffee4 | 49 | let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); |
416331ca | 50 | let const_body = ecx.expr_block(ecx.block(span, stmts)); |
dfeec247 | 51 | let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); |
fc512014 XL |
52 | let const_item = if is_stmt { |
53 | Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) | |
54 | } else { | |
55 | Annotatable::Item(const_item) | |
56 | }; | |
416331ca XL |
57 | |
58 | // Return the original item and the new methods. | |
fc512014 | 59 | vec![orig_item, const_item] |
416331ca XL |
60 | } |
61 | ||
62 | struct AllocFnFactory<'a, 'b> { | |
63 | span: Span, | |
5099ac24 | 64 | ty_span: Span, |
416331ca XL |
65 | global: Ident, |
66 | cx: &'b ExtCtxt<'a>, | |
67 | } | |
68 | ||
69 | impl AllocFnFactory<'_, '_> { | |
70 | fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { | |
9ffffee4 | 71 | let mut abi_args = ThinVec::new(); |
416331ca | 72 | let mut i = 0; |
74b04a01 | 73 | let mut mk = || { |
3dfed10e | 74 | let name = Ident::from_str_and_span(&format!("arg{}", i), self.span); |
416331ca XL |
75 | i += 1; |
76 | name | |
77 | }; | |
74b04a01 | 78 | let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, &mut mk)).collect(); |
416331ca XL |
79 | let result = self.call_allocator(method.name, args); |
80 | let (output_ty, output_expr) = self.ret_ty(&method.output, result); | |
74b04a01 XL |
81 | let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); |
82 | let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; | |
3dfed10e | 83 | let sig = FnSig { decl, header, span: self.span }; |
3c0e092e XL |
84 | let body = Some(self.cx.block_expr(output_expr)); |
85 | let kind = ItemKind::Fn(Box::new(Fn { | |
86 | defaultness: ast::Defaultness::Final, | |
94222f64 | 87 | sig, |
3c0e092e XL |
88 | generics: Generics::default(), |
89 | body, | |
90 | })); | |
416331ca XL |
91 | let item = self.cx.item( |
92 | self.span, | |
49aad941 | 93 | Ident::from_str_and_span(&global_fn_name(method.name), self.span), |
416331ca XL |
94 | self.attrs(), |
95 | kind, | |
96 | ); | |
5099ac24 | 97 | self.cx.stmt_item(self.ty_span, item) |
416331ca XL |
98 | } |
99 | ||
9ffffee4 | 100 | fn call_allocator(&self, method: Symbol, mut args: ThinVec<P<Expr>>) -> P<Expr> { |
3dfed10e | 101 | let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]); |
5099ac24 FG |
102 | let method = self.cx.expr_path(self.cx.path(self.ty_span, method)); |
103 | let allocator = self.cx.path_ident(self.ty_span, self.global); | |
416331ca | 104 | let allocator = self.cx.expr_path(allocator); |
5099ac24 | 105 | let allocator = self.cx.expr_addr_of(self.ty_span, allocator); |
416331ca XL |
106 | args.insert(0, allocator); |
107 | ||
5099ac24 | 108 | self.cx.expr_call(self.ty_span, method, args) |
416331ca XL |
109 | } |
110 | ||
f2b60f7d | 111 | fn attrs(&self) -> AttrVec { |
487cf647 | 112 | thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] |
416331ca XL |
113 | } |
114 | ||
115 | fn arg_ty( | |
116 | &self, | |
117 | ty: &AllocatorTy, | |
9ffffee4 | 118 | args: &mut ThinVec<Param>, |
416331ca XL |
119 | ident: &mut dyn FnMut() -> Ident, |
120 | ) -> P<Expr> { | |
121 | match *ty { | |
122 | AllocatorTy::Layout => { | |
e1599b0c | 123 | let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); |
416331ca XL |
124 | let ty_usize = self.cx.ty_path(usize); |
125 | let size = ident(); | |
126 | let align = ident(); | |
e1599b0c XL |
127 | args.push(self.cx.param(self.span, size, ty_usize.clone())); |
128 | args.push(self.cx.param(self.span, align, ty_usize)); | |
416331ca | 129 | |
3dfed10e XL |
130 | let layout_new = |
131 | self.cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); | |
416331ca XL |
132 | let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); |
133 | let size = self.cx.expr_ident(self.span, size); | |
134 | let align = self.cx.expr_ident(self.span, align); | |
9ffffee4 | 135 | let layout = self.cx.expr_call(self.span, layout_new, thin_vec![size, align]); |
416331ca XL |
136 | layout |
137 | } | |
138 | ||
139 | AllocatorTy::Ptr => { | |
140 | let ident = ident(); | |
e1599b0c | 141 | args.push(self.cx.param(self.span, ident, self.ptr_u8())); |
416331ca XL |
142 | let arg = self.cx.expr_ident(self.span, ident); |
143 | self.cx.expr_cast(self.span, arg, self.ptr_u8()) | |
144 | } | |
145 | ||
146 | AllocatorTy::Usize => { | |
147 | let ident = ident(); | |
e1599b0c | 148 | args.push(self.cx.param(self.span, ident, self.usize())); |
416331ca XL |
149 | self.cx.expr_ident(self.span, ident) |
150 | } | |
151 | ||
152 | AllocatorTy::ResultPtr | AllocatorTy::Unit => { | |
153 | panic!("can't convert AllocatorTy to an argument") | |
154 | } | |
155 | } | |
156 | } | |
157 | ||
158 | fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) { | |
159 | match *ty { | |
160 | AllocatorTy::ResultPtr => { | |
161 | // We're creating: | |
162 | // | |
163 | // #expr as *mut u8 | |
164 | ||
165 | let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); | |
166 | (self.ptr_u8(), expr) | |
167 | } | |
168 | ||
9ffffee4 | 169 | AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), expr), |
416331ca XL |
170 | |
171 | AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { | |
172 | panic!("can't convert `AllocatorTy` to an output") | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | fn usize(&self) -> P<Ty> { | |
e1599b0c | 178 | let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); |
416331ca XL |
179 | self.cx.ty_path(usize) |
180 | } | |
181 | ||
182 | fn ptr_u8(&self) -> P<Ty> { | |
e1599b0c | 183 | let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span)); |
416331ca | 184 | let ty_u8 = self.cx.ty_path(u8); |
dfeec247 | 185 | self.cx.ty_ptr(self.span, ty_u8, Mutability::Mut) |
416331ca XL |
186 | } |
187 | } |