Skip to content

rustc: Add official support for weak failure #14293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 21, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/libcore/failure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,19 @@ fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {

#[cold]
pub fn begin_unwind(fmt: &fmt::Arguments, file: &'static str, line: uint) -> ! {
// FIXME: this should be a proper lang item, it should not just be some
// undefined symbol sitting in the middle of nowhere.
#[allow(ctypes)]
extern { fn rust_begin_unwind(fmt: &fmt::Arguments, file: &'static str,
line: uint) -> !; }
unsafe { rust_begin_unwind(fmt, file, line) }
#[cfg(stage0)]
extern {
#[link_name = "rust_begin_unwind"]
fn begin_unwind(fmt: &fmt::Arguments, file: &'static str,
line: uint) -> !;
}
#[allow(ctypes)]
#[cfg(not(stage0))]
extern {
#[lang = "begin_unwind"]
fn begin_unwind(fmt: &fmt::Arguments, file: &'static str,
line: uint) -> !;
}
unsafe { begin_unwind(fmt, file, line) }
}
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ pub mod middle {
pub mod dead;
pub mod expr_use_visitor;
pub mod dependency_format;
pub mod weak_lang_items;
}

pub mod front {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ pub static tag_lang_items: uint = 0x70;
pub static tag_lang_items_item: uint = 0x71;
pub static tag_lang_items_item_id: uint = 0x72;
pub static tag_lang_items_item_node_id: uint = 0x73;
pub static tag_lang_items_missing: uint = 0x74;

pub static tag_item_unnamed_field: uint = 0x74;
pub static tag_item_unnamed_field: uint = 0x75;
pub static tag_items_data_item_visibility: uint = 0x76;
pub static tag_items_data_item_sized: uint = 0x77;

Expand Down
8 changes: 8 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
use middle::lang_items;
use middle::ty;
use middle::typeck;

Expand Down Expand Up @@ -298,3 +299,10 @@ pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
let cdata = cstore.get_crate_data(cnum);
decoder::get_dylib_dependency_formats(&*cdata)
}

pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum)
-> Vec<lang_items::LangItem>
{
let cdata = cstore.get_crate_data(cnum);
decoder::get_missing_lang_items(&*cdata)
}
15 changes: 15 additions & 0 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use metadata::cstore;
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::lang_items;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty;
use middle::typeck;
Expand Down Expand Up @@ -1299,3 +1300,17 @@ pub fn get_dylib_dependency_formats(cdata: Cmd)
}
return result;
}

pub fn get_missing_lang_items(cdata: Cmd)
-> Vec<lang_items::LangItem>
{
let items = reader::get_doc(reader::Doc(cdata.data()), tag_lang_items);
let mut result = Vec::new();
reader::tagged_docs(items, tag_lang_items_missing, |missing_doc| {
let item: lang_items::LangItem =
FromPrimitive::from_u32(reader::doc_as_u32(missing_doc)).unwrap();
result.push(item);
true
});
return result;
}
4 changes: 4 additions & 0 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,10 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut Encoder) {
}
}

for i in ecx.tcx.lang_items.missing.iter() {
ebml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32);
}

ebml_w.end_tag(); // tag_lang_items
}

Expand Down
28 changes: 23 additions & 5 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use driver::session::Session;
use metadata::csearch::each_lang_item;
use middle::ty;
use middle::weak_lang_items;
use syntax::ast;
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
Expand All @@ -41,21 +42,23 @@ macro_rules! lets_do_this {
$( $variant:ident, $name:expr, $method:ident; )*
) => {

#[deriving(FromPrimitive)]
#[deriving(FromPrimitive, Eq, TotalEq, Hash)]
pub enum LangItem {
$($variant),*
}

pub struct LanguageItems {
pub items: Vec<Option<ast::DefId>> ,
pub items: Vec<Option<ast::DefId>>,
pub missing: Vec<LangItem>,
}

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

LanguageItems {
items: vec!($(foo($variant)),*)
items: vec!($(foo($variant)),*),
missing: Vec::new(),
}
}

Expand Down Expand Up @@ -198,7 +201,8 @@ pub fn collect_language_items(krate: &ast::Crate,
session: &Session) -> LanguageItems {
let mut collector = LanguageItemCollector::new(session);
collector.collect(krate);
let LanguageItemCollector { items, .. } = collector;
let LanguageItemCollector { mut items, .. } = collector;
weak_lang_items::check_crate(krate, session, &mut items);
session.abort_if_errors();
items
}
Expand Down Expand Up @@ -240,8 +244,20 @@ lets_do_this! {

StrEqFnLangItem, "str_eq", str_eq_fn;
UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn;

// A number of failure-related lang items. The `fail_` item corresponds to
// divide-by-zero and various failure cases with `match`. The
// `fail_bounds_check` item is for indexing arrays.
//
// The `begin_unwind` lang item has a predefined symbol name and is sort of
// a "weak lang item" in the sense that a crate is not required to have it
// defined to use it, but a final product is required to define it
// somewhere. Additionally, there are restrictions on crates that use a weak
// lang item, but do not have it defined.
FailFnLangItem, "fail_", fail_fn;
FailBoundsCheckFnLangItem, "fail_bounds_check", fail_bounds_check_fn;
BeginUnwindLangItem, "begin_unwind", begin_unwind;

ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
ClosureExchangeMallocFnLangItem, "closure_exchange_malloc", closure_exchange_malloc_fn;
ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
Expand All @@ -257,7 +273,7 @@ lets_do_this! {

TypeIdLangItem, "type_id", type_id;

EhPersonalityLangItem, "eh_personality", eh_personality_fn;
EhPersonalityLangItem, "eh_personality", eh_personality;

ManagedHeapLangItem, "managed_heap", managed_heap;
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
Expand All @@ -276,4 +292,6 @@ lets_do_this! {
NoCopyItem, "no_copy_bound", no_copy_bound;
NoShareItem, "no_share_bound", no_share_bound;
ManagedItem, "managed_bound", managed_bound;

StackExhaustedLangItem, "stack_exhausted", stack_exhausted;
}
23 changes: 21 additions & 2 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use lib;
use metadata::{csearch, encoder};
use middle::astencode;
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
use middle::trans::_match;
use middle::trans::adt;
use middle::trans::build::*;
Expand Down Expand Up @@ -1679,6 +1680,19 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: StrBuf, node_id: ast::N
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
}

// The stack exhaustion lang item shouldn't have a split stack because
// otherwise it would continue to be exhausted (bad), and both it and the
// eh_personality functions need to be externally linkable.
let def = ast_util::local_def(node_id);
if ccx.tcx.lang_items.stack_exhausted() == Some(def) {
unset_split_stack(llfn);
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
}
if ccx.tcx.lang_items.eh_personality() == Some(def) {
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
}


if is_entry_fn(ccx.sess(), node_id) {
create_entry_wrapper(ccx, sp, llfn);
}
Expand Down Expand Up @@ -1816,8 +1830,13 @@ fn exported_name(ccx: &CrateContext, id: ast::NodeId,
// Don't mangle
path.last().unwrap().to_str().to_strbuf()
} else {
// Usual name mangling
mangle_exported_name(ccx, path, ty, id)
match weak_lang_items::link_name(attrs) {
Some(name) => name.get().to_strbuf(),
None => {
// Usual name mangling
mangle_exported_name(ccx, path, ty, id)
}
}
}
})
}
Expand Down
28 changes: 25 additions & 3 deletions src/librustc/middle/trans/cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/

use lib::llvm::{BasicBlockRef, ValueRef};
use middle::lang_items::{EhPersonalityLangItem};
use middle::trans::base;
use middle::trans::build;
use middle::trans::callee;
Expand Down Expand Up @@ -665,8 +664,31 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
false);

// The exception handling personality function.
let def_id = common::langcall(pad_bcx, None, "", EhPersonalityLangItem);
let llpersonality = callee::trans_fn_ref(pad_bcx, def_id, ExprId(0));
//
// If our compilation unit has the `eh_personality` lang item somewhere
// within it, then we just need to translate that. Otherwise, we're
// building an rlib which will depend on some upstream implementation of
// this function, so we just codegen a generic reference to it. We don't
// specify any of the types for the function, we just make it a symbol
// that LLVM can later use.
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)),
None => {
let mut personality = self.ccx.eh_personality.borrow_mut();
match *personality {
Some(llpersonality) => llpersonality,
None => {
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = base::decl_cdecl_fn(self.ccx.llmod,
"rust_eh_personality",
fty,
ty::mk_i32());
*personality = Some(f);
f
}
}
}
};

// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1u);
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/trans/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub struct CrateContext {
pub uses_gc: bool,
pub dbg_cx: Option<debuginfo::CrateDebugContext>,

pub eh_personality: RefCell<Option<ValueRef>>,

intrinsics: RefCell<HashMap<&'static str, ValueRef>>,
}

Expand Down Expand Up @@ -224,6 +226,7 @@ impl CrateContext {
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
uses_gc: false,
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
intrinsics: RefCell::new(HashMap::new()),
};

Expand Down
9 changes: 6 additions & 3 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use back::{link};
use lib::llvm::llvm;
use lib::llvm::{ValueRef, CallConv, StructRetAttribute, Linkage};
use lib;
use middle::weak_lang_items;
use middle::trans::base::push_ctxt;
use middle::trans::base;
use middle::trans::build::*;
Expand Down Expand Up @@ -815,10 +816,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
// the massive simplifications that have occurred.

pub fn link_name(i: &ast::ForeignItem) -> InternedString {
match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
"link_name") {
None => token::get_ident(i.ident),
match attr::first_attr_value_str_by_name(i.attrs.as_slice(), "link_name") {
Some(ln) => ln.clone(),
None => match weak_lang_items::link_name(i.attrs.as_slice()) {
Some(name) => name,
None => token::get_ident(i.ident),
}
}
}

Expand Down
Loading