Merge remote-tracking branch 'mozilla/incoming' into incoming

This commit is contained in:
Tim Chevalier 2012-06-21 08:47:48 -07:00
commit 4396ad488f
17 changed files with 220 additions and 84 deletions

View File

@ -94,27 +94,31 @@ fn listen<T: send, U>(f: fn(chan<T>) -> U) -> U {
f(po.chan())
}
resource port_ptr<T: send>(po: *rust_port) unsafe {
class port_ptr<T:send> {
let po: *rust_port;
new(po: *rust_port) { self.po = po; }
drop unsafe {
task::unkillable {||
// Once the port is detached it's guaranteed not to receive further
// messages
let yield = 0u;
let yieldp = ptr::addr_of(yield);
rustrt::rust_port_begin_detach(po, yieldp);
rustrt::rust_port_begin_detach(self.po, yieldp);
if yield != 0u {
// Need to wait for the port to be detached
// FIXME: If this fails then we're going to leave our port
// in a bogus state. (Issue #1988)
task::yield();
}
rustrt::rust_port_end_detach(po);
rustrt::rust_port_end_detach(self.po);
// Drain the port so that all the still-enqueued items get dropped
while rustrt::rust_port_size(po) > 0u as size_t {
recv_::<T>(po);
while rustrt::rust_port_size(self.po) > 0u as size_t {
recv_::<T>(self.po);
}
rustrt::del_port(po);
rustrt::del_port(self.po);
}
}
}
#[doc = "
@ -126,21 +130,26 @@ Fails if the port is detached or dead. Fails if the port
is owned by a different task.
"]
fn as_raw_port<T: send, U>(ch: comm::chan<T>, f: fn(*rust_port) -> U) -> U {
resource portref(p: *rust_port) {
if !ptr::is_null(p) {
rustrt::rust_port_drop(p);
}
class portref {
let p: *rust_port;
new(p: *rust_port) { self.p = p; }
drop {
if !ptr::is_null(self.p) {
rustrt::rust_port_drop(self.p);
}
}
}
let p = portref(rustrt::rust_port_take(*ch));
if ptr::is_null(*p) {
if ptr::is_null(p.p) {
fail "unable to locate port for channel"
} else if rustrt::get_task_id() != rustrt::rust_port_task(*p) {
} else if rustrt::get_task_id() != rustrt::rust_port_task(p.p) {
fail "unable to access unowned port"
}
f(*p)
f(p.p)
}
#[doc = "
@ -148,7 +157,7 @@ Constructs a channel. The channel is bound to the port used to
construct it.
"]
fn chan<T: send>(p: port<T>) -> chan<T> {
chan_t(rustrt::get_port_id(***p))
chan_t(rustrt::get_port_id((**p).po))
}
#[doc = "
@ -170,10 +179,10 @@ fn send<T: send>(ch: chan<T>, -data: T) {
Receive from a port. If no data is available on the port then the
task will block until data becomes available.
"]
fn recv<T: send>(p: port<T>) -> T { recv_(***p) }
fn recv<T: send>(p: port<T>) -> T { recv_((**p).po) }
#[doc = "Returns true if there are messages available"]
fn peek<T: send>(p: port<T>) -> bool { peek_(***p) }
fn peek<T: send>(p: port<T>) -> bool { peek_((**p).po) }
#[doc(hidden)]
fn recv_chan<T: send>(ch: comm::chan<T>) -> T {
@ -196,7 +205,7 @@ fn recv_<T: send>(p: *rust_port) -> T {
// Data isn't available yet, so res has not been initialized.
task::yield();
} else {
// In the absense of compiler-generated preemption points
// In the absence of compiler-generated preemption points
// this is a good place to yield
task::yield();
}
@ -210,7 +219,7 @@ fn peek_(p: *rust_port) -> bool unsafe {
#[doc = "Receive on one of two ports"]
fn select2<A: send, B: send>(p_a: port<A>, p_b: port<B>)
-> either<A, B> unsafe {
let ports = [***p_a, ***p_b];
let ports = [(**p_a).po, (**p_b).po];
let n_ports = 2 as libc::size_t;
let yield = 0u, yieldp = ptr::addr_of(yield);
@ -233,9 +242,9 @@ fn select2<A: send, B: send>(p_a: port<A>, p_b: port<B>)
// Now we know the port we're supposed to receive from
assert resport != ptr::null();
if resport == ***p_a {
if resport == (**p_a).po {
either::left(recv(p_a))
} else if resport == ***p_b {
} else if resport == (**p_b).po {
either::right(recv(p_b))
} else {
fail "unexpected result from rust_port_select";
@ -482,4 +491,4 @@ fn test_port_detach_fail() {
}
}
}
}
}

View File

@ -23,10 +23,10 @@ fn walk_stack(visit: fn(frame) -> bool) {
reinterpret_cast(frame_pointer)
};
loop {
let frame = frame(frame_address);
let fr = frame(frame_address);
#debug("frame: %x", unsafe { reinterpret_cast(frame.fp) });
visit(frame);
#debug("frame: %x", unsafe { reinterpret_cast(fr.fp) });
visit(fr);
unsafe {
let next_fp: **word = reinterpret_cast(frame_address);
@ -44,7 +44,7 @@ fn walk_stack(visit: fn(frame) -> bool) {
#[test]
fn test_simple() {
for walk_stack { |frame|
for walk_stack { |_frame|
}
}
@ -53,7 +53,7 @@ fn test_simple_deep() {
fn run(i: int) {
if i == 0 { ret }
for walk_stack { |frame|
for walk_stack { |_frame|
unsafe {
breakpoint();
}

View File

@ -566,7 +566,7 @@ pure fn to_upper(s: str/&) -> str {
}
#[doc = "
Replace all occurances of one string with another
Replace all occurrences of one string with another
# Arguments

View File

@ -7,7 +7,7 @@ import future::future;
export map, mapi, alli, any, mapi_factory;
#[doc="The maximum number of tasks this module will spawn for a single
operationg."]
operation."]
const max_tasks : uint = 32u;
#[doc="The minimum number of elements each task will process."]

View File

@ -47,6 +47,7 @@ fn check_loans(bccx: borrowck_ctxt,
mut declared_purity: ast::impure_fn,
mut fn_args: @[]});
let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
visit_local: check_loans_in_local,
visit_block: check_loans_in_block,
visit_fn: check_loans_in_fn
with *visit::default_visitor()});
@ -419,6 +420,9 @@ impl methods for check_loan_ctxt {
// rvalues, I guess.
cat_special(sk_static_item) { }
cat_deref(_, _, unsafe_ptr) {
}
// Nothing else.
_ {
self.bccx.span_err(
@ -542,6 +546,18 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
#debug["purity on exit=%?", copy self.declared_purity];
}
fn check_loans_in_local(local: @ast::local,
&&self: check_loan_ctxt,
vt: visit::vt<check_loan_ctxt>) {
alt local.node.init {
some({op: ast::init_move, expr: expr}) {
self.check_move_out(expr);
}
some({op: ast::init_assign, _}) | none {}
}
visit::visit_local(local, self, vt);
}
fn check_loans_in_expr(expr: @ast::expr,
&&self: check_loan_ctxt,
vt: visit::vt<check_loan_ctxt>) {

View File

@ -573,7 +573,6 @@ fn visit_item_with_scope(e: @env, i: @ast::item,
}
ast::item_class(tps, ifaces, members, ctor, m_dtor, _) {
v.visit_ty_params(tps, sc, v);
// Can maybe skip this now that we require self on class fields
let class_scope = @cons(scope_item(i), sc);
/* visit the constructor... */
let ctor_scope = @cons(scope_method(ctor.node.self_id, tps),
@ -1061,7 +1060,7 @@ fn lookup_in_scope(e: env, &&sc: scopes, sp: span, name: ident, ns: namespace,
}
ast::item_class(tps, _, members, ctor, _, _) {
if ns == ns_type {
ret lookup_in_ty_params(e, name, tps);
ret lookup_in_ty_params(e, name, tps);
}
if ns == ns_val && name == it.ident {
ret some(ast::def_fn(local_def(ctor.node.id),
@ -1317,13 +1316,14 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
alt i.node {
ast::item_const(*) {
if ns == ns_val {
ret some(ast::def_const(local_def(i.id))); }
}
ast::item_fn(decl, _, _) {
if ns == ns_val {
ret some(ast::def_fn(local_def(i.id), decl.purity));
ret some(ast::def_const(local_def(i.id)));
}
}
ast::item_fn(decl, _, _) {
if ns == ns_val {
ret some(ast::def_fn(local_def(i.id), decl.purity));
}
}
ast::item_mod(_) {
if ns == ns_module { ret some(ast::def_mod(local_def(i.id))); }
}
@ -1342,9 +1342,16 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option<def> {
_ { }
}
}
ast::item_class(*) {
if ns == ns_type {
ret some(ast::def_class(local_def(i.id)));
ast::item_class(_, _, _members, ct, _, _) {
alt ns {
ns_type {
ret some(ast::def_class(local_def(i.id)));
}
ns_val {
ret some(ast::def_fn(local_def(ct.node.id),
ast::impure_fn));
}
ns_module { }
}
}
ast::item_impl(*) { /* ??? */ }
@ -1653,14 +1660,6 @@ fn index_mod(md: ast::_mod) -> mod_index {
ast::item_class(tps, _, items, ctor, _, _) {
// add the class name itself
add_to_index(index, it.ident, mie_item(it));
// add the constructor decl
add_to_index(index, it.ident,
mie_item(@{ident: it.ident, attrs: [],
id: ctor.node.id,
node:
item_fn(ctor.node.dec, tps, ctor.node.body),
vis: ast::public,
span: ctor.node.body.span}));
}
}
}

View File

@ -754,7 +754,8 @@ fn trans_class_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id,
// We have to cast v0
let classptr = GEPi(bcx, v0, [0u, 1u]);
// Find and call the actual destructor
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, substs.tps);
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, some(class_did),
substs.tps);
// The second argument is the "self" argument for drop
let params = lib::llvm::fn_ty_param_tys
(llvm::LLVMGetElementType
@ -829,7 +830,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
build_return(bcx);
}
fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, substs: [ty::t])
fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id,
// Parent ID is an option because resources don't
// have one. We can make this a def_id when
// resources get removed.
opt_id: option<ast::def_id>, substs: [ty::t])
-> ValueRef {
let _icx = ccx.insn_ctxt("trans_res_dtor");
if (substs.len() > 0u) {
@ -841,14 +846,27 @@ fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, substs: [ty::t])
} else if did.crate == ast::local_crate {
get_item_val(ccx, did.node)
} else {
let fty = ty::mk_fn(ccx.tcx, {purity: ast::impure_fn,
proto: ast::proto_bare,
inputs: [{mode: ast::expl(ast::by_ref),
alt opt_id {
some(parent_id) {
let tcx = ccx.tcx;
let name = csearch::get_symbol(ccx.sess.cstore, did);
let class_ty = ty::subst_tps(tcx, substs,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv,
llty)
}
none {
let fty = ty::mk_fn(ccx.tcx, {purity: ast::impure_fn,
proto: ast::proto_bare,
inputs: [{mode: ast::expl(ast::by_ref),
ty: ty::mk_nil_ptr(ccx.tcx)}],
output: ty::mk_nil(ccx.tcx),
ret_style: ast::return_val,
constraints: []});
trans_external_path(ccx, did, fty)
trans_external_path(ccx, did, fty)
}
}
}
}
@ -862,7 +880,7 @@ fn trans_res_drop(bcx: block, rs: ValueRef, did: ast::def_id,
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|bcx|
let valptr = GEPi(bcx, rs, [0u, 1u]);
// Find and call the actual destructor.
let dtor_addr = get_res_dtor(ccx, did, tps);
let dtor_addr = get_res_dtor(ccx, did, none, tps);
let args = [bcx.fcx.llretptr, null_env_ptr(bcx)];
// Kludge to work around the fact that we know the precise type of the
// value here, but the dtor expects a type that might have opaque
@ -2304,14 +2322,14 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
}
}
ast_map::node_dtor(_, dtor, _, pt) {
let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
dtor.node.self_id)) {
some(did) { did }
none { ccx.sess.span_bug(dtor.span, "Bad self ty in \
let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
dtor.node.self_id)) {
some(did) { did }
none { ccx.sess.span_bug(dtor.span, "Bad self ty in \
dtor"); }
};
trans_class_dtor(ccx, *pt, dtor.node.body,
dtor.node.id, psubsts, some(hash_id), parent_id)
};
trans_class_dtor(ccx, *pt, dtor.node.body,
dtor.node.id, psubsts, some(hash_id), parent_id)
}
// Ugh -- but this ensures any new variants won't be forgotten
ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
@ -4930,15 +4948,15 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
}
fn trans_class_dtor(ccx: @crate_ctxt, path: path,
body: ast::blk,
dtor_id: ast::node_id, substs: option<param_substs>,
hash_id: option<mono_id>, parent_id: ast::def_id)
body: ast::blk, dtor_id: ast::node_id,
psubsts: option<param_substs>,
hash_id: option<mono_id>, parent_id: ast::def_id)
-> ValueRef {
let tcx = ccx.tcx;
/* Look up the parent class's def_id */
let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty;
/* Substitute in the class type if necessary */
option::iter(substs) {|ss|
option::iter(psubsts) {|ss|
class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
}
@ -4947,7 +4965,9 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
T_ptr(type_of(ccx, class_ty))],
llvm::LLVMVoidType());
let s = get_dtor_symbol(ccx, path, dtor_id);
let s = get_dtor_symbol(ccx, path, dtor_id, psubsts);
/* Register the dtor as a function. It has external linkage */
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage);
@ -4959,7 +4979,7 @@ fn trans_class_dtor(ccx: @crate_ctxt, path: path,
}
/* Translate the dtor body */
trans_fn(ccx, path, ast_util::dtor_dec(),
body, lldecl, impl_self(class_ty), substs, dtor_id);
body, lldecl, impl_self(class_ty), psubsts, dtor_id);
lldecl
}
@ -5196,16 +5216,34 @@ fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
} + [path_name(i.ident)]
}
/* If there's already a symbol for the dtor with <id>, return it;
otherwise, create one and register it, returning it as well */
fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id) -> str {
/* If there's already a symbol for the dtor with <id> and substs <substs>,
return it; otherwise, create one and register it, returning it as well */
fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id,
substs: option<param_substs>) -> str {
let t = ty::node_id_to_type(ccx.tcx, id);
alt ccx.item_symbols.find(id) {
some(s) { s }
none if is_none(substs) {
let s = mangle_exported_name(ccx,
path + [path_name(@ccx.names("dtor"))],
t);
ccx.item_symbols.insert(id, s);
s
}
none {
let s = mangle_exported_name(ccx, path +
[path_name(@ccx.names("dtor"))], ty::node_id_to_type(ccx.tcx, id));
ccx.item_symbols.insert(id, s);
s
// Monomorphizing, so just make a symbol, don't add
// this to item_symbols
alt substs {
some(ss) {
let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, t);
mangle_exported_name(ccx, path +
[path_name(@ccx.names("dtor"))], mono_ty)
}
none {
ccx.sess.bug(#fmt("get_dtor_symbol: not monomorphizing and \
couldn't find a symbol for dtor %?", path));
}
}
}
}
}
@ -5289,7 +5327,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
T_ptr(type_of(ccx, class_ty))],
llvm::LLVMVoidType());
let s = get_dtor_symbol(ccx, *pt, dt.node.id);
let s = get_dtor_symbol(ccx, *pt, dt.node.id, none);
/* Make the declaration for the dtor */
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty);

View File

@ -21,12 +21,14 @@ import std::map::hashmap;
import ty_ctxt = middle::ty::ctxt;
type nominal_id = @{did: ast::def_id, tps: [ty::t]};
type nominal_id = @{did: ast::def_id, parent_id: option<ast::def_id>,
tps: [ty::t]};
fn mk_nominal_id(tcx: ty::ctxt, did: ast::def_id,
parent_id: option<ast::def_id>,
tps: [ty::t]) -> nominal_id {
let tps_norm = tps.map { |t| ty::normalize_ty(tcx, t) };
@{did: did, tps: tps_norm}
@{did: did, parent_id: parent_id, tps: tps_norm}
}
fn hash_nominal_id(&&ri: nominal_id) -> uint {
@ -233,7 +235,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
tk_enum { [s_variant_enum_t(ccx.tcx)] }
tk_newtype | tk_complex {
let mut s = [shape_enum], id;
let nom_id = mk_nominal_id(ccx.tcx, did, substs.tps);
let nom_id = mk_nominal_id(ccx.tcx, did, none, substs.tps);
alt ccx.shape_cx.tag_id_to_index.find(nom_id) {
none {
id = ccx.shape_cx.next_tag_id;
@ -335,7 +337,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
else { [shape_struct] };
let mut sub = [];
option::iter(m_dtor_did) {|dtor_did|
let ri = @{did: dtor_did, tps: tps};
let ri = @{did: dtor_did, parent_id: some(did), tps: tps};
let id = interner::intern(ccx.shape_cx.resources, ri);
add_u16(s, id as u16);
@ -362,7 +364,7 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> [u8] {
for substs.tps.each() {|t| assert !ty::type_has_params(t); }
let subt = ty::subst(ccx.tcx, substs, raw_subt);
let tps = substs.tps;
let ri = @{did: did, tps: tps};
let ri = @{did: did, parent_id: none, tps: tps};
let id = interner::intern(ccx.shape_cx.resources, ri);
let mut s = [shape_res];
@ -597,7 +599,8 @@ fn gen_resource_shapes(ccx: @crate_ctxt) -> ValueRef {
for uint::range(0u, len) {|i|
let ri = interner::get(ccx.shape_cx.resources, i);
for ri.tps.each() {|s| assert !ty::type_has_params(s); }
dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.tps)];
dtors += [trans::base::get_res_dtor(ccx, ri.did, ri.parent_id,
ri.tps)];
}
ret mk_global(ccx, "resource_shapes", C_struct(dtors), true);
}

View File

@ -8,6 +8,7 @@ import std::map::hashmap;
import ty::*;
export type_of;
export type_of_dtor;
export type_of_explicit_args;
export type_of_fn_from_ty;
export type_of_fn;
@ -251,3 +252,9 @@ fn llvm_type_name(cx: @crate_ctxt, t: ty::t) -> str {
);
}
fn type_of_dtor(ccx: @crate_ctxt, self_ty: ty::t) -> TypeRef {
T_fn([T_ptr(type_of(ccx, ty::mk_nil(ccx.tcx))),
T_ptr(type_of(ccx, self_ty))],
llvm::LLVMVoidType())
}

View File

@ -28,12 +28,12 @@ fn bound_region_to_str(cx: ctxt, br: bound_region) -> str {
}
fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> str {
alt cx.items.get(node_id) {
ast_map::node_block(blk) {
alt cx.items.find(node_id) {
some(ast_map::node_block(blk)) {
#fmt("<block at %s>",
codemap::span_to_str(blk.span, cx.sess.codemap))
}
ast_map::node_expr(expr) {
some(ast_map::node_expr(expr)) {
alt expr.node {
ast::expr_call(*) {
#fmt("<call at %s>",

View File

@ -1,3 +1,11 @@
S 2012-06-20 c891dec
macos-x86_64 cd7b3213a05e11dbf7440db016c9f7db16598501
macos-i386 eba609b4c815c415ca9485cac749c08ede5bf9ff
freebsd-x86_64 c93d3297bf68d12a55af04fecab5c1792394fcca
linux-x86_64 eb0e614c6f463fdbf3f40953ff122eb7cd829b85
linux-i386 6d858ef6915517135e633043115ab51d677010c5
winnt-i386 ffc26150a21aac3c5b023070c0e52d3c01b1881c
S 2012-06-19 de491ea
freebsd-x86_64 b5c1080df70136bb316286e1973fa2b5734c9a01
winnt-i386 fa1c7b2295dbde00269f859b8cb637a59a8deec4

View File

@ -1,6 +1,6 @@
/**
An implementation of the Graph500 Bread First Search problem in Rust.
An implementation of the Graph500 Breadth First Search problem in Rust.
*/

View File

@ -0,0 +1,9 @@
fn main() {
let x = some(~1);
alt x { //! NOTE loan of immutable local variable granted here
some(y) {
let _a <- x; //! ERROR moving out of immutable local variable prohibited due to outstanding loan
}
_ {}
}
}

View File

@ -0,0 +1,14 @@
//xfail-test
// this should be illegal but borrowck is not handling
// pattern bindings correctly right now
fn main() {
let x = some(~1);
alt x {
some(y) {
let b <- y;
}
_ {}
}
}

View File

@ -0,0 +1,7 @@
fn foo(x: *~int) -> ~int {
let y <- *x; //! ERROR dereference of unsafe pointer requires unsafe function or block
ret y;
}
fn main() {
}

View File

@ -0,0 +1,11 @@
// just make sure this compiles:
fn bar(x: *~int) -> ~int {
unsafe {
let y <- *x;
ret y;
}
}
fn main() {
}

View File

@ -0,0 +1,15 @@
fn main() {
class b {
let i: int;
fn do_stuff() -> int { ret 37; }
new(i:int) { self.i = i; }
}
// fn b(x:int) -> int { fail; }
let z = b(42);
assert(z.i == 42);
assert(z.do_stuff() == 37);
}