monomorphize.rs 7.5 KB
Newer Older
R
Russell 已提交
1
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use llvm::ValueRef;
12
use llvm;
13
use rustc::hir::def_id::DefId;
14
use rustc::infer::TransNormalize;
15 16 17
use rustc::ty::subst;
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TypeFoldable, TyCtxt};
18 19 20 21 22 23 24
use attributes;
use base::{push_ctxt};
use base::trans_fn;
use base;
use common::*;
use declare;
use Disr;
25
use rustc::hir::map as hir_map;
26
use rustc::util::ppaux;
27

28
use rustc::hir;
29

30
use syntax::attr;
31
use syntax::errors;
32 33

use std::fmt;
34

35
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
N
Niko Matsakis 已提交
36
                                fn_id: DefId,
37
                                psubsts: &'tcx subst::Substs<'tcx>)
38
                                -> (ValueRef, Ty<'tcx>) {
39
    debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts);
40

41
    assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
42

43
    let _icx = push_ctxt("monomorphic_fn");
44

45
    let instance = Instance::new(fn_id, psubsts);
46

47
    let item_ty = ccx.tcx().lookup_item_type(fn_id).ty;
48

49
    debug!("monomorphic_fn about to subst into {:?}", item_ty);
50 51
    let mono_ty = apply_param_substs(ccx.tcx(), psubsts, &item_ty);
    debug!("mono_ty = {:?} (post-substitution)", mono_ty);
52

53
    match ccx.instances().borrow().get(&instance) {
54
        Some(&val) => {
55 56
            debug!("leaving monomorphic fn {:?}", instance);
            return (val, mono_ty);
57 58 59 60
        }
        None => ()
    }

61
    debug!("monomorphic_fn({:?})", instance);
62

63
    ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
64

65 66
    let depth;
    {
67
        let mut monomorphizing = ccx.monomorphizing().borrow_mut();
68
        depth = match monomorphizing.get(&fn_id) {
69 70 71
            Some(&d) => d, None => 0
        };

72 73
        debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1);

74 75 76
        // Random cut-off -- code that needs to instantiate the same function
        // recursively more than thirty times can probably safely be assumed
        // to be causing an infinite expansion.
E
Eduard Burtescu 已提交
77
        if depth > ccx.sess().recursion_limit.get() {
78 79 80 81 82 83 84
            let error = format!("reached the recursion limit while instantiating `{}`",
                                instance);
            if let Some(id) = ccx.tcx().map.as_local_node_id(fn_id) {
                ccx.sess().span_fatal(ccx.tcx().map.span(id), &error);
            } else {
                ccx.sess().fatal(&error);
            }
85
        }
86

87
        monomorphizing.insert(fn_id, depth + 1);
88 89
    }

90
    let symbol = instance.symbol_name(ccx.shared());
R
Russell 已提交
91

92 93
    debug!("monomorphize_fn mangled to {}", symbol);
    assert!(declare::get_defined_value(ccx, &symbol).is_none());
94

95
    // FIXME(nagisa): perhaps needs a more fine grained selection?
96
    let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty);
97 98
    // FIXME(eddyb) Doubt all extern fn should allow unwinding.
    attributes::unwind(lldecl, true);
R
Russell 已提交
99

100
    ccx.instances().borrow_mut().insert(instance, lldecl);
101

102 103 104 105 106 107 108 109 110 111 112 113 114
    // we can only monomorphize things in this crate (or inlined into it)
    let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap();
    let map_node = errors::expect(
        ccx.sess().diagnostic(),
        ccx.tcx().map.find(fn_node_id),
        || {
            format!("while instantiating `{}`, couldn't find it in \
                     the item map (may have attempted to monomorphize \
                     an item defined in a different crate?)",
                    instance)
        });
    match map_node {
        hir_map::NodeItem(&hir::Item {
115
            ref attrs, node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
116 117 118
        }) |
        hir_map::NodeTraitItem(&hir::TraitItem {
            ref attrs, node: hir::MethodTraitItem(
119
                hir::MethodSig { ref decl, .. }, Some(ref body)), ..
120 121 122
        }) |
        hir_map::NodeImplItem(&hir::ImplItem {
            ref attrs, node: hir::ImplItemKind::Method(
123
                hir::MethodSig { ref decl, .. }, ref body), ..
124 125 126
        }) => {
            attributes::from_fn_attrs(ccx, attrs, lldecl);

127 128
            let is_first = !ccx.available_monomorphizations().borrow()
                                                             .contains(&symbol);
129
            if is_first {
130
                ccx.available_monomorphizations().borrow_mut().insert(symbol.clone());
131
            }
132

133 134
            let trans_everywhere = attr::requests_inline(attrs);
            if trans_everywhere || is_first {
135 136
                let origin = if is_first { base::OriginalTranslation } else { base::InlinedCopy };
                base::update_linkage(ccx, lldecl, None, origin);
137
                trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id);
138 139 140 141
            } else {
                // We marked the value as using internal linkage earlier, but that is illegal for
                // declarations, so switch back to external linkage.
                llvm::SetLinkage(lldecl, llvm::ExternalLinkage);
142
            }
143
        }
144 145 146 147 148

        hir_map::NodeVariant(_) | hir_map::NodeStructCtor(_) => {
            let disr = match map_node {
                hir_map::NodeVariant(_) => {
                    Disr::from(inlined_variant_def(ccx, fn_node_id).disr_val)
149
                }
150
                hir_map::NodeStructCtor(_) => Disr(0),
151
                _ => bug!()
152 153 154
            };
            attributes::inline(lldecl, attributes::InlineAttr::Hint);
            base::trans_ctor_shim(ccx, fn_node_id, disr, psubsts, lldecl);
155
        }
156

157
        _ => bug!("can't monomorphize a {:?}", map_node)
158
    };
159

160
    ccx.monomorphizing().borrow_mut().insert(fn_id, depth);
161

162
    debug!("leaving monomorphic fn {}", ccx.tcx().item_path_str(fn_id));
163
    (lldecl, mono_ty)
164 165
}

166 167
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Instance<'tcx> {
N
Niko Matsakis 已提交
168
    pub def: DefId,
169
    pub substs: &'tcx Substs<'tcx>,
E
Eduard Burtescu 已提交
170
}
171

172 173
impl<'tcx> fmt::Display for Instance<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174
        ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[],
175 176 177 178 179
                             |tcx| tcx.lookup_item_type(self.def).generics)
    }
}

impl<'tcx> Instance<'tcx> {
180 181 182 183 184
    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
               -> Instance<'tcx> {
        assert!(substs.regions.iter().all(|&r| r == ty::ReStatic));
        Instance { def: def_id, substs: substs }
    }
185 186
    pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
        Instance::new(def_id, scx.empty_substs_for_def_id(def_id))
187 188 189
    }
}

190 191
/// Monomorphizes a type from the AST by first applying the in-scope
/// substitutions and then normalizing any associated types.
192
pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
193 194 195
                                       param_substs: &Substs<'tcx>,
                                       value: &T)
                                       -> T
196
    where T: TransNormalize<'tcx>
197 198
{
    let substituted = value.subst(tcx, param_substs);
199
    tcx.normalize_associated_type(&substituted)
200 201
}

202 203

/// Returns the normalized type of a struct field
204
pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
205 206 207
                          param_substs: &Substs<'tcx>,
                          f: ty::FieldDef<'tcx>)
                          -> Ty<'tcx>
208
{
209
    tcx.normalize_associated_type(&f.ty(tcx, param_substs))
210
}