diff --git a/src/libcore/failure.rs b/src/libcore/failure.rs index c4a2c9a6099..003ebed6364 100644 --- a/src/libcore/failure.rs +++ b/src/libcore/failure.rs @@ -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) } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 678d525ddcb..5f13ed4942e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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 { diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 518dc4b05ca..f30d6119339 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index fc5c01d4d8d..f30e24a3151 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -15,6 +15,7 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; +use middle::lang_items; use middle::ty; use middle::typeck; @@ -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 +{ + let cdata = cstore.get_crate_data(cnum); + decoder::get_missing_lang_items(&*cdata) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index da21cde3d6c..b3ef888c0b4 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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; @@ -1299,3 +1300,17 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) } return result; } + +pub fn get_missing_lang_items(cdata: Cmd) + -> Vec +{ + 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; +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a7ba8300aed..34baed3acc8 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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 } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index ed8b27a8660..81e9c3f5ec6 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -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; @@ -41,13 +42,14 @@ 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> , + pub items: Vec>, + pub missing: Vec, } impl LanguageItems { @@ -55,7 +57,8 @@ impl LanguageItems { fn foo(_: LangItem) -> Option { None } LanguageItems { - items: vec!($(foo($variant)),*) + items: vec!($(foo($variant)),*), + missing: Vec::new(), } } @@ -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 } @@ -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; @@ -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; @@ -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; } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 92e3b95abad..a88bc243277 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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::*; @@ -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); } @@ -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) + } + } } }) } diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs index 776de01614d..87cde42e398 100644 --- a/src/librustc/middle/trans/cleanup.rs +++ b/src/librustc/middle/trans/cleanup.rs @@ -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; @@ -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); diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 71fcb0b4de5..a737361b55a 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -122,6 +122,8 @@ pub struct CrateContext { pub uses_gc: bool, pub dbg_cx: Option, + pub eh_personality: RefCell>, + intrinsics: RefCell>, } @@ -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()), }; diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 2c4043a62f5..fb6aff0e26e 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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::*; @@ -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), + } } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs new file mode 100644 index 00000000000..cbe04e4fcda --- /dev/null +++ b/src/librustc/middle/weak_lang_items.rs @@ -0,0 +1,124 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Validity checking for weak lang items + +use driver::config; +use driver::session::Session; +use metadata::csearch; +use middle::lang_items; + +use syntax::ast; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use syntax::visit::Visitor; +use syntax::visit; + +use 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, +} + +/// Checks the crate for usage of weak lang items, returning a vector of all the +/// language items required by this crate, but not defined yet. +pub fn check_crate(krate: &ast::Crate, + sess: &Session, + items: &mut lang_items::LanguageItems) { + // These are never called by user code, they're generated by the compiler. + // They will never implicitly be added to the `missing` array unless we do + // so here. + if items.stack_exhausted().is_none() { + items.missing.push(lang_items::StackExhaustedLangItem); + } + if items.eh_personality().is_none() { + items.missing.push(lang_items::EhPersonalityLangItem); + } + + { + let mut cx = Context { sess: sess, items: items }; + visit::walk_crate(&mut cx, krate, ()); + } + verify(sess, items); +} + +pub fn link_name(attrs: &[ast::Attribute]) -> Option { + lang_items::extract(attrs).and_then(|name| { + $(if name.get() == stringify!($name) { + Some(InternedString::new(stringify!($sym))) + } else)* { + None + } + }) +} + +fn verify(sess: &Session, items: &lang_items::LanguageItems) { + // We only need to check for the presence of weak lang items if we're + // emitting something that's not an rlib. + let needs_check = sess.crate_types.borrow().iter().any(|kind| { + match *kind { + config::CrateTypeDylib | + config::CrateTypeExecutable | + config::CrateTypeStaticlib => true, + config::CrateTypeRlib => false, + } + }); + if !needs_check { return } + + let mut missing = HashSet::new(); + sess.cstore.iter_crate_data(|cnum, _| { + for item in csearch::get_missing_lang_items(&sess.cstore, cnum).iter() { + missing.insert(*item); + } + }); + + $( + if missing.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)* { + self.sess.span_err(span, + format!("unknown external lang item: `{}`", + name)); + } + } +} + +impl<'a> Visitor<()> for Context<'a> { + fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) { + match lang_items::extract(i.attrs.as_slice()) { + None => {} + Some(lang_item) => self.register(lang_item.get(), i.span), + } + visit::walk_foreign_item(self, i, ()) + } +} + +) ) + +weak_lang_items!( + begin_unwind, BeginUnwindLangItem, rust_begin_unwind; + stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted; + eh_personality, EhPersonalityLangItem, rust_eh_personality; +) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 791ee96d672..4e2b23310ab 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -71,7 +71,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) let sessopts = driver::config::Options { maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()), addl_lib_search_paths: RefCell::new(libs), - crate_types: vec!(driver::config::CrateTypeDylib), + crate_types: vec!(driver::config::CrateTypeRlib), lint_opts: vec!((lint::Warnings, lint::allow)), ..rustc::driver::config::basic_options().clone() }; diff --git a/src/libstd/rt/stack.rs b/src/libstd/rt/stack.rs index b9bcd1de8fc..b3be742e1ed 100644 --- a/src/libstd/rt/stack.rs +++ b/src/libstd/rt/stack.rs @@ -30,12 +30,9 @@ pub static RED_ZONE: uint = 20 * 1024; /// stacks are currently not enabled as segmented stacks, but rather one giant /// stack segment. This means that whenever we run out of stack, we want to /// truly consider it to be stack overflow rather than allocating a new stack. -#[no_mangle] // - this is called from C code -#[no_split_stack] // - it would be sad for this function to trigger __morestack -#[doc(hidden)] // - Function must be `pub` to get exported, but it's - // irrelevant for documentation purposes. -#[cfg(not(test))] // in testing, use the original libstd's version -pub extern "C" fn rust_stack_exhausted() { +#[cfg(not(test), not(stage0))] // in testing, use the original libstd's version +#[lang = "stack_exhausted"] +extern fn stack_exhausted() { use option::{Option, None, Some}; use owned::Box; use rt::local::Local; @@ -106,6 +103,35 @@ pub extern "C" fn rust_stack_exhausted() { } } +#[no_mangle] // - this is called from C code +#[no_split_stack] // - it would be sad for this function to trigger __morestack +#[doc(hidden)] // - Function must be `pub` to get exported, but it's + // irrelevant for documentation purposes. +#[cfg(stage0, not(test))] // in testing, use the original libstd's version +pub extern "C" fn rust_stack_exhausted() { + use option::{Option, None, Some}; + use owned::Box; + use rt::local::Local; + use rt::task::Task; + use str::Str; + use intrinsics; + + unsafe { + let limit = get_sp_limit(); + record_sp_limit(limit - RED_ZONE / 2); + let task: Option> = Local::try_take(); + let name = match task { + Some(ref task) => { + task.name.as_ref().map(|n| n.as_slice()) + } + None => None + }; + let name = name.unwrap_or(""); + rterrln!("task '{}' has overflowed its stack", name); + intrinsics::abort(); + } +} + #[inline(always)] pub unsafe fn record_stack_bounds(stack_lo: uint, stack_hi: uint) { // When the old runtime had segmented stacks, it used a calculation that was diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 1cc513825a7..af87a31b7bd 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -211,8 +211,24 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } + #[lang="eh_personality"] + #[cfg(not(stage0))] + extern fn eh_personality( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context + ) -> uw::_Unwind_Reason_Code + { + unsafe { + __gcc_personality_v0(version, actions, exception_class, ue_header, + context) + } + } #[lang="eh_personality"] #[no_mangle] // so we can reference it by name from middle/trans/base.rs + #[cfg(stage0)] pub extern "C" fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, @@ -263,8 +279,22 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } + #[lang="eh_personality"] + #[cfg(not(stage0))] + extern "C" fn eh_personality( + state: uw::_Unwind_State, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context + ) -> uw::_Unwind_Reason_Code + { + unsafe { + __gcc_personality_v0(state, ue_header, context) + } + } + #[lang="eh_personality"] #[no_mangle] // so we can reference it by name from middle/trans/base.rs + #[cfg(stage0)] pub extern "C" fn rust_eh_personality( state: uw::_Unwind_State, ue_header: *uw::_Unwind_Exception, @@ -296,8 +326,15 @@ pub mod eabi { } // Entry point of failure from the libcore crate +#[cfg(not(test), not(stage0))] +#[lang = "begin_unwind"] +pub extern fn rust_begin_unwind(msg: &fmt::Arguments, + file: &'static str, line: uint) -> ! { + begin_unwind_fmt(msg, file, line) +} + #[no_mangle] -#[cfg(not(test))] +#[cfg(not(test), stage0)] pub extern fn rust_begin_unwind(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! { begin_unwind_fmt(msg, file, line) @@ -310,7 +347,8 @@ pub extern fn rust_begin_unwind(msg: &fmt::Arguments, /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. #[inline(never)] #[cold] -pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str, line: uint) -> ! { +pub fn begin_unwind_fmt(msg: &fmt::Arguments, file: &'static str, + line: uint) -> ! { // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // failure + OOM properly anyway (see comment in begin_unwind diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index 1435a101115..2c9a5bc433f 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -13,5 +13,8 @@ #[lang="fail_"] fn fail(_: *i8, _: *i8, _: uint) -> ! { loop {} } -#[no_mangle] -pub extern "C" fn rust_stack_exhausted() {} +#[lang = "stack_exhausted"] +extern fn stack_exhausted() {} + +#[lang = "eh_personality"] +extern fn eh_personality() {} diff --git a/src/test/auxiliary/weak-lang-items.rs b/src/test/auxiliary/weak-lang-items.rs new file mode 100644 index 00000000000..68a2ae24b85 --- /dev/null +++ b/src/test/auxiliary/weak-lang-items.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +// This aux-file will require the eh_personality function to be codegen'd, but +// it hasn't been defined just yet. Make sure we don't explode. + +#![no_std] +#![feature(phase)] +#![crate_type = "rlib"] + +#[phase(syntax, link)] +extern crate core; + +struct A; + +impl core::ops::Drop for A { + fn drop(&mut self) {} +} + +pub fn foo() { + let _a = A; + fail!("wut"); +} + +mod std { + pub use core::{option, fmt}; +} + diff --git a/src/test/compile-fail/weak-lang-item.rs b/src/test/compile-fail/weak-lang-item.rs new file mode 100644 index 00000000000..a1b64b77ac1 --- /dev/null +++ b/src/test/compile-fail/weak-lang-item.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:weak-lang-items.rs +// error-pattern: language item required, but not found: `begin_unwind` +// error-pattern: language item required, but not found: `stack_exhausted` +// error-pattern: language item required, but not found: `eh_personality` + +#![no_std] + +extern crate core; +extern crate other = "weak-lang-items"; diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index b95f0769d53..0dbd4c67530 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -19,8 +19,8 @@ extern crate libc; extern { fn puts(s: *u8); } extern "rust-intrinsic" { fn transmute(t: T) -> U; } -#[no_mangle] -pub extern fn rust_stack_exhausted() {} +#[lang = "stack_exhausted"] extern fn stack_exhausted() {} +#[lang = "eh_personality"] extern fn eh_personality() {} #[start] #[no_split_stack] diff --git a/src/test/run-pass/weak-lang-item.rs b/src/test/run-pass/weak-lang-item.rs new file mode 100644 index 00000000000..889259b6acd --- /dev/null +++ b/src/test/run-pass/weak-lang-item.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:weak-lang-items.rs + +extern crate other = "weak-lang-items"; + +use std::task; + +fn main() { + let _ = task::try(proc() { + other::foo() + }); +}