]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Validity checking for weak lang items | |
12 | ||
c30ab7b3 | 13 | use session::config; |
1a4d82fc JJ |
14 | use middle::lang_items; |
15 | ||
83c7162d | 16 | use rustc_target::spec::PanicStrategy; |
b039eaaf | 17 | use syntax::ast; |
476ff2be | 18 | use syntax::symbol::Symbol; |
3157f602 | 19 | use syntax_pos::Span; |
8faf50e0 | 20 | use hir::def_id::DefId; |
476ff2be | 21 | use hir::intravisit::{Visitor, NestedVisitorMap}; |
54a0048b SL |
22 | use hir::intravisit; |
23 | use hir; | |
ea8adc8c | 24 | use ty::TyCtxt; |
1a4d82fc JJ |
25 | |
26 | use std::collections::HashSet; | |
27 | ||
28 | macro_rules! weak_lang_items { | |
29 | ($($name:ident, $item:ident, $sym:ident;)*) => ( | |
30 | ||
ea8adc8c XL |
31 | struct Context<'a, 'tcx: 'a> { |
32 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
1a4d82fc JJ |
33 | items: &'a mut lang_items::LanguageItems, |
34 | } | |
35 | ||
36 | /// Checks the crate for usage of weak lang items, returning a vector of all the | |
37 | /// language items required by this crate, but not defined yet. | |
ea8adc8c XL |
38 | pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
39 | items: &mut lang_items::LanguageItems) { | |
1a4d82fc JJ |
40 | // These are never called by user code, they're generated by the compiler. |
41 | // They will never implicitly be added to the `missing` array unless we do | |
42 | // so here. | |
1a4d82fc JJ |
43 | if items.eh_personality().is_none() { |
44 | items.missing.push(lang_items::EhPersonalityLangItem); | |
45 | } | |
ea8adc8c | 46 | if tcx.sess.target.target.options.custom_unwind_resume & |
c1a9b12d SL |
47 | items.eh_unwind_resume().is_none() { |
48 | items.missing.push(lang_items::EhUnwindResumeLangItem); | |
49 | } | |
1a4d82fc JJ |
50 | |
51 | { | |
ea8adc8c XL |
52 | let mut cx = Context { tcx, items }; |
53 | tcx.hir.krate().visit_all_item_likes(&mut cx.as_deep_visitor()); | |
1a4d82fc | 54 | } |
ea8adc8c | 55 | verify(tcx, items); |
1a4d82fc JJ |
56 | } |
57 | ||
476ff2be | 58 | pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> { |
2c00a5a8 | 59 | lang_items::extract(attrs).and_then(|(name, _)| { |
476ff2be SL |
60 | $(if name == stringify!($name) { |
61 | Some(Symbol::intern(stringify!($sym))) | |
1a4d82fc JJ |
62 | } else)* { |
63 | None | |
64 | } | |
65 | }) | |
66 | } | |
67 | ||
83c7162d XL |
68 | /// Returns whether the specified `lang_item` doesn't actually need to be |
69 | /// present for this compilation. | |
70 | /// | |
71 | /// Not all lang items are always required for each compilation, particularly in | |
72 | /// the case of panic=abort. In these situations some lang items are injected by | |
73 | /// crates and don't actually need to be defined in libstd. | |
74 | pub fn whitelisted(tcx: TyCtxt, lang_item: lang_items::LangItem) -> bool { | |
75 | // If we're not compiling with unwinding, we won't actually need these | |
76 | // symbols. Other panic runtimes ensure that the relevant symbols are | |
77 | // available to link things together, but they're never exercised. | |
78 | if tcx.sess.panic_strategy() != PanicStrategy::Unwind { | |
79 | return lang_item == lang_items::EhPersonalityLangItem || | |
80 | lang_item == lang_items::EhUnwindResumeLangItem | |
81 | } | |
82 | ||
83 | false | |
84 | } | |
85 | ||
ea8adc8c XL |
86 | fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
87 | items: &lang_items::LanguageItems) { | |
1a4d82fc JJ |
88 | // We only need to check for the presence of weak lang items if we're |
89 | // emitting something that's not an rlib. | |
ea8adc8c | 90 | let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| { |
1a4d82fc JJ |
91 | match *kind { |
92 | config::CrateTypeDylib | | |
c30ab7b3 | 93 | config::CrateTypeProcMacro | |
a7813a04 | 94 | config::CrateTypeCdylib | |
1a4d82fc JJ |
95 | config::CrateTypeExecutable | |
96 | config::CrateTypeStaticlib => true, | |
32a655c1 | 97 | config::CrateTypeRlib => false, |
1a4d82fc JJ |
98 | } |
99 | }); | |
a7813a04 XL |
100 | if !needs_check { |
101 | return | |
102 | } | |
1a4d82fc JJ |
103 | |
104 | let mut missing = HashSet::new(); | |
ea8adc8c XL |
105 | for &cnum in tcx.crates().iter() { |
106 | for &item in tcx.missing_lang_items(cnum).iter() { | |
92a42be0 | 107 | missing.insert(item); |
1a4d82fc | 108 | } |
92a42be0 | 109 | } |
1a4d82fc JJ |
110 | |
111 | $( | |
a7813a04 | 112 | if missing.contains(&lang_items::$item) && |
83c7162d | 113 | !whitelisted(tcx, lang_items::$item) && |
a7813a04 | 114 | items.$name().is_none() { |
8faf50e0 XL |
115 | if lang_items::$item == lang_items::PanicImplLangItem { |
116 | tcx.sess.err(&format!("`#[panic_implementation]` function required, \ | |
117 | but not found")); | |
118 | } else if lang_items::$item == lang_items::OomLangItem { | |
119 | tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \ | |
120 | but not found")); | |
121 | } else { | |
122 | tcx.sess.err(&format!("language item required, but not found: `{}`", | |
123 | stringify!($name))); | |
124 | } | |
1a4d82fc JJ |
125 | } |
126 | )* | |
127 | } | |
128 | ||
ea8adc8c | 129 | impl<'a, 'tcx> Context<'a, 'tcx> { |
1a4d82fc JJ |
130 | fn register(&mut self, name: &str, span: Span) { |
131 | $(if name == stringify!($name) { | |
132 | if self.items.$name().is_none() { | |
133 | self.items.missing.push(lang_items::$item); | |
134 | } | |
135 | } else)* { | |
ea8adc8c | 136 | span_err!(self.tcx.sess, span, E0264, |
92a42be0 SL |
137 | "unknown external lang item: `{}`", |
138 | name); | |
1a4d82fc JJ |
139 | } |
140 | } | |
141 | } | |
142 | ||
ea8adc8c | 143 | impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { |
476ff2be SL |
144 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { |
145 | NestedVisitorMap::None | |
146 | } | |
147 | ||
e9174d1e | 148 | fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { |
2c00a5a8 | 149 | if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { |
476ff2be | 150 | self.register(&lang_item.as_str(), i.span); |
1a4d82fc | 151 | } |
92a42be0 | 152 | intravisit::walk_foreign_item(self, i) |
1a4d82fc JJ |
153 | } |
154 | } | |
155 | ||
8faf50e0 XL |
156 | impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> { |
157 | pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { | |
158 | let lang_items = self.lang_items(); | |
159 | let did = Some(item_def_id); | |
160 | ||
161 | $(lang_items.$name() == did)||+ | |
162 | } | |
163 | } | |
164 | ||
1a4d82fc JJ |
165 | ) } |
166 | ||
167 | weak_lang_items! { | |
94b46f34 | 168 | panic_impl, PanicImplLangItem, rust_begin_unwind; |
1a4d82fc | 169 | eh_personality, EhPersonalityLangItem, rust_eh_personality; |
c1a9b12d | 170 | eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; |
83c7162d | 171 | oom, OomLangItem, rust_oom; |
1a4d82fc | 172 | } |