]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | //! Validity checking for weak lang items |
2 | ||
74b04a01 XL |
3 | use rustc_data_structures::fx::FxHashSet; |
4 | use rustc_errors::struct_span_err; | |
5 | use rustc_hir as hir; | |
6 | use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; | |
3dfed10e | 7 | use rustc_hir::lang_items::{self, LangItem}; |
74b04a01 | 8 | use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; |
f035d41b | 9 | use rustc_middle::middle::lang_items::required; |
ba9703b0 | 10 | use rustc_middle::ty::TyCtxt; |
f9f354fc | 11 | use rustc_session::config::CrateType; |
74b04a01 XL |
12 | use rustc_span::symbol::Symbol; |
13 | use rustc_span::Span; | |
14 | ||
15 | struct Context<'a, 'tcx> { | |
16 | tcx: TyCtxt<'tcx>, | |
17 | items: &'a mut lang_items::LanguageItems, | |
18 | } | |
19 | ||
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 | |
25 | // so here. | |
26 | if items.eh_personality().is_none() { | |
3dfed10e | 27 | items.missing.push(LangItem::EhPersonality); |
74b04a01 | 28 | } |
74b04a01 XL |
29 | |
30 | { | |
31 | let mut cx = Context { tcx, items }; | |
32 | tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor()); | |
33 | } | |
34 | verify(tcx, items); | |
35 | } | |
36 | ||
37 | fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { | |
38 | // We only need to check for the presence of weak lang items if we're | |
39 | // emitting something that's not an rlib. | |
f9f354fc XL |
40 | let needs_check = tcx.sess.crate_types().iter().any(|kind| match *kind { |
41 | CrateType::Dylib | |
42 | | CrateType::ProcMacro | |
43 | | CrateType::Cdylib | |
44 | | CrateType::Executable | |
45 | | CrateType::Staticlib => true, | |
46 | CrateType::Rlib => false, | |
74b04a01 XL |
47 | }); |
48 | if !needs_check { | |
49 | return; | |
50 | } | |
51 | ||
52 | let mut missing = FxHashSet::default(); | |
53 | for &cnum in tcx.crates().iter() { | |
54 | for &item in tcx.missing_lang_items(cnum).iter() { | |
55 | missing.insert(item); | |
56 | } | |
57 | } | |
58 | ||
59 | for (name, &item) in WEAK_ITEMS_REFS.iter() { | |
f035d41b | 60 | if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { |
3dfed10e | 61 | if item == LangItem::PanicImpl { |
74b04a01 | 62 | tcx.sess.err("`#[panic_handler]` function required, but not found"); |
3dfed10e | 63 | } else if item == LangItem::Oom { |
74b04a01 XL |
64 | tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); |
65 | } else { | |
66 | tcx.sess.err(&format!("language item required, but not found: `{}`", name)); | |
67 | } | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
72 | impl<'a, 'tcx> Context<'a, 'tcx> { | |
3dfed10e | 73 | fn register(&mut self, name: Symbol, span: Span) { |
74b04a01 XL |
74 | if let Some(&item) = WEAK_ITEMS_REFS.get(&name) { |
75 | if self.items.require(item).is_err() { | |
76 | self.items.missing.push(item); | |
77 | } | |
78 | } else { | |
79 | struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name) | |
80 | .emit(); | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 | impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { | |
ba9703b0 | 86 | type Map = intravisit::ErasedMap<'v>; |
74b04a01 | 87 | |
ba9703b0 | 88 | fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
74b04a01 XL |
89 | NestedVisitorMap::None |
90 | } | |
91 | ||
92 | fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) { | |
3dfed10e XL |
93 | let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym); |
94 | if let Some((lang_item, _)) = lang_items::extract(check_name, &i.attrs) { | |
95 | self.register(lang_item, i.span); | |
74b04a01 XL |
96 | } |
97 | intravisit::walk_foreign_item(self, i) | |
98 | } | |
99 | } |