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;
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>,
19 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)]
20 pub enum InstanceDef<'tcx> {
24 /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
27 /// `fn()` pointer where the function itself cannot be turned into a pointer.
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`).
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).
40 /// `<fn() as FnTrait>::call_*`
41 /// `DefId` is `FnTrait::call_*`.
42 FnPtrShim(DefId, Ty<'tcx>),
44 /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly
45 /// codegen'd as virtual calls.
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),
51 /// `<[mut closure] as FnOnce>::call_once`
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
60 DropGlue(DefId, Option<Ty<'tcx>>),
62 ///`<T as Clone>::clone` shim.
63 CloneShim(DefId, Ty<'tcx>),
66 impl<'tcx> Instance<'tcx> {
67 /// Returns the `Ty` corresponding to this `Instance`,
68 /// with generic substitutions applied and lifetimes erased.
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
83 if self.substs.has_param_types() {
84 bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs);
86 tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty)
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)
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.
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
107 if !tcx.sess.opts.share_generics() {
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() {
117 // If this a non-generic instance, it cannot be a shared monomorphization.
118 self.substs.non_erasable_generics().next()?;
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),
130 impl<'tcx> InstanceDef<'tcx> {
132 pub fn def_id(&self) -> DefId {
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,
147 pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
148 tcx.get_attrs(self.def_id())
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,
163 match tcx.def_key(def_id).disambiguated_data.data {
164 DefPathData::Ctor | DefPathData::ClosureExpr => true,
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) {
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() {
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.
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()
200 tcx.codegen_fn_attrs(self.def_id()).requests_inline()
203 pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
205 InstanceDef::Item(def_id) => {
206 tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
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)?;
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),
236 impl<'tcx> Instance<'tcx> {
237 pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> {
239 !substs.has_escaping_bound_vars(),
240 "substs of instance {:?} not normalized for codegen: {:?}",
244 Instance { def: InstanceDef::Item(def_id), substs }
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))
252 pub fn def_id(&self) -> DefId {
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,
260 /// Returns `None` if we cannot resolve `Instance` to a specific instance.
261 /// For example, in a context like this,
264 /// fn foo<T: Debug>(t: T) { ... }
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.)
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
276 param_env: ty::ParamEnv<'tcx>,
278 substs: SubstsRef<'tcx>,
279 ) -> Option<Instance<'tcx>> {
280 (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs)
283 pub fn resolve_for_fn_ptr(
285 param_env: ty::ParamEnv<'tcx>,
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| {
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);
296 InstanceDef::Virtual(def_id, _) => {
297 debug!(" => fn pointer created for virtual call");
298 resolved.def = InstanceDef::ReifyShim(def_id);
307 pub fn resolve_for_vtable(
309 param_env: ty::ParamEnv<'tcx>,
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;
319 debug!(" => associated item with unsizeable self: Self");
320 Some(Instance { def: InstanceDef::VtableShim(def_id), substs })
322 Instance::resolve(tcx, param_env, def_id, substs)
326 pub fn resolve_closure(
329 substs: ty::SubstsRef<'tcx>,
330 requested_kind: ty::ClosureKind,
331 ) -> Instance<'tcx> {
332 let actual_kind = substs.as_closure().kind(def_id, tcx);
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),
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()
346 pub fn fn_once_adapter_instance(
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();
354 .associated_items(fn_once)
355 .in_definition_order()
356 .find(|it| it.kind == ty::AssocKind::Method)
359 let def = ty::InstanceDef::ClosureOnceShim { call_once };
361 let self_ty = tcx.mk_closure(closure_did, substs);
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()]);
368 debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
369 Instance { def, substs }
372 pub fn is_vtable_shim(&self) -> bool {
373 if let InstanceDef::VtableShim(..) = self.def { true } else { false }
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.
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.
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:
400 // fn call_once(self, ...) { call_mut(&self, ...) }
401 // fn call_once(mut self, ...) { call_mut(&mut self, ...) }
403 // These are both the same at codegen time.
406 (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()),
410 fn resolve_instance_default(
412 _param_env: ty::ParamEnv<'tcx>,
414 _substs: SubstsRef<'tcx>,
415 ) -> Option<Instance<'tcx>> {
419 pub static RESOLVE_INSTANCE: AtomicRef<
425 ) -> Option<Instance<'tcx>>,
426 > = AtomicRef::new(&(resolve_instance_default as _));