]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/instance.rs
Rollup merge of #69735 - tmiasko:bootstrap-sanitizers-hash, r=Mark-Simulacrum
[rust.git] / src / librustc / ty / instance.rs
1 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2 use crate::middle::lang_items::DropInPlaceFnLangItem;
3 use crate::ty::print::{FmtPrinter, Printer};
4 use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
5 use rustc_data_structures::AtomicRef;
6 use rustc_hir::def::Namespace;
7 use rustc_hir::def_id::{CrateNum, DefId};
8 use rustc_macros::HashStable;
9
10 use std::fmt;
11
12 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
13 #[derive(HashStable, Lift)]
14 pub struct Instance<'tcx> {
15     pub def: InstanceDef<'tcx>,
16     pub substs: SubstsRef<'tcx>,
17 }
18
19 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
20 pub enum InstanceDef<'tcx> {
21     Item(DefId),
22     Intrinsic(DefId),
23
24     /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
25     VtableShim(DefId),
26
27     /// `fn()` pointer where the function itself cannot be turned into a pointer.
28     ///
29     /// One example is `<dyn Trait as Trait>::fn`, where the shim contains
30     /// a virtual call, which codegen supports only via a direct call to the
31     /// `<dyn Trait as Trait>::fn` instance (an `InstanceDef::Virtual`).
32     ///
33     /// Another example is functions annotated with `#[track_caller]`, which
34     /// must have their implicit caller location argument populated for a call.
35     /// Because this is a required part of the function's ABI but can't be tracked
36     /// as a property of the function pointer, we use a single "caller location"
37     /// (the definition of the function itself).
38     ReifyShim(DefId),
39
40     /// `<fn() as FnTrait>::call_*`
41     /// `DefId` is `FnTrait::call_*`.
42     FnPtrShim(DefId, Ty<'tcx>),
43
44     /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
45     /// codegen'd as virtual calls.
46     ///
47     /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used
48     /// (see `ReifyShim` above for more details on that).
49     Virtual(DefId, usize),
50
51     /// `<[mut closure] as FnOnce>::call_once`
52     ClosureOnceShim {
53         call_once: DefId,
54     },
55
56     /// `core::ptr::drop_in_place::<T>`.
57     /// The `DefId` is for `core::ptr::drop_in_place`.
58     /// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop
59     /// glue.
60     DropGlue(DefId, Option<Ty<'tcx>>),
61
62     ///`<T as Clone>::clone` shim.
63     CloneShim(DefId, Ty<'tcx>),
64 }
65
66 impl<'tcx> Instance<'tcx> {
67     /// Returns the `Ty` corresponding to this `Instance`,
68     /// with generic substitutions applied and lifetimes erased.
69     ///
70     /// This method can only be called when the 'substs' for this Instance
71     /// are fully monomorphic (no `ty::Param`'s are present).
72     /// This is usually the case (e.g. during codegen).
73     /// However, during constant evaluation, we may want
74     /// to try to resolve a `Instance` using generic parameters
75     /// (e.g. when we are attempting to to do const-propagation).
76     /// In this case, `Instance.ty_env` should be used to provide
77     /// the `ParamEnv` for our generic context.
78     pub fn monomorphic_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
79         let ty = tcx.type_of(self.def.def_id());
80         // There shouldn't be any params - if there are, then
81         // Instance.ty_env should have been used to provide the proper
82         // ParamEnv
83         if self.substs.has_param_types() {
84             bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs);
85         }
86         tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty)
87     }
88
89     /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during
90     /// normalization. This method is only really useful during constant evaluation,
91     /// where we are dealing with potentially generic types.
92     pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
93         let ty = tcx.type_of(self.def.def_id());
94         tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
95     }
96
97     /// Finds a crate that contains a monomorphization of this instance that
98     /// can be linked to from the local crate. A return value of `None` means
99     /// no upstream crate provides such an exported monomorphization.
100     ///
101     /// This method already takes into account the global `-Zshare-generics`
102     /// setting, always returning `None` if `share-generics` is off.
103     pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
104         // If we are not in share generics mode, we don't link to upstream
105         // monomorphizations but always instantiate our own internal versions
106         // instead.
107         if !tcx.sess.opts.share_generics() {
108             return None;
109         }
110
111         // If this is an item that is defined in the local crate, no upstream
112         // crate can know about it/provide a monomorphization.
113         if self.def_id().is_local() {
114             return None;
115         }
116
117         // If this a non-generic instance, it cannot be a shared monomorphization.
118         self.substs.non_erasable_generics().next()?;
119
120         match self.def {
121             InstanceDef::Item(def_id) => tcx
122                 .upstream_monomorphizations_for(def_id)
123                 .and_then(|monos| monos.get(&self.substs).cloned()),
124             InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs),
125             _ => None,
126         }
127     }
128 }
129
130 impl<'tcx> InstanceDef<'tcx> {
131     #[inline]
132     pub fn def_id(&self) -> DefId {
133         match *self {
134             InstanceDef::Item(def_id)
135             | InstanceDef::VtableShim(def_id)
136             | InstanceDef::ReifyShim(def_id)
137             | InstanceDef::FnPtrShim(def_id, _)
138             | InstanceDef::Virtual(def_id, _)
139             | InstanceDef::Intrinsic(def_id)
140             | InstanceDef::ClosureOnceShim { call_once: def_id }
141             | InstanceDef::DropGlue(def_id, _)
142             | InstanceDef::CloneShim(def_id, _) => def_id,
143         }
144     }
145
146     #[inline]
147     pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
148         tcx.get_attrs(self.def_id())
149     }
150
151     /// Returns `true` if the LLVM version of this instance is unconditionally
152     /// marked with `inline`. This implies that a copy of this instance is
153     /// generated in every codegen unit.
154     /// Note that this is only a hint. See the documentation for
155     /// `generates_cgu_internal_copy` for more information.
156     pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool {
157         use crate::hir::map::DefPathData;
158         let def_id = match *self {
159             ty::InstanceDef::Item(def_id) => def_id,
160             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
161             _ => return true,
162         };
163         match tcx.def_key(def_id).disambiguated_data.data {
164             DefPathData::Ctor | DefPathData::ClosureExpr => true,
165             _ => false,
166         }
167     }
168
169     /// Returns `true` if the machine code for this instance is instantiated in
170     /// each codegen unit that references it.
171     /// Note that this is only a hint! The compiler can globally decide to *not*
172     /// do this in order to speed up compilation. CGU-internal copies are
173     /// only exist to enable inlining. If inlining is not performed (e.g. at
174     /// `-Copt-level=0`) then the time for generating them is wasted and it's
175     /// better to create a single copy with external linkage.
176     pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool {
177         if self.requires_inline(tcx) {
178             return true;
179         }
180         if let ty::InstanceDef::DropGlue(.., Some(ty)) = *self {
181             // Drop glue generally wants to be instantiated at every codegen
182             // unit, but without an #[inline] hint. We should make this
183             // available to normal end-users.
184             if tcx.sess.opts.incremental.is_none() {
185                 return true;
186             }
187             // When compiling with incremental, we can generate a *lot* of
188             // codegen units. Including drop glue into all of them has a
189             // considerable compile time cost.
190             //
191             // We include enums without destructors to allow, say, optimizing
192             // drops of `Option::None` before LTO. We also respect the intent of
193             // `#[inline]` on `Drop::drop` implementations.
194             return ty.ty_adt_def().map_or(true, |adt_def| {
195                 adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| {
196                     tcx.codegen_fn_attrs(dtor.did).requests_inline()
197                 })
198             });
199         }
200         tcx.codegen_fn_attrs(self.def_id()).requests_inline()
201     }
202
203     pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
204         match *self {
205             InstanceDef::Item(def_id) => {
206                 tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
207             }
208             _ => false,
209         }
210     }
211 }
212
213 impl<'tcx> fmt::Display for Instance<'tcx> {
214     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215         ty::tls::with(|tcx| {
216             let substs = tcx.lift(&self.substs).expect("could not lift for printing");
217             FmtPrinter::new(tcx, &mut *f, Namespace::ValueNS)
218                 .print_def_path(self.def_id(), substs)?;
219             Ok(())
220         })?;
221
222         match self.def {
223             InstanceDef::Item(_) => Ok(()),
224             InstanceDef::VtableShim(_) => write!(f, " - shim(vtable)"),
225             InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
226             InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
227             InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
228             InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({:?})", ty),
229             InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"),
230             InstanceDef::DropGlue(_, ty) => write!(f, " - shim({:?})", ty),
231             InstanceDef::CloneShim(_, ty) => write!(f, " - shim({:?})", ty),
232         }
233     }
234 }
235
236 impl<'tcx> Instance<'tcx> {
237     pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> {
238         assert!(
239             !substs.has_escaping_bound_vars(),
240             "substs of instance {:?} not normalized for codegen: {:?}",
241             def_id,
242             substs
243         );
244         Instance { def: InstanceDef::Item(def_id), substs }
245     }
246
247     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
248         Instance::new(def_id, tcx.empty_substs_for_def_id(def_id))
249     }
250
251     #[inline]
252     pub fn def_id(&self) -> DefId {
253         self.def.def_id()
254     }
255
256     /// Resolves a `(def_id, substs)` pair to an (optional) instance -- most commonly,
257     /// this is used to find the precise code that will run for a trait method invocation,
258     /// if known.
259     ///
260     /// Returns `None` if we cannot resolve `Instance` to a specific instance.
261     /// For example, in a context like this,
262     ///
263     /// ```
264     /// fn foo<T: Debug>(t: T) { ... }
265     /// ```
266     ///
267     /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not
268     /// know what code ought to run. (Note that this setting is also affected by the
269     /// `RevealMode` in the parameter environment.)
270     ///
271     /// Presuming that coherence and type-check have succeeded, if this method is invoked
272     /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return
273     /// `Some`.
274     pub fn resolve(
275         tcx: TyCtxt<'tcx>,
276         param_env: ty::ParamEnv<'tcx>,
277         def_id: DefId,
278         substs: SubstsRef<'tcx>,
279     ) -> Option<Instance<'tcx>> {
280         (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs)
281     }
282
283     pub fn resolve_for_fn_ptr(
284         tcx: TyCtxt<'tcx>,
285         param_env: ty::ParamEnv<'tcx>,
286         def_id: DefId,
287         substs: SubstsRef<'tcx>,
288     ) -> Option<Instance<'tcx>> {
289         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
290         Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
291             match resolved.def {
292                 InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
293                     debug!(" => fn pointer created for function with #[track_caller]");
294                     resolved.def = InstanceDef::ReifyShim(def_id);
295                 }
296                 InstanceDef::Virtual(def_id, _) => {
297                     debug!(" => fn pointer created for virtual call");
298                     resolved.def = InstanceDef::ReifyShim(def_id);
299                 }
300                 _ => {}
301             }
302
303             resolved
304         })
305     }
306
307     pub fn resolve_for_vtable(
308         tcx: TyCtxt<'tcx>,
309         param_env: ty::ParamEnv<'tcx>,
310         def_id: DefId,
311         substs: SubstsRef<'tcx>,
312     ) -> Option<Instance<'tcx>> {
313         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
314         let fn_sig = tcx.fn_sig(def_id);
315         let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty()
316             && fn_sig.input(0).skip_binder().is_param(0)
317             && tcx.generics_of(def_id).has_self;
318         if is_vtable_shim {
319             debug!(" => associated item with unsizeable self: Self");
320             Some(Instance { def: InstanceDef::VtableShim(def_id), substs })
321         } else {
322             Instance::resolve(tcx, param_env, def_id, substs)
323         }
324     }
325
326     pub fn resolve_closure(
327         tcx: TyCtxt<'tcx>,
328         def_id: DefId,
329         substs: ty::SubstsRef<'tcx>,
330         requested_kind: ty::ClosureKind,
331     ) -> Instance<'tcx> {
332         let actual_kind = substs.as_closure().kind(def_id, tcx);
333
334         match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
335             Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
336             _ => Instance::new(def_id, substs),
337         }
338     }
339
340     pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
341         let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None);
342         let substs = tcx.intern_substs(&[ty.into()]);
343         Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
344     }
345
346     pub fn fn_once_adapter_instance(
347         tcx: TyCtxt<'tcx>,
348         closure_did: DefId,
349         substs: ty::SubstsRef<'tcx>,
350     ) -> Instance<'tcx> {
351         debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs);
352         let fn_once = tcx.lang_items().fn_once_trait().unwrap();
353         let call_once = tcx
354             .associated_items(fn_once)
355             .in_definition_order()
356             .find(|it| it.kind == ty::AssocKind::Method)
357             .unwrap()
358             .def_id;
359         let def = ty::InstanceDef::ClosureOnceShim { call_once };
360
361         let self_ty = tcx.mk_closure(closure_did, substs);
362
363         let sig = substs.as_closure().sig(closure_did, tcx);
364         let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
365         assert_eq!(sig.inputs().len(), 1);
366         let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
367
368         debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
369         Instance { def, substs }
370     }
371
372     pub fn is_vtable_shim(&self) -> bool {
373         if let InstanceDef::VtableShim(..) = self.def { true } else { false }
374     }
375 }
376
377 fn needs_fn_once_adapter_shim(
378     actual_closure_kind: ty::ClosureKind,
379     trait_closure_kind: ty::ClosureKind,
380 ) -> Result<bool, ()> {
381     match (actual_closure_kind, trait_closure_kind) {
382         (ty::ClosureKind::Fn, ty::ClosureKind::Fn)
383         | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut)
384         | (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
385             // No adapter needed.
386             Ok(false)
387         }
388         (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
389             // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
390             // `fn(&mut self, ...)`. In fact, at codegen time, these are
391             // basically the same thing, so we can just return llfn.
392             Ok(false)
393         }
394         (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce)
395         | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
396             // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
397             // self, ...)`.  We want a `fn(self, ...)`. We can produce
398             // this by doing something like:
399             //
400             //     fn call_once(self, ...) { call_mut(&self, ...) }
401             //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
402             //
403             // These are both the same at codegen time.
404             Ok(true)
405         }
406         (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()),
407     }
408 }
409
410 fn resolve_instance_default(
411     _tcx: TyCtxt<'tcx>,
412     _param_env: ty::ParamEnv<'tcx>,
413     _def_id: DefId,
414     _substs: SubstsRef<'tcx>,
415 ) -> Option<Instance<'tcx>> {
416     unimplemented!()
417 }
418
419 pub static RESOLVE_INSTANCE: AtomicRef<
420     for<'tcx> fn(
421         TyCtxt<'tcx>,
422         ty::ParamEnv<'tcx>,
423         DefId,
424         SubstsRef<'tcx>,
425     ) -> Option<Instance<'tcx>>,
426 > = AtomicRef::new(&(resolve_instance_default as _));