1 // Copyright 2014 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 llvm
::{AvailableExternallyLinkage, InternalLinkage, SetLinkage}
;
12 use metadata
::csearch
;
13 use middle
::astencode
;
14 use middle
::subst
::Substs
;
15 use trans
::base
::{push_ctxt, trans_item, get_item_val, trans_fn}
;
20 use syntax
::ast_util
::local_def
;
22 fn instantiate_inline(ccx
: &CrateContext
, fn_id
: ast
::DefId
)
23 -> Option
<ast
::DefId
> {
24 debug
!("instantiate_inline({:?})", fn_id
);
25 let _icx
= push_ctxt("instantiate_inline");
27 match ccx
.external().borrow().get(&fn_id
) {
28 Some(&Some(node_id
)) => {
30 debug
!("instantiate_inline({}): already inline as node id {}",
31 ty
::item_path_str(ccx
.tcx(), fn_id
), node_id
);
32 return Some(local_def(node_id
));
35 return None
; // Not inlinable
43 csearch
::maybe_get_item_ast(
45 Box
::new(|a
,b
,c
,d
| astencode
::decode_inlined_item(a
, b
, c
, d
)));
47 let inline_id
= match csearch_result
{
48 csearch
::FoundAst
::NotFound
=> {
49 ccx
.external().borrow_mut().insert(fn_id
, None
);
52 csearch
::FoundAst
::Found(&ast
::IIItem(ref item
)) => {
53 ccx
.external().borrow_mut().insert(fn_id
, Some(item
.id
));
54 ccx
.external_srcs().borrow_mut().insert(item
.id
, fn_id
);
56 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
57 trans_item(ccx
, item
);
59 let linkage
= match item
.node
{
60 ast
::ItemFn(_
, _
, _
, _
, ref generics
, _
) => {
61 if generics
.is_type_parameterized() {
62 // Generics have no symbol, so they can't be given any
66 if ccx
.sess().opts
.cg
.codegen_units
== 1 {
67 // We could use AvailableExternallyLinkage here,
68 // but InternalLinkage allows LLVM to optimize more
69 // aggressively (at the cost of sometimes
73 // With multiple compilation units, duplicated code
74 // is more of a problem. Also, `codegen_units > 1`
75 // means the user is okay with losing some
77 Some(AvailableExternallyLinkage
)
81 ast
::ItemConst(..) => None
,
87 let g
= get_item_val(ccx
, item
.id
);
88 SetLinkage(g
, linkage
);
95 csearch
::FoundAst
::Found(&ast
::IIForeign(ref item
)) => {
96 ccx
.external().borrow_mut().insert(fn_id
, Some(item
.id
));
97 ccx
.external_srcs().borrow_mut().insert(item
.id
, fn_id
);
100 csearch
::FoundAst
::FoundParent(parent_id
, &ast
::IIItem(ref item
)) => {
101 ccx
.external().borrow_mut().insert(parent_id
, Some(item
.id
));
102 ccx
.external_srcs().borrow_mut().insert(item
.id
, parent_id
);
106 ast
::ItemEnum(_
, _
) => {
107 let vs_here
= ty
::enum_variants(ccx
.tcx(), local_def(item
.id
));
108 let vs_there
= ty
::enum_variants(ccx
.tcx(), parent_id
);
109 for (here
, there
) in vs_here
.iter().zip(vs_there
.iter()) {
110 if there
.id
== fn_id { my_id = here.id.node; }
111 ccx
.external().borrow_mut().insert(there
.id
, Some(here
.id
.node
));
114 ast
::ItemStruct(ref struct_def
, _
) => {
115 match struct_def
.ctor_id
{
118 ccx
.external().borrow_mut().insert(fn_id
, Some(ctor_id
));
123 _
=> ccx
.sess().bug("instantiate_inline: item has a \
124 non-enum, non-struct parent")
126 trans_item(ccx
, &**item
);
129 csearch
::FoundAst
::FoundParent(_
, _
) => {
130 ccx
.sess().bug("maybe_get_item_ast returned a FoundParent \
131 with a non-item parent");
133 csearch
::FoundAst
::Found(&ast
::IITraitItem(_
, ref trait_item
)) => {
134 ccx
.external().borrow_mut().insert(fn_id
, Some(trait_item
.id
));
135 ccx
.external_srcs().borrow_mut().insert(trait_item
.id
, fn_id
);
137 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
139 // Associated consts already have to be evaluated in `typeck`, so
140 // the logic to do that already exists in `middle`. In order to
141 // reuse that code, it needs to be able to look up the traits for
143 let ty_trait_item
= ty
::impl_or_trait_item(ccx
.tcx(), fn_id
).clone();
144 ccx
.tcx().impl_or_trait_items
.borrow_mut()
145 .insert(local_def(trait_item
.id
), ty_trait_item
);
147 // If this is a default method, we can't look up the
148 // impl type. But we aren't going to translate anyways, so
152 csearch
::FoundAst
::Found(&ast
::IIImplItem(impl_did
, ref impl_item
)) => {
153 ccx
.external().borrow_mut().insert(fn_id
, Some(impl_item
.id
));
154 ccx
.external_srcs().borrow_mut().insert(impl_item
.id
, fn_id
);
156 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
158 // Translate monomorphic impl methods immediately.
159 if let ast
::MethodImplItem(ref sig
, ref body
) = impl_item
.node
{
160 let impl_tpt
= ty
::lookup_item_type(ccx
.tcx(), impl_did
);
161 if impl_tpt
.generics
.types
.is_empty() &&
162 sig
.generics
.ty_params
.is_empty() {
163 let empty_substs
= ccx
.tcx().mk_substs(Substs
::trans_empty());
164 let llfn
= get_item_val(ccx
, impl_item
.id
);
172 // See linkage comments on items.
173 if ccx
.sess().opts
.cg
.codegen_units
== 1 {
174 SetLinkage(llfn
, InternalLinkage
);
176 SetLinkage(llfn
, AvailableExternallyLinkage
);
185 Some(local_def(inline_id
))
188 pub fn get_local_instance(ccx
: &CrateContext
, fn_id
: ast
::DefId
)
189 -> Option
<ast
::DefId
> {
190 if fn_id
.krate
== ast
::LOCAL_CRATE
{
193 instantiate_inline(ccx
, fn_id
)
197 pub fn maybe_instantiate_inline(ccx
: &CrateContext
, fn_id
: ast
::DefId
) -> ast
::DefId
{
198 get_local_instance(ccx
, fn_id
).unwrap_or(fn_id
)