Skip to content

Commit feb9f30

Browse files
committed
auto merge of #14293 : alexcrichton/rust/weak-lang-items, r=brson
This commit is part of the ongoing libstd facade efforts (cc #13851). The compiler now recognizes some language items as "extern { fn foo(...); }" and will automatically perform the following actions: 1. The foreign function has a pre-defined name. 2. The crate and downstream crates can only be built as rlibs until a crate defines the lang item itself. 3. The actual lang item has a pre-defined name. This is essentially nicer compiler support for the hokey core-depends-on-std-failure scheme today, but it is implemented the same way. The details are a little more hidden under the covers. In addition to failure, this commit promotes the eh_personality and rust_stack_exhausted functions to official lang items. The compiler can generate calls to these functions, causing linkage errors if they are left undefined. The checking for these items is not as precise as it could be. Crates compiling with `-Z no-landing-pads` will not need the eh_personality lang item, and crates compiling with no split stacks won't need the stack exhausted lang item. For ease, however, these items are checked for presence in all final outputs of the compiler. It is quite easy to define dummy versions of the functions necessary: #[lang = "stack_exhausted"] extern fn stack_exhausted() { /* ... */ } #[lang = "eh_personality"] extern fn eh_personality() { /* ... */ } cc #11922, rust_stack_exhausted is now a lang item cc #13851, libcollections is blocked on eh_personality becoming weak
2 parents f30382d + 6efd166 commit feb9f30

20 files changed

+403
-32
lines changed

src/libcore/failure.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,19 @@ fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
6060

6161
#[cold]
6262
pub fn begin_unwind(fmt: &fmt::Arguments, file: &'static str, line: uint) -> ! {
63-
// FIXME: this should be a proper lang item, it should not just be some
64-
// undefined symbol sitting in the middle of nowhere.
6563
#[allow(ctypes)]
66-
extern { fn rust_begin_unwind(fmt: &fmt::Arguments, file: &'static str,
67-
line: uint) -> !; }
68-
unsafe { rust_begin_unwind(fmt, file, line) }
64+
#[cfg(stage0)]
65+
extern {
66+
#[link_name = "rust_begin_unwind"]
67+
fn begin_unwind(fmt: &fmt::Arguments, file: &'static str,
68+
line: uint) -> !;
69+
}
70+
#[allow(ctypes)]
71+
#[cfg(not(stage0))]
72+
extern {
73+
#[lang = "begin_unwind"]
74+
fn begin_unwind(fmt: &fmt::Arguments, file: &'static str,
75+
line: uint) -> !;
76+
}
77+
unsafe { begin_unwind(fmt, file, line) }
6978
}

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub mod middle {
7878
pub mod dead;
7979
pub mod expr_use_visitor;
8080
pub mod dependency_format;
81+
pub mod weak_lang_items;
8182
}
8283

8384
pub mod front {

src/librustc/metadata/common.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ pub static tag_lang_items: uint = 0x70;
167167
pub static tag_lang_items_item: uint = 0x71;
168168
pub static tag_lang_items_item_id: uint = 0x72;
169169
pub static tag_lang_items_item_node_id: uint = 0x73;
170+
pub static tag_lang_items_missing: uint = 0x74;
170171

171-
pub static tag_item_unnamed_field: uint = 0x74;
172+
pub static tag_item_unnamed_field: uint = 0x75;
172173
pub static tag_items_data_item_visibility: uint = 0x76;
173174
pub static tag_items_data_item_sized: uint = 0x77;
174175

src/librustc/metadata/csearch.rs

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use metadata::common::*;
1616
use metadata::cstore;
1717
use metadata::decoder;
18+
use middle::lang_items;
1819
use middle::ty;
1920
use middle::typeck;
2021

@@ -298,3 +299,10 @@ pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
298299
let cdata = cstore.get_crate_data(cnum);
299300
decoder::get_dylib_dependency_formats(&*cdata)
300301
}
302+
303+
pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum)
304+
-> Vec<lang_items::LangItem>
305+
{
306+
let cdata = cstore.get_crate_data(cnum);
307+
decoder::get_missing_lang_items(&*cdata)
308+
}

src/librustc/metadata/decoder.rs

+15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use metadata::cstore;
2121
use metadata::tydecode::{parse_ty_data, parse_def_id,
2222
parse_type_param_def_data,
2323
parse_bare_fn_ty_data, parse_trait_ref_data};
24+
use middle::lang_items;
2425
use middle::ty::{ImplContainer, TraitContainer};
2526
use middle::ty;
2627
use middle::typeck;
@@ -1299,3 +1300,17 @@ pub fn get_dylib_dependency_formats(cdata: Cmd)
12991300
}
13001301
return result;
13011302
}
1303+
1304+
pub fn get_missing_lang_items(cdata: Cmd)
1305+
-> Vec<lang_items::LangItem>
1306+
{
1307+
let items = reader::get_doc(reader::Doc(cdata.data()), tag_lang_items);
1308+
let mut result = Vec::new();
1309+
reader::tagged_docs(items, tag_lang_items_missing, |missing_doc| {
1310+
let item: lang_items::LangItem =
1311+
FromPrimitive::from_u32(reader::doc_as_u32(missing_doc)).unwrap();
1312+
result.push(item);
1313+
true
1314+
});
1315+
return result;
1316+
}

src/librustc/metadata/encoder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,10 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut Encoder) {
15181518
}
15191519
}
15201520

1521+
for i in ecx.tcx.lang_items.missing.iter() {
1522+
ebml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32);
1523+
}
1524+
15211525
ebml_w.end_tag(); // tag_lang_items
15221526
}
15231527

src/librustc/middle/lang_items.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use driver::session::Session;
2424
use metadata::csearch::each_lang_item;
2525
use middle::ty;
26+
use middle::weak_lang_items;
2627
use syntax::ast;
2728
use syntax::ast_util::local_def;
2829
use syntax::attr::AttrMetaMethods;
@@ -41,21 +42,23 @@ macro_rules! lets_do_this {
4142
$( $variant:ident, $name:expr, $method:ident; )*
4243
) => {
4344

44-
#[deriving(FromPrimitive)]
45+
#[deriving(FromPrimitive, Eq, TotalEq, Hash)]
4546
pub enum LangItem {
4647
$($variant),*
4748
}
4849

4950
pub struct LanguageItems {
50-
pub items: Vec<Option<ast::DefId>> ,
51+
pub items: Vec<Option<ast::DefId>>,
52+
pub missing: Vec<LangItem>,
5153
}
5254

5355
impl LanguageItems {
5456
pub fn new() -> LanguageItems {
5557
fn foo(_: LangItem) -> Option<ast::DefId> { None }
5658

5759
LanguageItems {
58-
items: vec!($(foo($variant)),*)
60+
items: vec!($(foo($variant)),*),
61+
missing: Vec::new(),
5962
}
6063
}
6164

@@ -198,7 +201,8 @@ pub fn collect_language_items(krate: &ast::Crate,
198201
session: &Session) -> LanguageItems {
199202
let mut collector = LanguageItemCollector::new(session);
200203
collector.collect(krate);
201-
let LanguageItemCollector { items, .. } = collector;
204+
let LanguageItemCollector { mut items, .. } = collector;
205+
weak_lang_items::check_crate(krate, session, &mut items);
202206
session.abort_if_errors();
203207
items
204208
}
@@ -240,8 +244,20 @@ lets_do_this! {
240244

241245
StrEqFnLangItem, "str_eq", str_eq_fn;
242246
UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn;
247+
248+
// A number of failure-related lang items. The `fail_` item corresponds to
249+
// divide-by-zero and various failure cases with `match`. The
250+
// `fail_bounds_check` item is for indexing arrays.
251+
//
252+
// The `begin_unwind` lang item has a predefined symbol name and is sort of
253+
// a "weak lang item" in the sense that a crate is not required to have it
254+
// defined to use it, but a final product is required to define it
255+
// somewhere. Additionally, there are restrictions on crates that use a weak
256+
// lang item, but do not have it defined.
243257
FailFnLangItem, "fail_", fail_fn;
244258
FailBoundsCheckFnLangItem, "fail_bounds_check", fail_bounds_check_fn;
259+
BeginUnwindLangItem, "begin_unwind", begin_unwind;
260+
245261
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
246262
ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn;
247263
ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
@@ -257,7 +273,7 @@ lets_do_this! {
257273

258274
TypeIdLangItem, "type_id", type_id;
259275

260-
EhPersonalityLangItem, "eh_personality", eh_personality_fn;
276+
EhPersonalityLangItem, "eh_personality", eh_personality;
261277

262278
ManagedHeapLangItem, "managed_heap", managed_heap;
263279
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
@@ -276,4 +292,6 @@ lets_do_this! {
276292
NoCopyItem, "no_copy_bound", no_copy_bound;
277293
NoShareItem, "no_share_bound", no_share_bound;
278294
ManagedItem, "managed_bound", managed_bound;
295+
296+
StackExhaustedLangItem, "stack_exhausted", stack_exhausted;
279297
}

src/librustc/middle/trans/base.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use lib;
3838
use metadata::{csearch, encoder};
3939
use middle::astencode;
4040
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
41+
use middle::weak_lang_items;
4142
use middle::trans::_match;
4243
use middle::trans::adt;
4344
use middle::trans::build::*;
@@ -1679,6 +1680,19 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: StrBuf, node_id: ast::N
16791680
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
16801681
}
16811682

1683+
// The stack exhaustion lang item shouldn't have a split stack because
1684+
// otherwise it would continue to be exhausted (bad), and both it and the
1685+
// eh_personality functions need to be externally linkable.
1686+
let def = ast_util::local_def(node_id);
1687+
if ccx.tcx.lang_items.stack_exhausted() == Some(def) {
1688+
unset_split_stack(llfn);
1689+
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
1690+
}
1691+
if ccx.tcx.lang_items.eh_personality() == Some(def) {
1692+
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
1693+
}
1694+
1695+
16821696
if is_entry_fn(ccx.sess(), node_id) {
16831697
create_entry_wrapper(ccx, sp, llfn);
16841698
}
@@ -1816,8 +1830,13 @@ fn exported_name(ccx: &CrateContext, id: ast::NodeId,
18161830
// Don't mangle
18171831
path.last().unwrap().to_str().to_strbuf()
18181832
} else {
1819-
// Usual name mangling
1820-
mangle_exported_name(ccx, path, ty, id)
1833+
match weak_lang_items::link_name(attrs) {
1834+
Some(name) => name.get().to_strbuf(),
1835+
None => {
1836+
// Usual name mangling
1837+
mangle_exported_name(ccx, path, ty, id)
1838+
}
1839+
}
18211840
}
18221841
})
18231842
}

src/librustc/middle/trans/cleanup.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
*/
1515

1616
use lib::llvm::{BasicBlockRef, ValueRef};
17-
use middle::lang_items::{EhPersonalityLangItem};
1817
use middle::trans::base;
1918
use middle::trans::build;
2019
use middle::trans::callee;
@@ -665,8 +664,31 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
665664
false);
666665

667666
// The exception handling personality function.
668-
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
669-
let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, ExprId(0));
667+
//
668+
// If our compilation unit has the `eh_personality` lang item somewhere
669+
// within it, then we just need to translate that. Otherwise, we're
670+
// building an rlib which will depend on some upstream implementation of
671+
// this function, so we just codegen a generic reference to it. We don't
672+
// specify any of the types for the function, we just make it a symbol
673+
// that LLVM can later use.
674+
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
675+
Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)),
676+
None => {
677+
let mut personality = self.ccx.eh_personality.borrow_mut();
678+
match *personality {
679+
Some(llpersonality) => llpersonality,
680+
None => {
681+
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
682+
let f = base::decl_cdecl_fn(self.ccx.llmod,
683+
"rust_eh_personality",
684+
fty,
685+
ty::mk_i32());
686+
*personality = Some(f);
687+
f
688+
}
689+
}
690+
}
691+
};
670692

671693
// The only landing pad clause will be 'cleanup'
672694
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);

src/librustc/middle/trans/context.rs

+3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ pub struct CrateContext {
122122
pub uses_gc: bool,
123123
pub dbg_cx: Option<debuginfo::CrateDebugContext>,
124124

125+
pub eh_personality: RefCell<Option<ValueRef>>,
126+
125127
intrinsics: RefCell<HashMap<&'static str, ValueRef>>,
126128
}
127129

@@ -224,6 +226,7 @@ impl CrateContext {
224226
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
225227
uses_gc: false,
226228
dbg_cx: dbg_cx,
229+
eh_personality: RefCell::new(None),
227230
intrinsics: RefCell::new(HashMap::new()),
228231
};
229232

src/librustc/middle/trans/foreign.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use back::{link};
1313
use lib::llvm::llvm;
1414
use lib::llvm::{ValueRef, CallConv, StructRetAttribute, Linkage};
1515
use lib;
16+
use middle::weak_lang_items;
1617
use middle::trans::base::push_ctxt;
1718
use middle::trans::base;
1819
use middle::trans::build::*;
@@ -815,10 +816,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
815816
// the massive simplifications that have occurred.
816817

817818
pub fn link_name(i: &ast::ForeignItem) -> InternedString {
818-
match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
819-
"link_name") {
820-
None => token::get_ident(i.ident),
819+
match attr::first_attr_value_str_by_name(i.attrs.as_slice(), "link_name") {
821820
Some(ln) => ln.clone(),
821+
None => match weak_lang_items::link_name(i.attrs.as_slice()) {
822+
Some(name) => name,
823+
None => token::get_ident(i.ident),
824+
}
822825
}
823826
}
824827

0 commit comments

Comments
 (0)