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
10use rustc_hir::LangItem;
11use rustc_hir::def_id::DefId;
12use rustc_span::Span;
13use rustc_target::spec::PanicStrategy;
14
15use crate::ty::{self, TyCtxt};
16
17impl<'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.
94pub 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