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