]>
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; |
476ff2be | 20 | use hir::intravisit::{Visitor, NestedVisitorMap}; |
54a0048b SL |
21 | use hir::intravisit; |
22 | use hir; | |
ea8adc8c | 23 | use ty::TyCtxt; |
1a4d82fc JJ |
24 | |
25 | use std::collections::HashSet; | |
26 | ||
27 | macro_rules! weak_lang_items { | |
28 | ($($name:ident, $item:ident, $sym:ident;)*) => ( | |
29 | ||
ea8adc8c XL |
30 | struct Context<'a, 'tcx: 'a> { |
31 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
1a4d82fc JJ |
32 | items: &'a mut lang_items::LanguageItems, |
33 | } | |
34 | ||
35 | /// Checks the crate for usage of weak lang items, returning a vector of all the | |
36 | /// language items required by this crate, but not defined yet. | |
ea8adc8c XL |
37 | pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
38 | items: &mut lang_items::LanguageItems) { | |
1a4d82fc JJ |
39 | // These are never called by user code, they're generated by the compiler. |
40 | // They will never implicitly be added to the `missing` array unless we do | |
41 | // so here. | |
1a4d82fc JJ |
42 | if items.eh_personality().is_none() { |
43 | items.missing.push(lang_items::EhPersonalityLangItem); | |
44 | } | |
ea8adc8c | 45 | if tcx.sess.target.target.options.custom_unwind_resume & |
c1a9b12d SL |
46 | items.eh_unwind_resume().is_none() { |
47 | items.missing.push(lang_items::EhUnwindResumeLangItem); | |
48 | } | |
1a4d82fc JJ |
49 | |
50 | { | |
ea8adc8c XL |
51 | let mut cx = Context { tcx, items }; |
52 | tcx.hir.krate().visit_all_item_likes(&mut cx.as_deep_visitor()); | |
1a4d82fc | 53 | } |
ea8adc8c | 54 | verify(tcx, items); |
1a4d82fc JJ |
55 | } |
56 | ||
476ff2be | 57 | pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> { |
2c00a5a8 | 58 | lang_items::extract(attrs).and_then(|(name, _)| { |
476ff2be SL |
59 | $(if name == stringify!($name) { |
60 | Some(Symbol::intern(stringify!($sym))) | |
1a4d82fc JJ |
61 | } else)* { |
62 | None | |
63 | } | |
64 | }) | |
65 | } | |
66 | ||
83c7162d XL |
67 | /// Returns whether the specified `lang_item` doesn't actually need to be |
68 | /// present for this compilation. | |
69 | /// | |
70 | /// Not all lang items are always required for each compilation, particularly in | |
71 | /// the case of panic=abort. In these situations some lang items are injected by | |
72 | /// crates and don't actually need to be defined in libstd. | |
73 | pub fn whitelisted(tcx: TyCtxt, lang_item: lang_items::LangItem) -> bool { | |
74 | // If we're not compiling with unwinding, we won't actually need these | |
75 | // symbols. Other panic runtimes ensure that the relevant symbols are | |
76 | // available to link things together, but they're never exercised. | |
77 | if tcx.sess.panic_strategy() != PanicStrategy::Unwind { | |
78 | return lang_item == lang_items::EhPersonalityLangItem || | |
79 | lang_item == lang_items::EhUnwindResumeLangItem | |
80 | } | |
81 | ||
82 | false | |
83 | } | |
84 | ||
ea8adc8c XL |
85 | fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
86 | items: &lang_items::LanguageItems) { | |
1a4d82fc JJ |
87 | // We only need to check for the presence of weak lang items if we're |
88 | // emitting something that's not an rlib. | |
ea8adc8c | 89 | let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| { |
1a4d82fc JJ |
90 | match *kind { |
91 | config::CrateTypeDylib | | |
c30ab7b3 | 92 | config::CrateTypeProcMacro | |
a7813a04 | 93 | config::CrateTypeCdylib | |
1a4d82fc JJ |
94 | config::CrateTypeExecutable | |
95 | config::CrateTypeStaticlib => true, | |
32a655c1 | 96 | config::CrateTypeRlib => false, |
1a4d82fc JJ |
97 | } |
98 | }); | |
a7813a04 XL |
99 | if !needs_check { |
100 | return | |
101 | } | |
1a4d82fc JJ |
102 | |
103 | let mut missing = HashSet::new(); | |
ea8adc8c XL |
104 | for &cnum in tcx.crates().iter() { |
105 | for &item in tcx.missing_lang_items(cnum).iter() { | |
92a42be0 | 106 | missing.insert(item); |
1a4d82fc | 107 | } |
92a42be0 | 108 | } |
1a4d82fc JJ |
109 | |
110 | $( | |
a7813a04 | 111 | if missing.contains(&lang_items::$item) && |
83c7162d | 112 | !whitelisted(tcx, lang_items::$item) && |
a7813a04 | 113 | items.$name().is_none() { |
ea8adc8c XL |
114 | tcx.sess.err(&format!("language item required, but not found: `{}`", |
115 | stringify!($name))); | |
1a4d82fc JJ |
116 | |
117 | } | |
118 | )* | |
119 | } | |
120 | ||
ea8adc8c | 121 | impl<'a, 'tcx> Context<'a, 'tcx> { |
1a4d82fc JJ |
122 | fn register(&mut self, name: &str, span: Span) { |
123 | $(if name == stringify!($name) { | |
124 | if self.items.$name().is_none() { | |
125 | self.items.missing.push(lang_items::$item); | |
126 | } | |
127 | } else)* { | |
ea8adc8c | 128 | span_err!(self.tcx.sess, span, E0264, |
92a42be0 SL |
129 | "unknown external lang item: `{}`", |
130 | name); | |
1a4d82fc JJ |
131 | } |
132 | } | |
133 | } | |
134 | ||
ea8adc8c | 135 | impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { |
476ff2be SL |
136 | fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { |
137 | NestedVisitorMap::None | |
138 | } | |
139 | ||
e9174d1e | 140 | fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { |
2c00a5a8 | 141 | if let Some((lang_item, _)) = lang_items::extract(&i.attrs) { |
476ff2be | 142 | self.register(&lang_item.as_str(), i.span); |
1a4d82fc | 143 | } |
92a42be0 | 144 | intravisit::walk_foreign_item(self, i) |
1a4d82fc JJ |
145 | } |
146 | } | |
147 | ||
148 | ) } | |
149 | ||
150 | weak_lang_items! { | |
94b46f34 | 151 | panic_impl, PanicImplLangItem, rust_begin_unwind; |
1a4d82fc | 152 | eh_personality, EhPersonalityLangItem, rust_eh_personality; |
c1a9b12d | 153 | eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; |
83c7162d | 154 | oom, OomLangItem, rust_oom; |
1a4d82fc | 155 | } |