Merge remote-tracking branch 'mozilla/incoming'
Conflicts: src/rustc/middle/tstate/auxiliary.rs
This commit is contained in:
commit
3b4cfdeee2
28 changed files with 172 additions and 191 deletions
|
@ -421,9 +421,9 @@ else
|
|||
TSREQS := \
|
||||
$(foreach target,$(CFG_TARGET_TRIPLES), \
|
||||
$(SREQ3_T_$(target)_H_$(CFG_HOST_TRIPLE)))
|
||||
FUZZ := $(HBIN3_H_$(CFG_HOST_TRIPLE))/fuzzer$(X)
|
||||
CARGO := $(HBIN3_H_$(CFG_HOST_TRIPLE))/cargo$(X)
|
||||
RUSTDOC := $(HBIN3_H_$(CFG_HOST_TRIPLE))/rustdoc$(X)
|
||||
FUZZ := $(HBIN2_H_$(CFG_HOST_TRIPLE))/fuzzer$(X)
|
||||
CARGO := $(HBIN2_H_$(CFG_HOST_TRIPLE))/cargo$(X)
|
||||
RUSTDOC := $(HBIN2_H_$(CFG_HOST_TRIPLE))/rustdoc$(X)
|
||||
|
||||
all: rustc $(GENERATED) docs $(FUZZ) $(CARGO) $(RUSTDOC)
|
||||
|
||||
|
|
10
src/libcore/cmp.rs
Normal file
10
src/libcore/cmp.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#[doc="Interfaces used for comparison."]
|
||||
|
||||
iface ord {
|
||||
fn lt(&&other: self) -> bool;
|
||||
}
|
||||
|
||||
iface eq {
|
||||
fn eq(&&other: self) -> bool;
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ export extfmt;
|
|||
export tuple;
|
||||
export to_str;
|
||||
export dvec, dvec_iter;
|
||||
export cmp;
|
||||
|
||||
// NDM seems to be necessary for resolve to work
|
||||
export option_iter;
|
||||
|
@ -152,6 +153,7 @@ mod tuple;
|
|||
|
||||
// Ubiquitous-utility-type modules
|
||||
|
||||
mod cmp;
|
||||
mod either;
|
||||
mod iter;
|
||||
mod logging;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import T = inst::T;
|
||||
import cmp::{eq, ord};
|
||||
|
||||
export min_value, max_value;
|
||||
export min, max;
|
||||
|
@ -10,6 +11,7 @@ export range;
|
|||
export compl;
|
||||
export abs;
|
||||
export parse_buf, from_str, to_str, to_str_bytes, str;
|
||||
export ord, eq;
|
||||
|
||||
const min_value: T = -1 as T << (inst::bits - 1 as T);
|
||||
const max_value: T = min_value - 1 as T;
|
||||
|
@ -108,6 +110,18 @@ fn to_str_bytes<U>(n: T, radix: uint, f: fn([u8]/&) -> U) -> U {
|
|||
#[doc = "Convert to a string"]
|
||||
fn str(i: T) -> str { ret to_str(i, 10u); }
|
||||
|
||||
impl ord of ord for T {
|
||||
fn lt(&&other: T) -> bool {
|
||||
ret self < other;
|
||||
}
|
||||
}
|
||||
|
||||
impl eq of eq for T {
|
||||
fn eq(&&other: T) -> bool {
|
||||
ret self == other;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Has alignment issues on windows and 32-bit linux
|
||||
#[test]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import T = inst::T;
|
||||
import cmp::{eq, ord};
|
||||
|
||||
export min_value, max_value;
|
||||
export min, max;
|
||||
|
@ -10,6 +11,7 @@ export range;
|
|||
export compl;
|
||||
export to_str, to_str_bytes;
|
||||
export from_str, from_str_radix, str, parse_buf;
|
||||
export ord, eq;
|
||||
|
||||
const min_value: T = 0 as T;
|
||||
const max_value: T = 0 as T - 1 as T;
|
||||
|
@ -49,6 +51,18 @@ pure fn compl(i: T) -> T {
|
|||
max_value ^ i
|
||||
}
|
||||
|
||||
impl ord of ord for T {
|
||||
fn lt(&&other: T) -> bool {
|
||||
ret self < other;
|
||||
}
|
||||
}
|
||||
|
||||
impl eq of eq for T {
|
||||
fn eq(&&other: T) -> bool {
|
||||
ret self == other;
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "
|
||||
Parse a buffer of bytes
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#[doc = "Sorting methods"];
|
||||
import vec::len;
|
||||
import int::{eq, ord};
|
||||
|
||||
export le;
|
||||
export merge_sort;
|
||||
|
@ -141,7 +142,6 @@ fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
|
|||
qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
|
||||
}
|
||||
|
||||
// FIXME: This should take lt and eq types (#2348)
|
||||
#[doc = "
|
||||
Fancy quicksort. Sorts a mut vector in place.
|
||||
|
||||
|
@ -152,10 +152,9 @@ According to these slides this is the algorithm of choice for
|
|||
|
||||
This is an unstable sort.
|
||||
"]
|
||||
fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
|
||||
arr: [mut T]) {
|
||||
fn quick_sort3<T: copy ord eq>(arr: [mut T]) {
|
||||
if len::<T>(arr) == 0u { ret; }
|
||||
qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
|
||||
qsort3::<T>({ |x, y| x.lt(y) }, { |x, y| x.eq(y) }, arr, 0,
|
||||
(len::<T>(arr) as int) - 1);
|
||||
}
|
||||
|
||||
|
@ -163,11 +162,7 @@ fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
|
|||
mod test_qsort3 {
|
||||
fn check_sort(v1: [mut int], v2: [mut int]) {
|
||||
let len = vec::len::<int>(v1);
|
||||
fn lt(&&a: int, &&b: int) -> bool { ret a < b; }
|
||||
fn equal(&&a: int, &&b: int) -> bool { ret a == b; }
|
||||
let f1 = lt;
|
||||
let f2 = equal;
|
||||
quick_sort3::<int>(f1, f2, v1);
|
||||
quick_sort3::<int>(v1);
|
||||
let mut i = 0u;
|
||||
while i < len {
|
||||
log(debug, v2[i]);
|
||||
|
|
|
@ -86,11 +86,14 @@ impl codemap_handler of handler for handler_t {
|
|||
}
|
||||
fn has_errors() -> bool { self.err_count > 0u }
|
||||
fn abort_if_errors() {
|
||||
if self.err_count > 0u {
|
||||
let s = #fmt["aborting due to %u previous errors",
|
||||
self.err_count];
|
||||
self.fatal(s);
|
||||
let s;
|
||||
alt self.err_count {
|
||||
0u { ret; }
|
||||
1u { s = "aborting due to previous error"; }
|
||||
_ { s = #fmt["aborting due to %u previous errors",
|
||||
self.err_count]; }
|
||||
}
|
||||
self.fatal(s);
|
||||
}
|
||||
fn warn(msg: str) {
|
||||
self.emit(none, msg, warning);
|
||||
|
|
|
@ -194,7 +194,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
|||
bind middle::check_loop::check_crate(ty_cx, crate));
|
||||
time(time_passes, "alt checking",
|
||||
bind middle::check_alt::check_crate(ty_cx, crate));
|
||||
let (last_use_map, spill_map) =
|
||||
let last_use_map =
|
||||
time(time_passes, "liveness checking",
|
||||
bind middle::liveness::check_crate(ty_cx, method_map, crate));
|
||||
time(time_passes, "typestate checking",
|
||||
|
@ -216,7 +216,7 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
|
|||
let maps = {mutbl_map: mutbl_map, root_map: root_map,
|
||||
copy_map: copy_map, last_use_map: last_use_map,
|
||||
impl_map: impl_map, method_map: method_map,
|
||||
vtable_map: vtable_map, spill_map: spill_map};
|
||||
vtable_map: vtable_map};
|
||||
|
||||
let (llmod, link_meta) =
|
||||
time(time_passes, "translation",
|
||||
|
|
|
@ -15,7 +15,8 @@ import std::map::hashmap;
|
|||
import getopts::{opt_present};
|
||||
import rustc::driver::driver::*;
|
||||
import syntax::codemap;
|
||||
import rustc::driver::{diagnostic, session};
|
||||
import syntax::diagnostic;
|
||||
import rustc::driver::session;
|
||||
import rustc::middle::lint;
|
||||
import io::reader_util;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import syntax::{ast, ast_util};
|
|||
import syntax::attr;
|
||||
import middle::ty;
|
||||
import syntax::ast_map;
|
||||
import common::*;
|
||||
import tydecode::{parse_ty_data, parse_def_id, parse_bounds_data,
|
||||
parse_ident};
|
||||
import syntax::print::pprust;
|
||||
|
@ -15,6 +14,7 @@ import cmd=cstore::crate_metadata;
|
|||
import util::ppaux::ty_to_str;
|
||||
import ebml::deserializer;
|
||||
import syntax::diagnostic::span_handler;
|
||||
import common::*;
|
||||
|
||||
export class_dtor;
|
||||
export get_class_fields;
|
||||
|
|
|
@ -57,7 +57,6 @@ type maps = {
|
|||
impl_map: middle::resolve::impl_map,
|
||||
method_map: middle::typeck::method_map,
|
||||
vtable_map: middle::typeck::vtable_map,
|
||||
spill_map: middle::liveness::spill_map
|
||||
};
|
||||
|
||||
type decode_ctxt = @{
|
||||
|
@ -839,12 +838,6 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
option::iter(maps.spill_map.find(id)) {|_m|
|
||||
ebml_w.tag(c::tag_table_spill) {||
|
||||
ebml_w.id(id);
|
||||
}
|
||||
}
|
||||
|
||||
option::iter(maps.last_use_map.find(id)) {|m|
|
||||
ebml_w.tag(c::tag_table_last_use) {||
|
||||
ebml_w.id(id);
|
||||
|
@ -953,8 +946,6 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
|
|||
dcx.maps.mutbl_map.insert(id, ());
|
||||
} else if tag == (c::tag_table_copy as uint) {
|
||||
dcx.maps.copy_map.insert(id, ());
|
||||
} else if tag == (c::tag_table_spill as uint) {
|
||||
dcx.maps.spill_map.insert(id, ());
|
||||
} else {
|
||||
let val_doc = entry_doc[c::tag_table_val];
|
||||
let val_dsr = ebml::ebml_deserializer(val_doc);
|
||||
|
|
|
@ -57,7 +57,6 @@ import capture::{cap_move, cap_drop, cap_copy, cap_ref};
|
|||
|
||||
export check_crate;
|
||||
export last_use_map;
|
||||
export spill_map;
|
||||
|
||||
// Maps from an expr id to a list of variable ids for which this expr
|
||||
// is the last use. Typically, the expr is a path and the node id is
|
||||
|
@ -66,13 +65,6 @@ export spill_map;
|
|||
// list of closed over variables that can be moved into the closure.
|
||||
type last_use_map = hashmap<node_id, @dvec<node_id>>;
|
||||
|
||||
// A set of variable ids which must be spilled (stored on the stack).
|
||||
// We add in any variables or arguments where:
|
||||
// (1) the variables are moved;
|
||||
// (2) the address of the variable/argument is taken;
|
||||
// or (3) we find a last use (as they may be moved).
|
||||
type spill_map = hashmap<node_id, ()>;
|
||||
|
||||
enum variable = uint;
|
||||
enum live_node = uint;
|
||||
|
||||
|
@ -85,7 +77,7 @@ enum live_node_kind {
|
|||
|
||||
fn check_crate(tcx: ty::ctxt,
|
||||
method_map: typeck::method_map,
|
||||
crate: @crate) -> (last_use_map, spill_map) {
|
||||
crate: @crate) -> last_use_map {
|
||||
let visitor = visit::mk_vt(@{
|
||||
visit_fn: visit_fn,
|
||||
visit_local: visit_local,
|
||||
|
@ -94,12 +86,11 @@ fn check_crate(tcx: ty::ctxt,
|
|||
});
|
||||
|
||||
let last_use_map = int_hash();
|
||||
let spill_map = int_hash();
|
||||
let initial_maps = @ir_maps(tcx, method_map,
|
||||
last_use_map, spill_map);
|
||||
last_use_map);
|
||||
visit::visit_crate(*crate, initial_maps, visitor);
|
||||
tcx.sess.abort_if_errors();
|
||||
ret (last_use_map, spill_map);
|
||||
ret last_use_map;
|
||||
}
|
||||
|
||||
impl of to_str::to_str for live_node {
|
||||
|
@ -162,7 +153,6 @@ class ir_maps {
|
|||
let tcx: ty::ctxt;
|
||||
let method_map: typeck::method_map;
|
||||
let last_use_map: last_use_map;
|
||||
let spill_map: spill_map;
|
||||
|
||||
let mut num_live_nodes: uint;
|
||||
let mut num_vars: uint;
|
||||
|
@ -174,11 +164,10 @@ class ir_maps {
|
|||
let mut lnks: [live_node_kind];
|
||||
|
||||
new(tcx: ty::ctxt, method_map: typeck::method_map,
|
||||
last_use_map: last_use_map, spill_map: spill_map) {
|
||||
last_use_map: last_use_map) {
|
||||
self.tcx = tcx;
|
||||
self.method_map = method_map;
|
||||
self.last_use_map = last_use_map;
|
||||
self.spill_map = spill_map;
|
||||
|
||||
self.num_live_nodes = 0u;
|
||||
self.num_vars = 0u;
|
||||
|
@ -264,17 +253,6 @@ class ir_maps {
|
|||
self.lnks[*ln]
|
||||
}
|
||||
|
||||
fn add_spill(var: variable) {
|
||||
let vk = self.var_kinds[*var];
|
||||
alt vk {
|
||||
vk_local(id, _) | vk_arg(id, _, by_val) {
|
||||
#debug["adding spill for %?", vk];
|
||||
self.spill_map.insert(id, ());
|
||||
}
|
||||
vk_arg(*) | vk_field(_) | vk_self | vk_implicit_ret {}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_last_use(expr_id: node_id, var: variable) {
|
||||
let vk = self.var_kinds[*var];
|
||||
#debug["Node %d is a last use of variable %?", expr_id, vk];
|
||||
|
@ -308,7 +286,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
|
|||
|
||||
// swap in a new set of IR maps for this function body:
|
||||
let fn_maps = @ir_maps(self.tcx, self.method_map,
|
||||
self.last_use_map, self.spill_map);
|
||||
self.last_use_map);
|
||||
|
||||
#debug["creating fn_maps: %x", ptr::addr_of(*fn_maps) as uint];
|
||||
|
||||
|
@ -1407,11 +1385,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
|||
vt.visit_expr(f, self, vt);
|
||||
vec::iter2(args, targs) { |arg_expr, arg_ty|
|
||||
alt ty::resolved_mode(self.tcx, arg_ty.mode) {
|
||||
by_val | by_copy {
|
||||
vt.visit_expr(arg_expr, self, vt);
|
||||
}
|
||||
by_ref | by_mutbl_ref {
|
||||
self.spill_expr(arg_expr);
|
||||
by_val | by_copy | by_ref | by_mutbl_ref{
|
||||
vt.visit_expr(arg_expr, self, vt);
|
||||
}
|
||||
by_move {
|
||||
|
@ -1421,10 +1395,6 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
|||
}
|
||||
}
|
||||
|
||||
expr_addr_of(_, arg_expr) {
|
||||
self.spill_expr(arg_expr);
|
||||
}
|
||||
|
||||
// no correctness conditions related to liveness
|
||||
expr_if_check(*) | expr_if(*) | expr_alt(*) |
|
||||
expr_while(*) | expr_loop(*) |
|
||||
|
@ -1434,7 +1404,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
|||
expr_assert(*) | expr_check(*) | expr_copy(*) |
|
||||
expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||
expr_ret(*) | expr_break | expr_cont | expr_lit(_) |
|
||||
expr_block(*) | expr_swap(*) | expr_mac(*) {
|
||||
expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) {
|
||||
visit::visit_expr(expr, self, vt);
|
||||
}
|
||||
}
|
||||
|
@ -1501,10 +1471,7 @@ impl check_methods for @liveness {
|
|||
ln.to_str(), var.to_str()];
|
||||
|
||||
alt (*self).live_on_exit(ln, var) {
|
||||
none {
|
||||
// update spill map to include this variable, as it is moved:
|
||||
(*self.ir).add_spill(var);
|
||||
}
|
||||
none { }
|
||||
some(lnk) {
|
||||
self.report_illegal_move(span, lnk, var);
|
||||
}
|
||||
|
@ -1516,20 +1483,10 @@ impl check_methods for @liveness {
|
|||
some(_) {}
|
||||
none {
|
||||
(*self.ir).add_last_use(expr.id, var);
|
||||
|
||||
// update spill map to include this variable, as it may be moved:
|
||||
(*self.ir).add_spill(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spill_expr(expr: @expr) {
|
||||
alt (*self).variable_from_path(expr) {
|
||||
some(var) {(*self.ir).add_spill(var)}
|
||||
none {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_move_from_expr(expr: @expr, vt: vt<@liveness>) {
|
||||
#debug["check_move_from_expr(node %d: %s)",
|
||||
expr.id, expr_to_str(expr)];
|
||||
|
@ -1775,4 +1732,4 @@ impl check_methods for @liveness {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,12 @@ enum dest {
|
|||
ignore,
|
||||
}
|
||||
|
||||
// Heap selectors. Indicate which heap something should go on.
|
||||
enum heap {
|
||||
heap_shared,
|
||||
heap_exchange,
|
||||
}
|
||||
|
||||
fn dest_str(ccx: @crate_ctxt, d: dest) -> str {
|
||||
alt d {
|
||||
by_val(v) { #fmt["by_val(%s)", val_str(ccx.tn, *v)] }
|
||||
|
@ -341,75 +347,61 @@ fn opaque_box_body(bcx: block,
|
|||
PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t)))
|
||||
}
|
||||
|
||||
// trans_malloc_boxed_raw: expects an unboxed type and returns a pointer to
|
||||
// malloc_raw: expects an unboxed type and returns a pointer to
|
||||
// enough space for a box of that type. This includes a rust_opaque_box
|
||||
// header.
|
||||
fn malloc_boxed_raw(bcx: block, t: ty::t,
|
||||
&static_ti: option<@tydesc_info>) -> ValueRef {
|
||||
let _icx = bcx.insn_ctxt("trans_malloc_boxed_raw");
|
||||
fn malloc_raw(bcx: block, t: ty::t, heap: heap) -> ValueRef {
|
||||
let _icx = bcx.insn_ctxt("malloc_raw");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
|
||||
// wants.
|
||||
let box_ptr = ty::mk_imm_box(ccx.tcx, t);
|
||||
let llty = type_of(ccx, box_ptr);
|
||||
let (mk_fn, upcall) = alt heap {
|
||||
heap_shared { (ty::mk_imm_box, ccx.upcalls.malloc) }
|
||||
heap_exchange {
|
||||
(ty::mk_imm_uniq, ccx.upcalls.exchange_malloc )
|
||||
}
|
||||
};
|
||||
|
||||
// Get the tydesc for the body:
|
||||
let lltydesc = get_tydesc(ccx, t, static_ti);
|
||||
lazily_emit_all_tydesc_glue(ccx, copy static_ti);
|
||||
|
||||
// Allocate space:
|
||||
let rval = Call(bcx, ccx.upcalls.malloc, [lltydesc]);
|
||||
ret PointerCast(bcx, rval, llty);
|
||||
}
|
||||
|
||||
// trans_malloc_boxed: usefully wraps trans_malloc_box_raw; allocates a box,
|
||||
// initializes the reference count to 1, and pulls out the body and rc
|
||||
fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
||||
let _icx = bcx.insn_ctxt("trans_malloc_boxed");
|
||||
let mut ti = none;
|
||||
let box = malloc_boxed_raw(bcx, t, ti);
|
||||
let box_no_addrspace = non_gc_box_cast(
|
||||
bcx, box, ty::mk_imm_box(bcx.tcx(), t));
|
||||
let body = GEPi(bcx, box_no_addrspace, [0u, abi::box_field_body]);
|
||||
ret {box: box, body: body};
|
||||
}
|
||||
|
||||
fn malloc_unique_raw(bcx: block, t: ty::t) -> ValueRef {
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_box_raw");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
|
||||
// wants.
|
||||
let box_ptr = ty::mk_imm_uniq(ccx.tcx, t);
|
||||
let llty = type_of(ccx, box_ptr);
|
||||
// Grab the TypeRef type of box_ptr_ty.
|
||||
let box_ptr_ty = mk_fn(bcx.tcx(), t);
|
||||
let llty = type_of(ccx, box_ptr_ty);
|
||||
|
||||
// Get the tydesc for the body:
|
||||
let mut static_ti = none;
|
||||
let lltydesc = get_tydesc(ccx, t, static_ti);
|
||||
lazily_emit_all_tydesc_glue(ccx, static_ti);
|
||||
lazily_emit_all_tydesc_glue(ccx, copy static_ti);
|
||||
|
||||
// Allocate space:
|
||||
let rval = Call(bcx, ccx.upcalls.exchange_malloc, [lltydesc]);
|
||||
let rval = Call(bcx, upcall, [lltydesc]);
|
||||
ret PointerCast(bcx, rval, llty);
|
||||
}
|
||||
|
||||
fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_box");
|
||||
let box = malloc_unique_raw(bcx, t);
|
||||
let non_gc_box = non_gc_box_cast(bcx, box, ty::mk_imm_uniq(bcx.tcx(), t));
|
||||
// malloc_general: usefully wraps malloc_raw; allocates a box,
|
||||
// and pulls out the body
|
||||
fn malloc_general(bcx: block, t: ty::t, heap: heap) ->
|
||||
{box: ValueRef, body: ValueRef} {
|
||||
let _icx = bcx.insn_ctxt("malloc_general");
|
||||
let mk_ty = alt heap { heap_shared { ty::mk_imm_box }
|
||||
heap_exchange { ty::mk_imm_uniq } };
|
||||
let box = malloc_raw(bcx, t, heap);
|
||||
let non_gc_box = non_gc_box_cast(bcx, box, mk_ty(bcx.tcx(), t));
|
||||
let body = GEPi(bcx, non_gc_box, [0u, abi::box_field_body]);
|
||||
ret {box: box, body: body};
|
||||
}
|
||||
|
||||
fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
||||
malloc_general(bcx, t, heap_shared)
|
||||
}
|
||||
fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
||||
malloc_general(bcx, t, heap_exchange)
|
||||
}
|
||||
|
||||
fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef {
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_box_raw");
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_dyn_raw");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Grab the TypeRef type of box_ptr, because that's what trans_raw_malloc
|
||||
// wants.
|
||||
let box_ptr = ty::mk_imm_uniq(ccx.tcx, t);
|
||||
let llty = type_of(ccx, box_ptr);
|
||||
// Grab the TypeRef type of box_ptr_ty.
|
||||
let box_ptr_ty = ty::mk_imm_uniq(ccx.tcx, t);
|
||||
let llty = type_of(ccx, box_ptr_ty);
|
||||
|
||||
// Get the tydesc for the body:
|
||||
let mut static_ti = none;
|
||||
|
@ -423,7 +415,7 @@ fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef {
|
|||
|
||||
fn malloc_unique_dyn(bcx: block, t: ty::t, size: ValueRef
|
||||
) -> {box: ValueRef, body: ValueRef} {
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_box");
|
||||
let _icx = bcx.insn_ctxt("malloc_unique_dyn");
|
||||
let box = malloc_unique_dyn_raw(bcx, t, size);
|
||||
let body = GEPi(bcx, box, [0u, abi::box_field_body]);
|
||||
ret {box: box, body: body};
|
||||
|
@ -3749,6 +3741,8 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block {
|
|||
let ty = expr_ty(bcx, e);
|
||||
let lv = trans_lval(bcx, e);
|
||||
let last_use = (lv.kind == owned && last_use_map.contains_key(e.id));
|
||||
#debug["is last use (%s) = %b, %d", expr_to_str(e), last_use,
|
||||
lv.kind as int];
|
||||
lval_result_to_dps(lv, ty, last_use, dest)
|
||||
}
|
||||
|
||||
|
@ -4039,29 +4033,10 @@ fn init_local(bcx: block, local: @ast::local) -> block {
|
|||
let ty = node_id_type(bcx, local.node.id);
|
||||
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
|
||||
some(local_mem(v)) { v }
|
||||
some(_) { bcx.tcx().sess.span_bug(local.span,
|
||||
_ { bcx.tcx().sess.span_bug(local.span,
|
||||
"init_local: Someone forgot to document why it's\
|
||||
safe to assume local.node.init must be local_mem!");
|
||||
}
|
||||
// This is a local that is kept immediate
|
||||
none {
|
||||
let initexpr = alt local.node.init {
|
||||
some({expr, _}) { expr }
|
||||
none { bcx.tcx().sess.span_bug(local.span,
|
||||
"init_local: late-initialized var appears to \
|
||||
be an immediate -- possibly init_local was called \
|
||||
without calling alloc_local"); }
|
||||
};
|
||||
let mut {bcx, val, kind} = trans_temp_lval(bcx, initexpr);
|
||||
if kind != temporary {
|
||||
if kind == owned { val = Load(bcx, val); }
|
||||
let rs = take_ty_immediate(bcx, val, ty);
|
||||
bcx = rs.bcx; val = rs.val;
|
||||
add_clean_temp(bcx, val, ty);
|
||||
}
|
||||
bcx.fcx.lllocals.insert(local.node.pat.id, local_imm(val));
|
||||
ret bcx;
|
||||
}
|
||||
};
|
||||
|
||||
let mut bcx = bcx;
|
||||
|
@ -4341,17 +4316,6 @@ fn alloc_local(cx: block, local: @ast::local) -> block {
|
|||
ast::pat_ident(pth, none) { some(path_to_ident(pth)) }
|
||||
_ { none }
|
||||
};
|
||||
// Do not allocate space for locals that can be kept immediate.
|
||||
let ccx = cx.ccx();
|
||||
if option::is_some(simple_name) &&
|
||||
!ccx.maps.mutbl_map.contains_key(local.node.pat.id) &&
|
||||
!ccx.maps.spill_map.contains_key(local.node.pat.id) &&
|
||||
ty::type_is_immediate(t) {
|
||||
alt local.node.init {
|
||||
some({op: ast::init_assign, _}) { ret cx; }
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
let val = alloc_ty(cx, t);
|
||||
if cx.sess().opts.debuginfo {
|
||||
option::iter(simple_name) {|name|
|
||||
|
|
|
@ -175,11 +175,12 @@ fn allocate_cbox(bcx: block,
|
|||
let mut temp_cleanups = [];
|
||||
let (bcx, box) = alt ck {
|
||||
ty::ck_box {
|
||||
let box = malloc_boxed_raw(bcx, cdata_ty, ti);
|
||||
get_tydesc(ccx, cdata_ty, ti);
|
||||
let box = malloc_raw(bcx, cdata_ty, heap_shared);
|
||||
(bcx, box)
|
||||
}
|
||||
ty::ck_uniq {
|
||||
let box = malloc_unique_raw(bcx, cdata_ty);
|
||||
let box = malloc_raw(bcx, cdata_ty, heap_exchange);
|
||||
(bcx, box)
|
||||
}
|
||||
ty::ck_block {
|
||||
|
|
|
@ -13,10 +13,9 @@ import tstate::ann::{pre_and_post, pre_and_post_state, empty_ann, prestate,
|
|||
set_postcondition, ts_ann,
|
||||
clear_in_postcond,
|
||||
clear_in_poststate_};
|
||||
import tritv::*;
|
||||
import bitvectors::promises_;
|
||||
import driver::session::session;
|
||||
import dvec::{dvec, extensions};
|
||||
import tritv::{dont_care, tfalse, tritv_get, ttrue};
|
||||
|
||||
import syntax::print::pprust::{constr_args_to_str, lit_to_str};
|
||||
|
||||
|
@ -817,7 +816,7 @@ fn copy_in_poststate_two(fcx: fn_ctxt, src_post: poststate,
|
|||
// dest def_id
|
||||
let insts = find_instances(fcx, subst, val);
|
||||
for insts.each {|p|
|
||||
if promises_(p.from, src_post) {
|
||||
if bitvectors::promises_(p.from, src_post) {
|
||||
set_in_poststate_(p.to, target_post);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,19 @@ import std::map::hashmap;
|
|||
import driver::session;
|
||||
import session::session;
|
||||
import syntax::{ast, ast_map};
|
||||
import syntax::ast::*;
|
||||
import syntax::ast_util;
|
||||
import syntax::ast_util::{is_local, local_def, split_class_items,
|
||||
new_def_hash};
|
||||
import syntax::codemap::span;
|
||||
import metadata::csearch;
|
||||
import util::common::*;
|
||||
import util::ppaux::region_to_str;
|
||||
import util::ppaux::vstore_to_str;
|
||||
import util::ppaux::{ty_to_str, tys_to_str, ty_constr_to_str};
|
||||
import syntax::print::pprust::*;
|
||||
import middle::lint::{get_warning_level, vecs_not_implicitly_copyable,
|
||||
ignore};
|
||||
import syntax::ast::*;
|
||||
import syntax::print::pprust::*;
|
||||
|
||||
export ty_vid, region_vid, vid;
|
||||
export br_hashmap;
|
||||
export is_instantiable;
|
||||
|
@ -1678,11 +1678,8 @@ fn is_instantiable(cx: ctxt, r_ty: t) -> bool {
|
|||
|
||||
ty_class(did, substs) {
|
||||
vec::push(*seen, did);
|
||||
let r = vec::any(lookup_class_fields(cx, did)) {|f|
|
||||
let fty = ty::lookup_item_type(cx, f.id);
|
||||
let sty = subst(cx, substs, fty.ty);
|
||||
type_requires(cx, seen, r_ty, sty)
|
||||
};
|
||||
let r = vec::any(class_items_as_fields(cx, did, substs)) {|f|
|
||||
type_requires(cx, seen, r_ty, f.mt.ty)};
|
||||
vec::pop(*seen);
|
||||
r
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ an rptr (`&r.T`) use the region `r` that appears in the rptr.
|
|||
"];
|
||||
|
||||
import check::fn_ctxt;
|
||||
import rscope::*;
|
||||
import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
|
||||
import rscope::{in_binding_rscope, region_scope, type_rscope};
|
||||
|
||||
iface ast_conv {
|
||||
fn tcx() -> ty::ctxt;
|
||||
|
|
|
@ -71,7 +71,8 @@ import collect::{methods}; // ccx.to_ty()
|
|||
import method::{methods}; // methods for method::lookup
|
||||
import middle::ty::tys_in_fn_ty;
|
||||
import regionmanip::{replace_bound_regions_in_fn_ty, region_of};
|
||||
import rscope::*;
|
||||
import rscope::{anon_rscope, binding_rscope, empty_rscope, in_anon_rscope};
|
||||
import rscope::{in_binding_rscope, region_scope, type_rscope};
|
||||
|
||||
type fn_ctxt =
|
||||
// var_bindings, locals and next_var_id are shared
|
||||
|
@ -386,6 +387,12 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
|
|||
};
|
||||
// typecheck the members
|
||||
for members.each {|m| check_class_member(class_ccx, class_t, m); }
|
||||
// Check that there's at least one field
|
||||
let (fields,_) = split_class_items(members);
|
||||
if fields.len() < 1u {
|
||||
ccx.tcx.sess.span_err(it.span, "A class must have at least one \
|
||||
field");
|
||||
}
|
||||
// Check that the class is instantiable
|
||||
check_instantiable(ccx.tcx, it.span, it.id);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import std::map::hashmap;
|
||||
import middle::ty;
|
||||
import middle::ty::*;
|
||||
import middle::ty::{arg, bound_region, br_anon, br_named, canon_mode};
|
||||
import middle::ty::{ck_block, ck_box, ck_uniq, constr, ctxt, field, method};
|
||||
import middle::ty::{mt, re_bound, re_free, re_scope, re_var, region, t};
|
||||
import middle::ty::{ty_bool, ty_bot, ty_box, ty_class, ty_constr, ty_enum};
|
||||
import middle::ty::{ty_estr, ty_evec, ty_float, ty_fn, ty_iface, ty_int};
|
||||
import middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param};
|
||||
import middle::ty::{ty_ptr, ty_rec, ty_res, ty_rptr, ty_self, ty_str, ty_tup};
|
||||
import middle::ty::{ty_type, ty_uniq, ty_uint, ty_var, ty_var_integral};
|
||||
import middle::ty::{ty_vec, vid};
|
||||
import metadata::encoder;
|
||||
import syntax::codemap;
|
||||
import syntax::print::pprust;
|
||||
|
|
9
src/test/compile-fail/issue-2509-a.rs
Normal file
9
src/test/compile-fail/issue-2509-a.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
class c { //! ERROR A class must have at least one field
|
||||
new() { }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let a = c();
|
||||
let x = [a];
|
||||
let _y = x[0];
|
||||
}
|
|
@ -3,14 +3,15 @@
|
|||
// Test that a class with a non-copyable field can't be
|
||||
// copied
|
||||
class bar {
|
||||
new() {}
|
||||
let x: int;
|
||||
new(x:int) {self.x = x;}
|
||||
drop {}
|
||||
}
|
||||
|
||||
class foo {
|
||||
let i: int;
|
||||
let j: bar;
|
||||
new(i:int) { self.i = i; self.j = bar(); }
|
||||
new(i:int) { self.i = i; self.j = bar(5); }
|
||||
}
|
||||
|
||||
fn main() { let x <- foo(10); let y = x; log(error, x); }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
enum an_enum/& { }
|
||||
iface an_iface/& { }
|
||||
class a_class/& { new() { } }
|
||||
class a_class/& { let x:int; new(x:int) { self.x = x; } }
|
||||
|
||||
fn a_fn1(e: an_enum/&a) -> an_enum/&b {
|
||||
ret e; //! ERROR mismatched types: expected `an_enum/&b` but found `an_enum/&a`
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// error-pattern: copying a noncopyable value
|
||||
|
||||
class r {
|
||||
new(_i:int) {}
|
||||
let i:int;
|
||||
new(i:int) {self.i = i;}
|
||||
drop {}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ fn getbig_call_c_and_fail(i: int) {
|
|||
}
|
||||
|
||||
class and_then_get_big_again {
|
||||
new() {}
|
||||
let x:int;
|
||||
new(x:int) {self.x = x;}
|
||||
drop {
|
||||
fn getbig(i: int) {
|
||||
if i != 0 {
|
||||
|
@ -34,7 +35,7 @@ class and_then_get_big_again {
|
|||
|
||||
fn main() {
|
||||
task::spawn {||
|
||||
let r = and_then_get_big_again();
|
||||
let r = and_then_get_big_again(4);
|
||||
getbig_call_c_and_fail(10000);
|
||||
};
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
use std;
|
||||
|
||||
fn getbig_and_fail(&&i: int) {
|
||||
let _r = and_then_get_big_again();
|
||||
let _r = and_then_get_big_again(5);
|
||||
if i != 0 {
|
||||
getbig_and_fail(i - 1);
|
||||
} else {
|
||||
|
@ -14,7 +14,8 @@ fn getbig_and_fail(&&i: int) {
|
|||
}
|
||||
|
||||
class and_then_get_big_again {
|
||||
new() {}
|
||||
let x:int;
|
||||
new(x:int) {self.x = x;}
|
||||
drop {
|
||||
fn getbig(i: int) {
|
||||
if i != 0 {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use std;
|
||||
|
||||
fn getbig_and_fail(&&i: int) {
|
||||
let r = and_then_get_big_again();
|
||||
let r = and_then_get_big_again(5);
|
||||
if i != 0 {
|
||||
getbig_and_fail(i - 1);
|
||||
} else {
|
||||
|
@ -14,7 +14,8 @@ fn getbig_and_fail(&&i: int) {
|
|||
}
|
||||
|
||||
class and_then_get_big_again {
|
||||
new() {}
|
||||
let x:int;
|
||||
new(x:int) {self.x = x;}
|
||||
drop {}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
// error-pattern:whatever
|
||||
|
||||
class r {
|
||||
let x:int;
|
||||
// Setting the exit status after the runtime has already
|
||||
// failed has no effect and the process exits with the
|
||||
// runtime's exit code
|
||||
drop {
|
||||
os::set_exit_status(50);
|
||||
}
|
||||
new() {}
|
||||
new(x:int) {self.x = x;}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
log(error, "whatever");
|
||||
task::spawn {||
|
||||
let i = r();
|
||||
let i = r(5);
|
||||
};
|
||||
fail;
|
||||
}
|
|
@ -26,11 +26,13 @@ enum tg { bar, }
|
|||
|
||||
#[cfg(bogus)]
|
||||
class r {
|
||||
new(i:int) {}
|
||||
let i: int;
|
||||
new(i:int) { self.i = i; }
|
||||
}
|
||||
|
||||
class r {
|
||||
new(i:int) {}
|
||||
let i: int;
|
||||
new(i:int) { self.i = i; }
|
||||
}
|
||||
|
||||
#[cfg(bogus)]
|
||||
|
|
Loading…
Reference in a new issue