| 1 | //! Detecting lang items. |
| 2 | //! |
| 3 | //! Language items are items that represent concepts intrinsic to the language |
| 4 | //! itself. Examples are: |
| 5 | //! |
| 6 | //! * Traits that specify "kinds"; e.g., `Sync`, `Send`. |
| 7 | //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. |
| 8 | //! * Functions called by the compiler itself. |
| 9 | |
| 10 | use rustc_hir::LangItem; |
| 11 | use rustc_hir::def_id::DefId; |
| 12 | use rustc_span::Span; |
| 13 | use rustc_target::spec::PanicStrategy; |
| 14 | |
| 15 | use crate::ty::{self, TyCtxt}; |
| 16 | |
| 17 | impl<'tcx> TyCtxt<'tcx> { |
| 18 | /// Returns the `DefId` for a given `LangItem`. |
| 19 | /// If not found, fatally aborts compilation. |
| 20 | pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId { |
| 21 | self.lang_items().get(lang_item).unwrap_or_else(|| { |
| 22 | self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); |
| 23 | }) |
| 24 | } |
| 25 | |
| 26 | pub fn is_lang_item(self, def_id: DefId, lang_item: LangItem) -> bool { |
| 27 | self.lang_items().get(lang_item) == Some(def_id) |
| 28 | } |
| 29 | |
| 30 | pub fn as_lang_item(self, def_id: DefId) -> Option<LangItem> { |
| 31 | self.lang_items().from_def_id(def_id) |
| 32 | } |
| 33 | |
| 34 | /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, |
| 35 | /// returns a corresponding [`ty::ClosureKind`]. |
| 36 | /// For any other [`DefId`] return `None`. |
| 37 | pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> { |
| 38 | let items = self.lang_items(); |
| 39 | match Some(id) { |
| 40 | x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), |
| 41 | x if x == items.fn_mut_trait() => Some(ty::ClosureKind::FnMut), |
| 42 | x if x == items.fn_once_trait() => Some(ty::ClosureKind::FnOnce), |
| 43 | _ => None, |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | /// Given a [`DefId`] of one of the `AsyncFn`, `AsyncFnMut` or `AsyncFnOnce` traits, |
| 48 | /// returns a corresponding [`ty::ClosureKind`]. |
| 49 | /// For any other [`DefId`] return `None`. |
| 50 | pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> { |
| 51 | let items = self.lang_items(); |
| 52 | match Some(id) { |
| 53 | x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn), |
| 54 | x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut), |
| 55 | x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce), |
| 56 | _ => None, |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family |
| 61 | /// trait, if it is defined. |
| 62 | pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> { |
| 63 | let items = self.lang_items(); |
| 64 | match kind { |
| 65 | ty::ClosureKind::Fn => items.fn_trait(), |
| 66 | ty::ClosureKind::FnMut => items.fn_mut_trait(), |
| 67 | ty::ClosureKind::FnOnce => items.fn_once_trait(), |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family |
| 72 | /// trait, if it is defined. |
| 73 | pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> { |
| 74 | let items = self.lang_items(); |
| 75 | match kind { |
| 76 | ty::ClosureKind::Fn => items.async_fn_trait(), |
| 77 | ty::ClosureKind::FnMut => items.async_fn_mut_trait(), |
| 78 | ty::ClosureKind::FnOnce => items.async_fn_once_trait(), |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | /// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits. |
| 83 | pub fn is_fn_trait(self, id: DefId) -> bool { |
| 84 | self.fn_trait_kind_from_def_id(id).is_some() |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /// Returns `true` if the specified `lang_item` must be present for this |
| 89 | /// compilation. |
| 90 | /// |
| 91 | /// Not all lang items are always required for each compilation, particularly in |
| 92 | /// the case of panic=abort. In these situations some lang items are injected by |
| 93 | /// crates and don't actually need to be defined in libstd. |
| 94 | pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { |
| 95 | // If we're not compiling with unwinding, we won't actually need these |
| 96 | // symbols. Other panic runtimes ensure that the relevant symbols are |
| 97 | // available to link things together, but they're never exercised. |
| 98 | match tcx.sess.panic_strategy() { |
| 99 | PanicStrategy::Abort => { |
| 100 | lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo |
| 101 | } |
| 102 | PanicStrategy::Unwind => true, |
| 103 | } |
| 104 | } |
| 105 | |