]>
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 | 14 | use session::Session; |
1a4d82fc JJ |
15 | use middle::lang_items; |
16 | ||
c30ab7b3 | 17 | use rustc_back::PanicStrategy; |
b039eaaf | 18 | use syntax::ast; |
1a4d82fc | 19 | use syntax::parse::token::InternedString; |
3157f602 | 20 | use syntax_pos::Span; |
54a0048b SL |
21 | use hir::intravisit::Visitor; |
22 | use hir::intravisit; | |
23 | use hir; | |
1a4d82fc JJ |
24 | |
25 | use std::collections::HashSet; | |
26 | ||
27 | macro_rules! weak_lang_items { | |
28 | ($($name:ident, $item:ident, $sym:ident;)*) => ( | |
29 | ||
30 | struct Context<'a> { | |
31 | sess: &'a Session, | |
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. | |
e9174d1e | 37 | pub fn check_crate(krate: &hir::Crate, |
1a4d82fc JJ |
38 | sess: &Session, |
39 | items: &mut lang_items::LanguageItems) { | |
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 | } | |
c1a9b12d SL |
46 | if sess.target.target.options.custom_unwind_resume & |
47 | items.eh_unwind_resume().is_none() { | |
48 | items.missing.push(lang_items::EhUnwindResumeLangItem); | |
49 | } | |
1a4d82fc JJ |
50 | |
51 | { | |
52 | let mut cx = Context { sess: sess, items: items }; | |
92a42be0 | 53 | krate.visit_all_items(&mut cx); |
1a4d82fc JJ |
54 | } |
55 | verify(sess, items); | |
56 | } | |
57 | ||
b039eaaf | 58 | pub fn link_name(attrs: &[ast::Attribute]) -> Option<InternedString> { |
1a4d82fc | 59 | lang_items::extract(attrs).and_then(|name| { |
85aaf69f | 60 | $(if &name[..] == stringify!($name) { |
1a4d82fc JJ |
61 | Some(InternedString::new(stringify!($sym))) |
62 | } else)* { | |
63 | None | |
64 | } | |
65 | }) | |
66 | } | |
67 | ||
68 | fn verify(sess: &Session, items: &lang_items::LanguageItems) { | |
69 | // We only need to check for the presence of weak lang items if we're | |
70 | // emitting something that's not an rlib. | |
71 | let needs_check = sess.crate_types.borrow().iter().any(|kind| { | |
72 | match *kind { | |
73 | config::CrateTypeDylib | | |
c30ab7b3 | 74 | config::CrateTypeProcMacro | |
a7813a04 | 75 | config::CrateTypeCdylib | |
1a4d82fc JJ |
76 | config::CrateTypeExecutable | |
77 | config::CrateTypeStaticlib => true, | |
78 | config::CrateTypeRlib => false, | |
79 | } | |
80 | }); | |
a7813a04 XL |
81 | if !needs_check { |
82 | return | |
83 | } | |
1a4d82fc JJ |
84 | |
85 | let mut missing = HashSet::new(); | |
92a42be0 SL |
86 | for cnum in sess.cstore.crates() { |
87 | for item in sess.cstore.missing_lang_items(cnum) { | |
88 | missing.insert(item); | |
1a4d82fc | 89 | } |
92a42be0 | 90 | } |
1a4d82fc | 91 | |
a7813a04 XL |
92 | // If we're not compiling with unwinding, we won't actually need these |
93 | // symbols. Other panic runtimes ensure that the relevant symbols are | |
94 | // available to link things together, but they're never exercised. | |
95 | let mut whitelisted = HashSet::new(); | |
c30ab7b3 | 96 | if sess.panic_strategy() != PanicStrategy::Unwind { |
a7813a04 XL |
97 | whitelisted.insert(lang_items::EhPersonalityLangItem); |
98 | whitelisted.insert(lang_items::EhUnwindResumeLangItem); | |
99 | } | |
100 | ||
1a4d82fc | 101 | $( |
a7813a04 XL |
102 | if missing.contains(&lang_items::$item) && |
103 | !whitelisted.contains(&lang_items::$item) && | |
104 | items.$name().is_none() { | |
85aaf69f SL |
105 | sess.err(&format!("language item required, but not found: `{}`", |
106 | stringify!($name))); | |
1a4d82fc JJ |
107 | |
108 | } | |
109 | )* | |
110 | } | |
111 | ||
112 | impl<'a> Context<'a> { | |
113 | fn register(&mut self, name: &str, span: Span) { | |
114 | $(if name == stringify!($name) { | |
115 | if self.items.$name().is_none() { | |
116 | self.items.missing.push(lang_items::$item); | |
117 | } | |
118 | } else)* { | |
85aaf69f | 119 | span_err!(self.sess, span, E0264, |
92a42be0 SL |
120 | "unknown external lang item: `{}`", |
121 | name); | |
1a4d82fc JJ |
122 | } |
123 | } | |
124 | } | |
125 | ||
126 | impl<'a, 'v> Visitor<'v> for Context<'a> { | |
e9174d1e | 127 | fn visit_foreign_item(&mut self, i: &hir::ForeignItem) { |
3157f602 XL |
128 | if let Some(lang_item) = lang_items::extract(&i.attrs) { |
129 | self.register(&lang_item, i.span); | |
1a4d82fc | 130 | } |
92a42be0 | 131 | intravisit::walk_foreign_item(self, i) |
1a4d82fc JJ |
132 | } |
133 | } | |
134 | ||
135 | ) } | |
136 | ||
137 | weak_lang_items! { | |
c1a9b12d | 138 | panic_fmt, PanicFmtLangItem, rust_begin_unwind; |
1a4d82fc | 139 | eh_personality, EhPersonalityLangItem, rust_eh_personality; |
c1a9b12d | 140 | eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; |
1a4d82fc | 141 | } |