1 //! Validity checking for weak lang items
3 use rustc_data_structures
::fx
::FxHashSet
;
4 use rustc_errors
::struct_span_err
;
6 use rustc_hir
::intravisit
::{self, NestedVisitorMap, Visitor}
;
7 use rustc_hir
::lang_items
::{self, LangItem}
;
8 use rustc_hir
::weak_lang_items
::WEAK_ITEMS_REFS
;
9 use rustc_middle
::middle
::lang_items
::required
;
10 use rustc_middle
::ty
::TyCtxt
;
11 use rustc_session
::config
::CrateType
;
12 use rustc_span
::symbol
::Symbol
;
15 struct Context
<'a
, 'tcx
> {
17 items
: &'a
mut lang_items
::LanguageItems
,
20 /// Checks the crate for usage of weak lang items, returning a vector of all the
21 /// language items required by this crate, but not defined yet.
22 pub fn check_crate
<'tcx
>(tcx
: TyCtxt
<'tcx
>, items
: &mut lang_items
::LanguageItems
) {
23 // These are never called by user code, they're generated by the compiler.
24 // They will never implicitly be added to the `missing` array unless we do
26 if items
.eh_personality().is_none() {
27 items
.missing
.push(LangItem
::EhPersonality
);
29 if tcx
.sess
.target
.is_like_emscripten
&& items
.eh_catch_typeinfo().is_none() {
30 items
.missing
.push(LangItem
::EhCatchTypeinfo
);
34 let mut cx
= Context { tcx, items }
;
35 tcx
.hir().krate().visit_all_item_likes(&mut cx
.as_deep_visitor());
40 fn verify
<'tcx
>(tcx
: TyCtxt
<'tcx
>, items
: &lang_items
::LanguageItems
) {
41 // We only need to check for the presence of weak lang items if we're
42 // emitting something that's not an rlib.
43 let needs_check
= tcx
.sess
.crate_types().iter().any(|kind
| match *kind
{
45 | CrateType
::ProcMacro
47 | CrateType
::Executable
48 | CrateType
::Staticlib
=> true,
49 CrateType
::Rlib
=> false,
55 let mut missing
= FxHashSet
::default();
56 for &cnum
in tcx
.crates(()).iter() {
57 for &item
in tcx
.missing_lang_items(cnum
).iter() {
62 for (name
, item
) in WEAK_ITEMS_REFS
.clone().into_sorted_vector().into_iter() {
63 if missing
.contains(&item
) && required(tcx
, item
) && items
.require(item
).is_err() {
64 if item
== LangItem
::PanicImpl
{
65 tcx
.sess
.err("`#[panic_handler]` function required, but not found");
66 } else if item
== LangItem
::Oom
{
67 if !tcx
.features().default_alloc_error_handler
{
68 tcx
.sess
.err("`#[alloc_error_handler]` function required, but not found.");
69 tcx
.sess
.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler.");
72 tcx
.sess
.err(&format
!("language item required, but not found: `{}`", name
));
78 impl<'a
, 'tcx
> Context
<'a
, 'tcx
> {
79 fn register(&mut self, name
: Symbol
, span
: Span
) {
80 if let Some(&item
) = WEAK_ITEMS_REFS
.get(&name
) {
81 if self.items
.require(item
).is_err() {
82 self.items
.missing
.push(item
);
85 struct_span_err
!(self.tcx
.sess
, span
, E0264
, "unknown external lang item: `{}`", name
)
91 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for Context
<'a
, 'tcx
> {
92 type Map
= intravisit
::ErasedMap
<'v
>;
94 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
95 NestedVisitorMap
::None
98 fn visit_foreign_item(&mut self, i
: &hir
::ForeignItem
<'_
>) {
99 let check_name
= |attr
, sym
| self.tcx
.sess
.check_name(attr
, sym
);
100 let attrs
= self.tcx
.hir().attrs(i
.hir_id());
101 if let Some((lang_item
, _
)) = lang_items
::extract(check_name
, attrs
) {
102 self.register(lang_item
, i
.span
);
104 intravisit
::walk_foreign_item(self, i
)