Skip to main content

rustc_middle/middle/
lang_items.rs

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::attrs::lang_items::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: Span) -> DefId {
21        self.lang_items().get(lang_item).unwrap_or_else(|| {
22            self.dcx()
23                .emit_fatal(crate::diagnostics::RequiresLangItem { span, name: lang_item.name() });
24        })
25    }
26
27    pub fn is_lang_item(self, def_id: DefId, lang_item: LangItem) -> bool {
28        self.lang_items().get(lang_item) == Some(def_id)
29    }
30
31    pub fn as_lang_item(self, def_id: DefId) -> Option<LangItem> {
32        self.lang_items().from_def_id(def_id)
33    }
34
35    /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits,
36    /// returns a corresponding [`ty::ClosureKind`].
37    /// For any other [`DefId`] return `None`.
38    pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
39        match self.as_lang_item(id)? {
40            LangItem::Fn => Some(ty::ClosureKind::Fn),
41            LangItem::FnMut => Some(ty::ClosureKind::FnMut),
42            LangItem::FnOnce => 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        match self.as_lang_item(id)? {
52            LangItem::AsyncFn => Some(ty::ClosureKind::Fn),
53            LangItem::AsyncFnMut => Some(ty::ClosureKind::FnMut),
54            LangItem::AsyncFnOnce => Some(ty::ClosureKind::FnOnce),
55            _ => None,
56        }
57    }
58
59    /// Given a [`DefId`], returns whether it is one of the built-in callable
60    /// traits: `Fn`/`FnMut`/`FnOnce` or `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`.
61    ///
62    /// These built-in callable traits all model their inputs using the
63    /// `rust-call` ABI, which is tupled at the type level.
64    pub fn is_callable_trait(self, id: DefId) -> bool {
65        #[allow(non_exhaustive_omitted_patterns)] match self.as_lang_item(id) {
    Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce | LangItem::AsyncFn
        | LangItem::AsyncFnMut | LangItem::AsyncFnOnce) => true,
    _ => false,
}matches!(
66            self.as_lang_item(id),
67            Some(
68                LangItem::Fn
69                    | LangItem::FnMut
70                    | LangItem::FnOnce
71                    | LangItem::AsyncFn
72                    | LangItem::AsyncFnMut
73                    | LangItem::AsyncFnOnce
74            )
75        )
76    }
77
78    /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
79    /// trait, if it is defined.
80    pub fn fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
81        let items = self.lang_items();
82        match kind {
83            ty::ClosureKind::Fn => items.fn_trait(),
84            ty::ClosureKind::FnMut => items.fn_mut_trait(),
85            ty::ClosureKind::FnOnce => items.fn_once_trait(),
86        }
87    }
88
89    /// Given a [`ty::ClosureKind`], get the [`DefId`] of its corresponding `Fn`-family
90    /// trait, if it is defined.
91    pub fn async_fn_trait_kind_to_def_id(self, kind: ty::ClosureKind) -> Option<DefId> {
92        let items = self.lang_items();
93        match kind {
94            ty::ClosureKind::Fn => items.async_fn_trait(),
95            ty::ClosureKind::FnMut => items.async_fn_mut_trait(),
96            ty::ClosureKind::FnOnce => items.async_fn_once_trait(),
97        }
98    }
99
100    /// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits.
101    pub fn is_fn_trait(self, id: DefId) -> bool {
102        self.fn_trait_kind_from_def_id(id).is_some()
103    }
104}
105
106/// Returns `true` if the specified `lang_item` must be present for this
107/// compilation.
108///
109/// Not all lang items are always required for each compilation, particularly in
110/// the case of panic=abort. In these situations some lang items are injected by
111/// crates and don't actually need to be defined in libstd.
112pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
113    // If we're not compiling with unwinding, we won't actually need this
114    // symbol. Other panic runtimes ensure that the relevant symbols are
115    // available to link things together, but they're never exercised.
116    match tcx.sess.panic_strategy() {
117        PanicStrategy::Abort => lang_item != LangItem::EhPersonality,
118        PanicStrategy::Unwind => true,
119        PanicStrategy::ImmediateAbort => false,
120    }
121}