1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use session::config;
use session::Session;
use middle::lang_items;
use rustc_back::PanicStrategy;
use syntax::ast;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use hir::intravisit::{Visitor, NestedVisitorMap};
use hir::intravisit;
use hir;
use std::collections::HashSet;
macro_rules! weak_lang_items {
($($name:ident, $item:ident, $sym:ident;)*) => (
struct Context<'a> {
sess: &'a Session,
items: &'a mut lang_items::LanguageItems,
}
pub fn check_crate(krate: &hir::Crate,
sess: &Session,
items: &mut lang_items::LanguageItems) {
if items.eh_personality().is_none() {
items.missing.push(lang_items::EhPersonalityLangItem);
}
if sess.target.target.options.custom_unwind_resume &
items.eh_unwind_resume().is_none() {
items.missing.push(lang_items::EhUnwindResumeLangItem);
}
{
let mut cx = Context { sess: sess, items: items };
krate.visit_all_item_likes(&mut cx.as_deep_visitor());
}
verify(sess, items);
}
pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
lang_items::extract(attrs).and_then(|name| {
$(if name == stringify!($name) {
Some(Symbol::intern(stringify!($sym)))
} else)* {
None
}
})
}
fn verify(sess: &Session, items: &lang_items::LanguageItems) {
let needs_check = sess.crate_types.borrow().iter().any(|kind| {
match *kind {
config::CrateTypeDylib |
config::CrateTypeProcMacro |
config::CrateTypeCdylib |
config::CrateTypeExecutable |
config::CrateTypeStaticlib => true,
config::CrateTypeRlib => false,
}
});
if !needs_check {
return
}
let mut missing = HashSet::new();
for cnum in sess.cstore.crates() {
for item in sess.cstore.missing_lang_items(cnum) {
missing.insert(item);
}
}
let mut whitelisted = HashSet::new();
if sess.panic_strategy() != PanicStrategy::Unwind {
whitelisted.insert(lang_items::EhPersonalityLangItem);
whitelisted.insert(lang_items::EhUnwindResumeLangItem);
}
$(
if missing.contains(&lang_items::$item) &&
!whitelisted.contains(&lang_items::$item) &&
items.$name().is_none() {
sess.err(&format!("language item required, but not found: `{}`",
stringify!($name)));
}
)*
}
impl<'a> Context<'a> {
fn register(&mut self, name: &str, span: Span) {
$(if name == stringify!($name) {
if self.items.$name().is_none() {
self.items.missing.push(lang_items::$item);
}
} else)* {
span_err!(self.sess, span, E0264,
"unknown external lang item: `{}`",
name);
}
}
}
impl<'a, 'v> Visitor<'v> for Context<'a> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::None
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
if let Some(lang_item) = lang_items::extract(&i.attrs) {
self.register(&lang_item.as_str(), i.span);
}
intravisit::walk_foreign_item(self, i)
}
}
) }
weak_lang_items! {
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
}