-
-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Expand file tree
/
Copy pathitem.rs
More file actions
204 lines (188 loc) · 8.26 KB
/
Copy pathitem.rs
File metadata and controls
204 lines (188 loc) · 8.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::mir::mono::MonoItem;
use rustc::session::config::OptLevel;
use rustc::ty::{self, TyCtxt, Instance};
use rustc::ty::subst::InternalSubsts;
use rustc::ty::print::obsolete::DefPathBasedNames;
use syntax::attr::InlineAttr;
use std::fmt;
use rustc::mir::mono::Linkage;
use syntax_pos::symbol::InternedString;
use syntax::source_map::Span;
/// Describes how a monomorphization will be instantiated in object files.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum InstantiationMode {
/// There will be exactly one instance of the given MonoItem. It will have
/// external linkage so that it can be linked to from other codegen units.
GloballyShared {
/// In some compilation scenarios we may decide to take functions that
/// are typically `LocalCopy` and instead move them to `GloballyShared`
/// to avoid codegenning them a bunch of times. In this situation,
/// however, our local copy may conflict with other crates also
/// inlining the same function.
///
/// This flag indicates that this situation is occurring, and informs
/// symbol name calculation that some extra mangling is needed to
/// avoid conflicts. Note that this may eventually go away entirely if
/// ThinLTO enables us to *always* have a globally shared instance of a
/// function within one crate's compilation.
may_conflict: bool,
},
/// Each codegen unit containing a reference to the given MonoItem will
/// have its own private copy of the function (with internal linkage).
LocalCopy,
}
pub trait MonoItemExt<'tcx>: fmt::Debug {
fn as_mono_item(&self) -> &MonoItem<'tcx>;
fn is_generic_fn(&self) -> bool {
match *self.as_mono_item() {
MonoItem::Fn(ref instance) => {
instance.substs.non_erasable_generics().next().is_some()
}
MonoItem::Static(..) |
MonoItem::GlobalAsm(..) => false,
}
}
fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
match *self.as_mono_item() {
MonoItem::Fn(instance) => tcx.symbol_name(instance),
MonoItem::Static(def_id) => {
tcx.symbol_name(Instance::mono(tcx, def_id))
}
MonoItem::GlobalAsm(hir_id) => {
let def_id = tcx.hir().local_def_id(hir_id);
ty::SymbolName {
name: InternedString::intern(&format!("global_asm_{:?}", def_id))
}
}
}
}
fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
let inline_in_all_cgus =
tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
tcx.sess.opts.optimize != OptLevel::No
}) && !tcx.sess.opts.cg.link_dead_code;
match *self.as_mono_item() {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
// If this function isn't inlined or otherwise has explicit
// linkage, then we'll be creating a globally shared version.
if self.explicit_linkage(tcx).is_some() ||
!instance.def.requires_local(tcx) ||
Some(instance.def_id()) == entry_def_id
{
return InstantiationMode::GloballyShared { may_conflict: false }
}
// At this point we don't have explicit linkage and we're an
// inlined function. If we're inlining into all CGUs then we'll
// be creating a local copy per CGU
if inline_in_all_cgus {
return InstantiationMode::LocalCopy
}
// Finally, if this is `#[inline(always)]` we're sure to respect
// that with an inline copy per CGU, but otherwise we'll be
// creating one copy of this `#[inline]` function which may
// conflict with upstream crates as it could be an exported
// symbol.
match tcx.codegen_fn_attrs(instance.def_id()).inline {
InlineAttr::Always => InstantiationMode::LocalCopy,
_ => {
InstantiationMode::GloballyShared { may_conflict: true }
}
}
}
MonoItem::Static(..) |
MonoItem::GlobalAsm(..) => {
InstantiationMode::GloballyShared { may_conflict: false }
}
}
}
fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option<Linkage> {
let def_id = match *self.as_mono_item() {
MonoItem::Fn(ref instance) => instance.def_id(),
MonoItem::Static(def_id) => def_id,
MonoItem::GlobalAsm(..) => return None,
};
let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
codegen_fn_attrs.linkage
}
/// Returns `true` if this instance is instantiable - whether it has no unsatisfied
/// predicates.
///
/// In order to codegen an item, all of its predicates must hold, because
/// otherwise the item does not make sense. Type-checking ensures that
/// the predicates of every item that is *used by* a valid item *do*
/// hold, so we can rely on that.
///
/// However, we codegen collector roots (reachable items) and functions
/// in vtables when they are seen, even if they are not used, and so they
/// might not be instantiable. For example, a programmer can define this
/// public function:
///
/// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
/// <&mut () as Clone>::clone(&s);
/// }
///
/// That function can't be codegened, because the method `<&mut () as Clone>::clone`
/// does not exist. Luckily for us, that function can't ever be used,
/// because that would require for `&'a mut (): Clone` to hold, so we
/// can just not emit any code, or even a linker reference for it.
///
/// Similarly, if a vtable method has such a signature, and therefore can't
/// be used, we can just not emit it and have a placeholder (a null pointer,
/// which will never be accessed) in its place.
fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool {
debug!("is_instantiable({:?})", self);
let (def_id, substs) = match *self.as_mono_item() {
MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()),
// global asm never has predicates
MonoItem::GlobalAsm(..) => return true
};
tcx.substitute_normalize_and_test_predicates((def_id, &substs))
}
fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {
return match *self.as_mono_item() {
MonoItem::Fn(instance) => {
to_string_internal(tcx, "fn ", instance, debug)
},
MonoItem::Static(def_id) => {
let instance = Instance::new(def_id, tcx.intern_substs(&[]));
to_string_internal(tcx, "static ", instance, debug)
},
MonoItem::GlobalAsm(..) => {
"global_asm".to_string()
}
};
fn to_string_internal<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
prefix: &str,
instance: Instance<'tcx>,
debug: bool,
) -> String {
let mut result = String::with_capacity(32);
result.push_str(prefix);
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_instance_as_string(instance, &mut result, debug);
result
}
}
fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
match *self.as_mono_item() {
MonoItem::Fn(Instance { def, .. }) => {
tcx.hir().as_local_hir_id(def.def_id())
}
MonoItem::Static(def_id) => {
tcx.hir().as_local_hir_id(def_id)
}
MonoItem::GlobalAsm(hir_id) => {
Some(hir_id)
}
}.map(|hir_id| tcx.hir().span(hir_id))
}
}
impl MonoItemExt<'tcx> for MonoItem<'tcx> {
fn as_mono_item(&self) -> &MonoItem<'tcx> {
self
}
}