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 middle
::cstore
::{CrateStore, FoundAst, InlinedItem}
;
13 use rustc
::hir
::def_id
::DefId
;
14 use rustc
::ty
::subst
::Substs
;
15 use base
::{push_ctxt, trans_item, trans_fn}
;
19 use rustc
::dep_graph
::DepNode
;
22 fn instantiate_inline(ccx
: &CrateContext
, fn_id
: DefId
) -> Option
<DefId
> {
23 debug
!("instantiate_inline({:?})", fn_id
);
24 let _icx
= push_ctxt("instantiate_inline");
26 let _task
= tcx
.dep_graph
.in_task(DepNode
::TransInlinedItem(fn_id
));
28 match ccx
.external().borrow().get(&fn_id
) {
29 Some(&Some(node_id
)) => {
31 debug
!("instantiate_inline({}): already inline as node id {}",
32 tcx
.item_path_str(fn_id
), node_id
);
33 let node_def_id
= tcx
.map
.local_def_id(node_id
);
34 return Some(node_def_id
);
37 return None
; // Not inlinable
44 let inlined
= tcx
.sess
.cstore
.maybe_get_item_ast(tcx
, fn_id
);
45 let inline_id
= match inlined
{
46 FoundAst
::NotFound
=> {
47 ccx
.external().borrow_mut().insert(fn_id
, None
);
50 FoundAst
::Found(&InlinedItem
::Item(ref item
)) => {
51 ccx
.external().borrow_mut().insert(fn_id
, Some(item
.id
));
52 ccx
.external_srcs().borrow_mut().insert(item
.id
, fn_id
);
54 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
55 trans_item(ccx
, item
);
57 if let hir
::ItemFn(_
, _
, _
, _
, ref generics
, _
) = item
.node
{
58 // Generics have no symbol, so they can't be given any linkage.
59 if !generics
.is_type_parameterized() {
60 let linkage
= if ccx
.sess().opts
.cg
.codegen_units
== 1 {
61 // We could use AvailableExternallyLinkage here,
62 // but InternalLinkage allows LLVM to optimize more
63 // aggressively (at the cost of sometimes
67 // With multiple compilation units, duplicated code
68 // is more of a problem. Also, `codegen_units > 1`
69 // means the user is okay with losing some
71 AvailableExternallyLinkage
73 let empty_substs
= tcx
.mk_substs(Substs
::empty());
74 let def_id
= tcx
.map
.local_def_id(item
.id
);
75 let llfn
= Callee
::def(ccx
, def_id
, empty_substs
).reify(ccx
).val
;
76 SetLinkage(llfn
, linkage
);
82 FoundAst
::Found(&InlinedItem
::Foreign(ref item
)) => {
83 ccx
.external().borrow_mut().insert(fn_id
, Some(item
.id
));
84 ccx
.external_srcs().borrow_mut().insert(item
.id
, fn_id
);
87 FoundAst
::FoundParent(parent_id
, item
) => {
88 ccx
.external().borrow_mut().insert(parent_id
, Some(item
.id
));
89 ccx
.external_srcs().borrow_mut().insert(item
.id
, parent_id
);
93 hir
::ItemEnum(ref ast_def
, _
) => {
94 let ast_vs
= &ast_def
.variants
;
95 let ty_vs
= &tcx
.lookup_adt_def(parent_id
).variants
;
96 assert_eq
!(ast_vs
.len(), ty_vs
.len());
97 for (ast_v
, ty_v
) in ast_vs
.iter().zip(ty_vs
.iter()) {
98 if ty_v
.did
== fn_id { my_id = ast_v.node.data.id(); }
99 ccx
.external().borrow_mut().insert(ty_v
.did
, Some(ast_v
.node
.data
.id()));
100 ccx
.external_srcs().borrow_mut().insert(ast_v
.node
.data
.id(), ty_v
.did
);
103 hir
::ItemStruct(ref struct_def
, _
) => {
104 if struct_def
.is_struct() {
105 bug
!("instantiate_inline: called on a \
108 ccx
.external().borrow_mut().insert(fn_id
, Some(struct_def
.id()));
109 ccx
.external_srcs().borrow_mut().insert(struct_def
.id(), fn_id
);
110 my_id
= struct_def
.id();
113 _
=> bug
!("instantiate_inline: item has a \
114 non-enum, non-struct parent")
118 FoundAst
::Found(&InlinedItem
::TraitItem(_
, ref trait_item
)) => {
119 ccx
.external().borrow_mut().insert(fn_id
, Some(trait_item
.id
));
120 ccx
.external_srcs().borrow_mut().insert(trait_item
.id
, fn_id
);
122 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
124 // Associated consts already have to be evaluated in `typeck`, so
125 // the logic to do that already exists in `middle`. In order to
126 // reuse that code, it needs to be able to look up the traits for
128 let ty_trait_item
= tcx
.impl_or_trait_item(fn_id
).clone();
129 let trait_item_def_id
= tcx
.map
.local_def_id(trait_item
.id
);
130 tcx
.impl_or_trait_items
.borrow_mut()
131 .insert(trait_item_def_id
, ty_trait_item
);
133 // If this is a default method, we can't look up the
134 // impl type. But we aren't going to translate anyways, so
138 FoundAst
::Found(&InlinedItem
::ImplItem(impl_did
, ref impl_item
)) => {
139 ccx
.external().borrow_mut().insert(fn_id
, Some(impl_item
.id
));
140 ccx
.external_srcs().borrow_mut().insert(impl_item
.id
, fn_id
);
142 ccx
.stats().n_inlines
.set(ccx
.stats().n_inlines
.get() + 1);
144 // Translate monomorphic impl methods immediately.
145 if let hir
::ImplItemKind
::Method(ref sig
, ref body
) = impl_item
.node
{
146 let impl_tpt
= tcx
.lookup_item_type(impl_did
);
147 if impl_tpt
.generics
.types
.is_empty() &&
148 sig
.generics
.ty_params
.is_empty() {
149 let def_id
= tcx
.map
.local_def_id(impl_item
.id
);
150 let empty_substs
= ccx
.empty_substs_for_def_id(def_id
);
151 let llfn
= Callee
::def(ccx
, def_id
, empty_substs
).reify(ccx
).val
;
158 // See linkage comments on items.
159 if ccx
.sess().opts
.cg
.codegen_units
== 1 {
160 SetLinkage(llfn
, InternalLinkage
);
162 SetLinkage(llfn
, AvailableExternallyLinkage
);
171 let inline_def_id
= tcx
.map
.local_def_id(inline_id
);
175 pub fn get_local_instance(ccx
: &CrateContext
, fn_id
: DefId
)
177 if let Some(_
) = ccx
.tcx().map
.as_local_node_id(fn_id
) {
180 instantiate_inline(ccx
, fn_id
)
184 pub fn maybe_instantiate_inline(ccx
: &CrateContext
, fn_id
: DefId
) -> DefId
{
185 get_local_instance(ccx
, fn_id
).unwrap_or(fn_id
)