From de82a9be61cc7f48f1c1a8b6c0e96715d5ec55b0 Mon Sep 17 00:00:00 2001 From: Elliott Slaughter Date: Tue, 10 Jul 2012 15:52:05 -0700 Subject: [PATCH] Move fail upcall into rust libcore. --- src/libcore/core.rc | 7 ++ src/libcore/rt.rs | 27 +++++++ src/rt/rust_upcall.cpp | 10 +++ src/rustc/driver/driver.rs | 7 +- src/rustc/middle/trans/base.rs | 94 ++++++++++++++++++++++- src/rustc/middle/trans/common.rs | 1 + src/test/run-pass/module-polymorphism.rc | 9 +-- src/test/run-pass/module-polymorphism.rs | 6 +- src/test/run-pass/module-polymorphism2.rc | 3 - src/test/run-pass/module-polymorphism3.rc | 2 - 10 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 src/libcore/rt.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index a90758694f83a..ef88258daec59 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -41,6 +41,10 @@ export either, option, result, iter; export libc, os, io, run, rand, sys, unsafe, logging; export arc, comm, task, future, pipes; export extfmt; +// The test harness links against core, so don't include runtime in tests. +// FIXME (#2861): Uncomment this after snapshot gets updated. +//#[cfg(notest)] +export rt; export tuple; export to_str, to_bytes; export dvec, dvec_iter; @@ -206,6 +210,9 @@ mod unsafe; // Exported but not part of the public interface mod extfmt; +// The test harness links against core, so don't include runtime in tests. +#[cfg(notest)] +mod rt; // For internal use, not exported diff --git a/src/libcore/rt.rs b/src/libcore/rt.rs new file mode 100644 index 0000000000000..a588aab9b68ec --- /dev/null +++ b/src/libcore/rt.rs @@ -0,0 +1,27 @@ +//! Runtime calls emitted by the compiler. + +import libc::c_char; +import libc::size_t; + +type rust_task = libc::c_void; + +extern mod rustrt { + #[rust_stack] + fn rust_upcall_fail(expr: *c_char, file: *c_char, line: size_t); +} + +// FIXME (#2861): This needs both the attribute, and the name prefixed with +// 'rt_', otherwise the compiler won't find it. To fix this, see +// gather_rust_rtcalls. +#[rt(fail)] +fn rt_fail(expr: *c_char, file: *c_char, line: size_t) { + rustrt::rust_upcall_fail(expr, file, line); +} + +// Local Variables: +// mode: rust; +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index cae5ce45b5497..736ee84196579 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -98,6 +98,16 @@ upcall_fail(char const *expr, UPCALL_SWITCH_STACK(task, &args, upcall_s_fail); } +// FIXME (#2861): Alias used by libcore/rt.rs to avoid naming conflicts with +// autogenerated wrappers for upcall_fail. Remove this when we fully move away +// away from the C upcall path. +extern "C" CDECL void +rust_upcall_fail(char const *expr, + char const *file, + size_t line) { + upcall_fail(expr, file, line); +} + struct s_trace_args { rust_task *task; char const *msg; diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 1222cfc2d6085..52aa88e6cb639 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -69,10 +69,11 @@ fn build_configuration(sess: session, argv0: ~str, input: input) -> // If the user wants a test runner, then add the test cfg let gen_cfg = { - if sess.opts.test && !attr::contains_name(user_cfg, ~"test") - { + if sess.opts.test && !attr::contains_name(user_cfg, ~"test") { ~[attr::mk_word_item(@~"test")] - } else { ~[] } + } else { + ~[attr::mk_word_item(@~"notest")] + } }; ret vec::append(vec::append(user_cfg, gen_cfg), default_cfg); } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 951bcce910f08..b4f6b57a86bfd 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -37,7 +37,7 @@ import link::{mangle_internal_name_by_type_only, mangle_internal_name_by_path, mangle_internal_name_by_path_and_seq, mangle_exported_name}; -import metadata::{csearch, cstore, encoder}; +import metadata::{csearch, cstore, decoder, encoder}; import metadata::common::link_meta; import util::ppaux; import util::ppaux::{ty_to_str, ty_to_short_str}; @@ -3942,11 +3942,25 @@ fn trans_fail_value(bcx: block, sp_opt: option, let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8())); let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8())); let args = ~[V_str, V_filename, C_int(ccx, V_line)]; - let bcx = invoke(bcx, bcx.ccx().upcalls._fail, args); + let bcx = trans_rtcall(bcx, ~"fail", args); Unreachable(bcx); ret bcx; } +fn trans_rtcall(bcx: block, name: ~str, args: ~[ValueRef]) -> block { + let did = bcx.ccx().rtcalls[name]; + let fty = if did.crate == ast::local_crate { + ty::node_id_to_type(bcx.ccx().tcx, did.node) + } else { + csearch::get_type(bcx.ccx().tcx, did).ty + }; + let rty = ty::ty_fn_ret(fty); + ret trans_call_inner( + bcx, none, fty, rty, + |bcx| lval_static_fn_inner(bcx, did, 0, ~[], none), + arg_vals(args), ignore); +} + fn trans_break_cont(bcx: block, to_end: bool) -> block { let _icx = bcx.insn_ctxt(~"trans_break_cont"); @@ -5314,6 +5328,79 @@ fn trap(bcx: block) { } } +fn push_rtcall(ccx: @crate_ctxt, name: ~str, did: ast::def_id) { + if ccx.rtcalls.contains_key(name) { + fail #fmt("multiple definitions for runtime call %s", name); + } + ccx.rtcalls.insert(name, did); +} + +fn gather_local_rtcalls(ccx: @crate_ctxt, crate: @ast::crate) { + visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{ + visit_item: |item| alt item.node { + ast::item_fn(decl, _, _) { + let attr_metas = attr::attr_metas( + attr::find_attrs_by_name(item.attrs, ~"rt")); + do vec::iter(attr_metas) |attr_meta| { + alt attr::get_meta_item_list(attr_meta) { + some(list) { + let name = *attr::get_meta_item_name(vec::head(list)); + push_rtcall(ccx, name, {crate: ast::local_crate, + node: item.id}); + } + none {} + } + } + } + _ {} + } + with *visit::default_simple_visitor() + })); +} + +fn gather_external_rtcalls(ccx: @crate_ctxt) { + do cstore::iter_crate_data(ccx.sess.cstore) |_cnum, cmeta| { + do decoder::each_path(cmeta) |path| { + let pathname = path.path_string; + alt path.def_like { + decoder::dl_def(d) { + alt d { + ast::def_fn(did, _) { + // FIXME (#2861): This should really iterate attributes + // like gather_local_rtcalls, but we'll need to + // export attributes in metadata/encoder before we can do + // that. + let sentinel = "rt::rt_"; + let slen = str::len(sentinel); + if str::starts_with(pathname, sentinel) { + let name = str::substr(pathname, + slen, str::len(pathname)-slen); + push_rtcall(ccx, name, did); + } + } + _ {} + } + } + _ {} + } + true + } + } +} + +fn gather_rtcalls(ccx: @crate_ctxt, crate: @ast::crate) { + gather_local_rtcalls(ccx, crate); + gather_external_rtcalls(ccx); + + // FIXME (#2861): Check for other rtcalls too, once they are + // supported. Also probably want to check type signature so we don't crash + // in some obscure place in LLVM if the user provides the wrong signature + // for an rtcall. + if !ccx.rtcalls.contains_key(~"fail") { + fail ~"no definition for runtime call fail"; + } +} + fn create_module_map(ccx: @crate_ctxt) -> ValueRef { let elttype = T_struct(~[ccx.int_type, ccx.int_type]); let maptype = T_array(elttype, ccx.module_data.size() + 1u); @@ -5544,6 +5631,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, upcalls: upcall::declare_upcalls(targ_cfg, tn, tydesc_type, llmod), + rtcalls: str_hash::(), tydesc_type: tydesc_type, int_type: int_type, float_type: float_type, @@ -5557,6 +5645,8 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt, mut do_not_commit_warning_issued: false}; + gather_rtcalls(ccx, crate); + { let _icx = ccx.insn_ctxt(~"data"); trans_constants(ccx, crate); diff --git a/src/rustc/middle/trans/common.rs b/src/rustc/middle/trans/common.rs index 77929bdd6a3c5..c002c5a2a43c9 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -118,6 +118,7 @@ type crate_ctxt = { maps: astencode::maps, stats: stats, upcalls: @upcall::upcalls, + rtcalls: hashmap<~str, ast::def_id>, tydesc_type: TypeRef, int_type: TypeRef, float_type: TypeRef, diff --git a/src/test/run-pass/module-polymorphism.rc b/src/test/run-pass/module-polymorphism.rc index 781e3a279b194..3f93608e53add 100644 --- a/src/test/run-pass/module-polymorphism.rc +++ b/src/test/run-pass/module-polymorphism.rc @@ -1,8 +1,5 @@ -#[no_core]; - - #[path = "module-polymorphism-files"] -mod float { +mod my_float { // The type of the float import inst::T; @@ -18,7 +15,7 @@ mod float { } #[path = "module-polymorphism-files"] -mod f64 { +mod my_f64 { import inst::T; @@ -33,7 +30,7 @@ mod f64 { } #[path = "module-polymorphism-files"] -mod f32 { +mod my_f32 { import inst::T; #[path = "inst_f32.rs"] diff --git a/src/test/run-pass/module-polymorphism.rs b/src/test/run-pass/module-polymorphism.rs index e2f8350ef72af..26c3582d6a635 100644 --- a/src/test/run-pass/module-polymorphism.rs +++ b/src/test/run-pass/module-polymorphism.rs @@ -5,7 +5,7 @@ fn main() { // All of these functions are defined by a single module // source file but instantiated for different types - assert float::template::plus(1.0f, 2.0f) == 3.0f; - assert f64::template::plus(1.0f64, 2.0f64) == 3.0f64; - assert f32::template::plus(1.0f32, 2.0f32) == 3.0f32; + assert my_float::template::plus(1.0f, 2.0f) == 3.0f; + assert my_f64::template::plus(1.0f64, 2.0f64) == 3.0f64; + assert my_f32::template::plus(1.0f32, 2.0f32) == 3.0f32; } \ No newline at end of file diff --git a/src/test/run-pass/module-polymorphism2.rc b/src/test/run-pass/module-polymorphism2.rc index 0d64cb46a2672..bc801bcb4a3f2 100644 --- a/src/test/run-pass/module-polymorphism2.rc +++ b/src/test/run-pass/module-polymorphism2.rc @@ -1,6 +1,3 @@ -#[no_core]; - - #[path = "module-polymorphism2-files"] mod mystd { diff --git a/src/test/run-pass/module-polymorphism3.rc b/src/test/run-pass/module-polymorphism3.rc index 34dc9000e3236..3ed7be15ff5fa 100644 --- a/src/test/run-pass/module-polymorphism3.rc +++ b/src/test/run-pass/module-polymorphism3.rc @@ -1,5 +1,3 @@ -#[no_core]; - // Use one template module to specify in a single file the implementation // of functions for multiple types