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