11use crate :: hir:: def_id:: { DefId , CrateNum , LOCAL_CRATE } ;
22use crate :: hir:: HirId ;
33use 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 } ;
57use crate :: util:: nodemap:: FxHashMap ;
8+ use crate :: ty:: print:: obsolete:: DefPathBasedNames ;
69use rustc_data_structures:: base_n;
710use rustc_data_structures:: stable_hasher:: { HashStable , StableHasherResult ,
811 StableHasher } ;
912use crate :: ich:: { Fingerprint , StableHashingContext , NodeIdHashingMode } ;
13+ use crate :: session:: config:: OptLevel ;
1014use std:: fmt;
1115use std:: hash:: Hash ;
1216
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+
1342#[ derive( PartialEq , Eq , Clone , Copy , Debug , Hash ) ]
1443pub enum MonoItem < ' tcx > {
1544 Fn ( Instance < ' tcx > ) ,
@@ -31,6 +60,166 @@ impl<'tcx> MonoItem<'tcx> {
3160 MonoItem :: GlobalAsm ( _) => 1 ,
3261 }
3362 }
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+ }
34223}
35224
36225impl < ' a , ' tcx > HashStable < StableHashingContext < ' a > > for MonoItem < ' tcx > {
0 commit comments