1 // Copyright 2016 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.
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.
11 use rustc
::middle
::allocator
::AllocatorKind
;
13 use rustc_target
::spec
::abi
::Abi
;
14 use syntax
::ast
::{Attribute, Crate, LitKind, StrStyle}
;
15 use syntax
::ast
::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety}
;
16 use syntax
::ast
::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}
;
18 use syntax
::codemap
::{dummy_spanned, respan}
;
19 use syntax
::codemap
::{ExpnInfo, MacroAttribute, NameAndSpan}
;
20 use syntax
::ext
::base
::ExtCtxt
;
21 use syntax
::ext
::base
::Resolver
;
22 use syntax
::ext
::build
::AstBuilder
;
23 use syntax
::ext
::expand
::ExpansionConfig
;
24 use syntax
::ext
::hygiene
::{Mark, SyntaxContext}
;
25 use syntax
::fold
::{self, Folder}
;
26 use syntax
::parse
::ParseSess
;
28 use syntax
::symbol
::Symbol
;
29 use syntax
::util
::small_vector
::SmallVector
;
30 use syntax_pos
::{Span, DUMMY_SP}
;
32 use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}
;
36 resolver
: &mut Resolver
,
38 handler
: &rustc_errors
::Handler
,
40 ExpandAllocatorDirectives
{
48 struct ExpandAllocatorDirectives
<'a
> {
50 handler
: &'a rustc_errors
::Handler
,
52 resolver
: &'a
mut Resolver
,
55 impl<'a
> Folder
for ExpandAllocatorDirectives
<'a
> {
56 fn fold_item(&mut self, item
: P
<Item
>) -> SmallVector
<P
<Item
>> {
57 let name
= if attr
::contains_name(&item
.attrs
, "global_allocator") {
60 return fold
::noop_fold_item(item
, self);
63 ItemKind
::Static(..) => {}
66 .span_err(item
.span
, "allocators must be statics");
67 return SmallVector
::one(item
);
72 self.handler
.span_err(
74 "cannot define more than one \
77 return SmallVector
::one(item
);
81 let mark
= Mark
::fresh(Mark
::root());
82 mark
.set_expn_info(ExpnInfo
{
85 format
: MacroAttribute(Symbol
::intern(name
)),
87 allow_internal_unstable
: true,
88 allow_internal_unsafe
: false,
91 let span
= item
.span
.with_ctxt(SyntaxContext
::empty().apply_mark(mark
));
92 let ecfg
= ExpansionConfig
::default(name
.to_string());
93 let mut f
= AllocFnFactory
{
95 kind
: AllocatorKind
::Global
,
97 core
: Ident
::from_str("core"),
98 cx
: ExtCtxt
::new(self.sess
, ecfg
, self.resolver
),
100 let super_path
= f
.cx
.path(f
.span
, vec
![Ident
::from_str("super"), f
.global
]);
101 let mut items
= vec
![
102 f
.cx
.item_extern_crate(f
.span
, f
.core
),
103 f
.cx
.item_use_simple(
105 respan(f
.span
.shrink_to_lo(), VisibilityKind
::Inherited
),
109 for method
in ALLOCATOR_METHODS
{
110 items
.push(f
.allocator_fn(method
));
112 let name
= f
.kind
.fn_name("allocator_abi");
113 let allocator_abi
= Ident
::with_empty_ctxt(Symbol
::gensym(&name
));
114 let module
= f
.cx
.item_mod(span
, span
, allocator_abi
, Vec
::new(), items
);
115 let module
= f
.cx
.monotonic_expander().fold_item(module
).pop().unwrap();
117 let mut ret
= SmallVector
::new();
123 fn fold_mac(&mut self, mac
: Mac
) -> Mac
{
124 fold
::noop_fold_mac(mac
, self)
128 struct AllocFnFactory
<'a
> {
136 impl<'a
> AllocFnFactory
<'a
> {
137 fn allocator_fn(&self, method
: &AllocatorMethod
) -> P
<Item
> {
138 let mut abi_args
= Vec
::new();
140 let ref mut mk
= || {
141 let name
= Ident
::from_str(&format
!("arg{}", i
));
148 .map(|ty
| self.arg_ty(ty
, &mut abi_args
, mk
))
150 let result
= self.call_allocator(method
.name
, args
);
151 let (output_ty
, output_expr
) = self.ret_ty(&method
.output
, result
);
152 let kind
= ItemKind
::Fn(
153 self.cx
.fn_decl(abi_args
, ast
::FunctionRetTy
::Ty(output_ty
)),
155 dummy_spanned(Constness
::NotConst
),
158 self.cx
.block_expr(output_expr
),
162 Ident
::from_str(&self.kind
.fn_name(method
.name
)),
168 fn call_allocator(&self, method
: &str, mut args
: Vec
<P
<Expr
>>) -> P
<Expr
> {
169 let method
= self.cx
.path(
173 Ident
::from_str("alloc"),
174 Ident
::from_str("GlobalAlloc"),
175 Ident
::from_str(method
),
178 let method
= self.cx
.expr_path(method
);
179 let allocator
= self.cx
.path_ident(self.span
, self.global
);
180 let allocator
= self.cx
.expr_path(allocator
);
181 let allocator
= self.cx
.expr_addr_of(self.span
, allocator
);
182 args
.insert(0, allocator
);
184 self.cx
.expr_call(self.span
, method
, args
)
187 fn attrs(&self) -> Vec
<Attribute
> {
188 let key
= Symbol
::intern("linkage");
189 let value
= LitKind
::Str(Symbol
::intern("external"), StrStyle
::Cooked
);
190 let linkage
= self.cx
.meta_name_value(self.span
, key
, value
);
192 let no_mangle
= Symbol
::intern("no_mangle");
193 let no_mangle
= self.cx
.meta_word(self.span
, no_mangle
);
195 let special
= Symbol
::intern("rustc_std_internal_symbol");
196 let special
= self.cx
.meta_word(self.span
, special
);
198 self.cx
.attribute(self.span
, linkage
),
199 self.cx
.attribute(self.span
, no_mangle
),
200 self.cx
.attribute(self.span
, special
),
208 ident
: &mut FnMut() -> Ident
,
211 AllocatorTy
::Layout
=> {
212 let usize = self.cx
.path_ident(self.span
, Ident
::from_str("usize"));
213 let ty_usize
= self.cx
.ty_path(usize);
216 args
.push(self.cx
.arg(self.span
, size
, ty_usize
.clone()));
217 args
.push(self.cx
.arg(self.span
, align
, ty_usize
));
219 let layout_new
= self.cx
.path(
223 Ident
::from_str("alloc"),
224 Ident
::from_str("Layout"),
225 Ident
::from_str("from_size_align_unchecked"),
228 let layout_new
= self.cx
.expr_path(layout_new
);
229 let size
= self.cx
.expr_ident(self.span
, size
);
230 let align
= self.cx
.expr_ident(self.span
, align
);
231 let layout
= self.cx
.expr_call(self.span
, layout_new
, vec
![size
, align
]);
235 AllocatorTy
::Ptr
=> {
237 args
.push(self.cx
.arg(self.span
, ident
, self.ptr_u8()));
238 let arg
= self.cx
.expr_ident(self.span
, ident
);
239 self.cx
.expr_cast(self.span
, arg
, self.ptr_opaque())
242 AllocatorTy
::Usize
=> {
244 args
.push(self.cx
.arg(self.span
, ident
, self.usize()));
245 self.cx
.expr_ident(self.span
, ident
)
248 AllocatorTy
::ResultPtr
| AllocatorTy
::Unit
=> {
249 panic
!("can't convert AllocatorTy to an argument")
254 fn ret_ty(&self, ty
: &AllocatorTy
, expr
: P
<Expr
>) -> (P
<Ty
>, P
<Expr
>) {
256 AllocatorTy
::ResultPtr
=> {
261 let expr
= self.cx
.expr_cast(self.span
, expr
, self.ptr_u8());
262 (self.ptr_u8(), expr
)
265 AllocatorTy
::Unit
=> (self.cx
.ty(self.span
, TyKind
::Tup(Vec
::new())), expr
),
267 AllocatorTy
::Layout
| AllocatorTy
::Usize
| AllocatorTy
::Ptr
=> {
268 panic
!("can't convert AllocatorTy to an output")
273 fn usize(&self) -> P
<Ty
> {
274 let usize = self.cx
.path_ident(self.span
, Ident
::from_str("usize"));
275 self.cx
.ty_path(usize)
278 fn ptr_u8(&self) -> P
<Ty
> {
279 let u8 = self.cx
.path_ident(self.span
, Ident
::from_str("u8"));
280 let ty_u8
= self.cx
.ty_path(u8);
281 self.cx
.ty_ptr(self.span
, ty_u8
, Mutability
::Mutable
)
284 fn ptr_opaque(&self) -> P
<Ty
> {
285 let opaque
= self.cx
.path(
289 Ident
::from_str("alloc"),
290 Ident
::from_str("Opaque"),
293 let ty_opaque
= self.cx
.ty_path(opaque
);
294 self.cx
.ty_ptr(self.span
, ty_opaque
, Mutability
::Mutable
)