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.
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.
11 //! Validity checking for weak lang items
14 use middle
::lang_items
;
16 use rustc_data_structures
::fx
::FxHashSet
;
17 use rustc_target
::spec
::PanicStrategy
;
19 use syntax
::symbol
::Symbol
;
21 use hir
::def_id
::DefId
;
22 use hir
::intravisit
::{Visitor, NestedVisitorMap}
;
27 macro_rules
! weak_lang_items
{
28 ($
($name
:ident
, $item
:ident
, $sym
:ident
;)*) => (
30 struct Context
<'a
, 'tcx
: 'a
> {
31 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
32 items
: &'a
mut lang_items
::LanguageItems
,
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.
37 pub fn check_crate
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
38 items
: &mut lang_items
::LanguageItems
) {
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
42 if items
.eh_personality().is_none() {
43 items
.missing
.push(lang_items
::EhPersonalityLangItem
);
45 if tcx
.sess
.target
.target
.options
.custom_unwind_resume
&
46 items
.eh_unwind_resume().is_none() {
47 items
.missing
.push(lang_items
::EhUnwindResumeLangItem
);
51 let mut cx
= Context { tcx, items }
;
52 tcx
.hir
.krate().visit_all_item_likes(&mut cx
.as_deep_visitor());
57 pub fn link_name(attrs
: &[ast
::Attribute
]) -> Option
<Symbol
> {
58 lang_items
::extract(attrs
).and_then(|(name
, _
)| {
59 $
(if name
== stringify
!($name
) {
60 Some(Symbol
::intern(stringify
!($sym
)))
67 /// Returns whether the specified `lang_item` doesn't actually need to be
68 /// present for this compilation.
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
85 fn verify
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
86 items
: &lang_items
::LanguageItems
) {
87 // We only need to check for the presence of weak lang items if we're
88 // emitting something that's not an rlib.
89 let needs_check
= tcx
.sess
.crate_types
.borrow().iter().any(|kind
| {
91 config
::CrateType
::Dylib
|
92 config
::CrateType
::ProcMacro
|
93 config
::CrateType
::Cdylib
|
94 config
::CrateType
::Executable
|
95 config
::CrateType
::Staticlib
=> true,
96 config
::CrateType
::Rlib
=> false,
103 let mut missing
= FxHashSet
::default();
104 for &cnum
in tcx
.crates().iter() {
105 for &item
in tcx
.missing_lang_items(cnum
).iter() {
106 missing
.insert(item
);
111 if missing
.contains(&lang_items
::$item
) &&
112 !whitelisted(tcx
, lang_items
::$item
) &&
113 items
.$
name().is_none() {
114 if lang_items
::$item
== lang_items
::PanicImplLangItem
{
115 tcx
.sess
.err(&format
!("`#[panic_handler]` function required, \
117 } else if lang_items
::$item
== lang_items
::OomLangItem
{
118 tcx
.sess
.err(&format
!("`#[alloc_error_handler]` function required, \
121 tcx
.sess
.err(&format
!("language item required, but not found: `{}`",
128 impl<'a
, 'tcx
> Context
<'a
, 'tcx
> {
129 fn register(&mut self, name
: &str, span
: Span
) {
130 $
(if name
== stringify
!($name
) {
131 if self.items
.$
name().is_none() {
132 self.items
.missing
.push(lang_items
::$item
);
135 span_err
!(self.tcx
.sess
, span
, E0264
,
136 "unknown external lang item: `{}`",
142 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for Context
<'a
, 'tcx
> {
143 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
144 NestedVisitorMap
::None
147 fn visit_foreign_item(&mut self, i
: &hir
::ForeignItem
) {
148 if let Some((lang_item
, _
)) = lang_items
::extract(&i
.attrs
) {
149 self.register(&lang_item
.as_str(), i
.span
);
151 intravisit
::walk_foreign_item(self, i
)
155 impl<'a
, 'tcx
, 'gcx
> TyCtxt
<'a
, 'tcx
, 'gcx
> {
156 pub fn is_weak_lang_item(&self, item_def_id
: DefId
) -> bool
{
157 let lang_items
= self.lang_items();
158 let did
= Some(item_def_id
);
160 $
(lang_items
.$
name() == did
)||+
167 panic_impl
, PanicImplLangItem
, rust_begin_unwind
;
168 eh_personality
, EhPersonalityLangItem
, rust_eh_personality
;
169 eh_unwind_resume
, EhUnwindResumeLangItem
, rust_eh_unwind_resume
;
170 oom
, OomLangItem
, rust_oom
;