From 34d607f9c9e3c103fc7f98b4c6fa18ff71905bb6 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 25 Apr 2014 15:14:52 +1200 Subject: [PATCH 1/5] Use the slice repr for ~[T] --- src/libcollections/slice.rs | 60 ++++++++ src/libcore/mem.rs | 2 +- src/librustc/middle/trans/adt.rs | 4 +- src/librustc/middle/trans/base.rs | 19 ++- src/librustc/middle/trans/debuginfo.rs | 81 +---------- src/librustc/middle/trans/expr.rs | 12 +- src/librustc/middle/trans/glue.rs | 22 +-- src/librustc/middle/trans/reflect.rs | 13 +- src/librustc/middle/trans/tvec.rs | 185 ++++++++++--------------- src/librustc/middle/trans/type_.rs | 2 +- src/librustc/middle/trans/type_of.rs | 23 +-- src/librustc/middle/ty.rs | 3 +- src/librustc_back/abi.rs | 6 - src/libserialize/serialize.rs | 1 + src/libtime/lib.rs | 36 ++++- src/rt/rust_builtin.c | 42 +++++- 16 files changed, 247 insertions(+), 264 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index c137cc25b252a..bd8e18d1f3c1b 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -92,6 +92,8 @@ use core::iter::{range_step, MultiplicativeIterator}; use MutableSeq; use vec::Vec; +#[cfg(not(stage0))] +use raw::Slice; pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice}; pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems}; @@ -282,6 +284,64 @@ pub trait CloneableVector { impl<'a, T: Clone> CloneableVector for &'a [T] { /// Returns a copy of `v`. + #[cfg(not(stage0))] + fn to_owned(&self) -> ~[T] { + use num::CheckedMul; + use option::Expect; + + let len = self.len(); + + if len == 0 { + unsafe { + let slice: Slice = Slice{data: 0 as *T, len: 0}; + mem::transmute(slice) + } + } else { + let unit_size = mem::size_of::(); + let data_size = if unit_size == 0 { + len + } else { + let data_size = len.checked_mul(&unit_size); + data_size.expect("overflow in from_iter()") + }; + + unsafe { + // this should pass the real required alignment + let ret = allocate(data_size, 8) as *mut T; + + if unit_size > 0 { + // Be careful with the following loop. We want it to be optimized + // to a memcpy (or something similarly fast) when T is Copy. LLVM + // is easily confused, so any extra operations during the loop can + // prevent this optimization. + let mut i = 0; + let p = &mut (*ret) as *mut _ as *mut T; + try_finally( + &mut i, (), + |i, ()| while *i < len { + mem::move_val_init( + &mut(*p.offset(*i as int)), + self.unsafe_ref(*i).clone()); + *i += 1; + }, + |i| if *i < len { + // we must be failing, clean up after ourselves + for j in range(0, *i as int) { + ptr::read(&*p.offset(j)); + } + // FIXME: #13994 (should pass align and size here) + deallocate(ret as *mut u8, 0, 8); + }); + } + let slice: Slice = Slice{data: ret as *T, len: len}; + mem::transmute(slice) + } + } + } + + /// Returns a copy of `v`. + // NOTE: remove after snapshot + #[cfg(stage0)] #[inline] fn to_vec(&self) -> Vec { Vec::from_slice(*self) } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 4de81db1013c4..f0c39766ebb30 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -174,7 +174,7 @@ pub unsafe fn overwrite(dst: *mut T, src: T) { /// Deprecated, use `overwrite` instead #[inline] -#[deprecated = "use ptr::write"] +#[deprecated = "this function has been renamed to overwrite()"] pub unsafe fn move_val_init(dst: &mut T, src: T) { ptr::write(dst, src) } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index bf8caef2e9743..57f8f8d6692f0 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -305,8 +305,7 @@ impl Case { // Box could either be a thin or fat pointer depending on T ty::ty_uniq(t) => match ty::get(t).sty { - // Box<[T]>/Box might be FatPointer in a post DST world - ty::ty_vec(_, None) | ty::ty_str => continue, + ty::ty_vec(_, None) | return Some(FatPointer(i, slice_elt_base)), // Box is a pair of pointers: the actual object and a vtable ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)), @@ -326,7 +325,6 @@ impl Case { // Anything else is not a pointer _ => continue - } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 043636a32c0f6..7c2f251bd1685 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -195,6 +195,16 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::NoReturnAttribute as uint64_t) } } + // `~` pointer return values never alias because ownership is transferred + ty::ty_uniq(t) + => match ty::get(t).sty { + ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {} + _ => unsafe { + llvm::LLVMAddReturnAttribute(llfn, + lib::llvm::NoAliasAttribute as c_uint, + lib::llvm::NoReturnAttribute as uint64_t); + } + }, _ => {} } @@ -364,20 +374,19 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId { // a given type, but with a potentially dynamic size. pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>, - ptr_ty: ty::t, + llty_ptr: Type, + info_ty: ty::t, size: ValueRef, align: ValueRef) -> Result<'a> { let _icx = push_ctxt("malloc_raw_exchange"); - let ccx = bcx.ccx(); // Allocate space: let r = callee::trans_lang_call(bcx, - require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem), + require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem), [size, align], None); - let llty_ptr = type_of::type_of(ccx, ptr_ty); Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } @@ -731,8 +740,8 @@ pub fn iter_structural_ty<'r, } } ty::ty_vec(_, Some(n)) => { + let (base, len) = tvec::get_fixed_base_and_len(cx, av, n); let unit_ty = ty::sequence_element_type(cx.tcx(), t); - let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n); cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); } ty::ty_tup(ref args) => { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 88bdb00a7c983..db674b4028f24 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2718,81 +2718,6 @@ fn fixed_vec_metadata(cx: &CrateContext, return MetadataCreationResult::new(metadata, false); } -fn heap_vec_metadata(cx: &CrateContext, - vec_pointer_type: ty::t, - element_type: ty::t, - unique_type_id: UniqueTypeId, - span: Span) - -> MetadataCreationResult { - let element_type_metadata = type_metadata(cx, element_type, span); - let element_llvm_type = type_of::type_of(cx, element_type); - let (element_size, element_align) = size_and_align_of(cx, element_llvm_type); - - return_if_metadata_created_in_meantime!(cx, unique_type_id); - - let vecbox_llvm_type = Type::vec(cx, &element_llvm_type); - let vec_pointer_type_name = compute_debuginfo_type_name(cx, - vec_pointer_type, - true); - let vec_pointer_type_name = vec_pointer_type_name.as_slice(); - - let member_llvm_types = vecbox_llvm_type.field_types(); - - let int_type_metadata = type_metadata(cx, ty::mk_int(), span); - let array_type_metadata = unsafe { - llvm::LLVMDIBuilderCreateArrayType( - DIB(cx), - bytes_to_bits(element_size), - bytes_to_bits(element_align), - element_type_metadata, - create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)])) - }; - - let member_descriptions = [ - MemberDescription { - name: "fill".to_string(), - llvm_type: *member_llvm_types.get(0), - type_metadata: int_type_metadata, - offset: ComputedMemberOffset, - }, - MemberDescription { - name: "alloc".to_string(), - llvm_type: *member_llvm_types.get(1), - type_metadata: int_type_metadata, - offset: ComputedMemberOffset, - }, - MemberDescription { - name: "elements".to_string(), - llvm_type: *member_llvm_types.get(2), - type_metadata: array_type_metadata, - offset: ComputedMemberOffset, - } - ]; - - assert!(member_descriptions.len() == member_llvm_types.len()); - - let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, loc.file.name.as_slice()); - - let vec_box_unique_id = debug_context(cx).type_map - .borrow_mut() - .get_unique_type_id_of_heap_vec_box(cx, - element_type); - - let vecbox_metadata = composite_type_metadata(cx, - vecbox_llvm_type, - vec_pointer_type_name, - vec_box_unique_id, - member_descriptions, - UNKNOWN_SCOPE_METADATA, - file_metadata, - span); - - MetadataCreationResult::new(pointer_type_metadata(cx, - vec_pointer_type, - vecbox_metadata), false) -} - fn vec_slice_metadata(cx: &CrateContext, vec_type: ty::t, element_type: ty::t, @@ -2995,11 +2920,13 @@ fn type_metadata(cx: &CrateContext, ty::ty_uniq(pointee_type) => { match ty::get(pointee_type).sty { ty::ty_vec(ref mt, None) => { - heap_vec_metadata(cx, pointee_type, mt.ty, unique_type_id, usage_site_span) + let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span); + pointer_type_metadata(cx, t, vec_metadata) } ty::ty_str => { let i8_t = ty::mk_i8(); - heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span) + let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span); + pointer_type_metadata(cx, t, vec_metadata) } ty::ty_trait(..) => { MetadataCreationResult::new( diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 748274b1201e5..ead90dbe36b2c 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -395,8 +395,8 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, ast::ExprField(ref base, ident, _) => { trans_rec_field(bcx, &**base, ident.node) } - ast::ExprIndex(ref base, ref idx) => { - trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) + ast::ExprIndex(base, idx) => { + trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id)) } ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => { fcx.push_ast_cleanup_scope(contents.id); @@ -465,7 +465,7 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, } fn trans_index<'a>(bcx: &'a Block<'a>, - index_expr: &ast::Expr, + sp: codemap::Span, base: &ast::Expr, idx: &ast::Expr, method_call: MethodCall) @@ -1256,10 +1256,8 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>, let llty = type_of::type_of(bcx.ccx(), contents_ty); let size = llsize_of(bcx.ccx(), llty); let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint); - // We need to a make a pointer type because box_ty is ty_bot - // if content_ty is, e.g. box fail!(). - let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty); - let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align); + let llty_ptr = llty.ptr_to(); + let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align); // Unique boxes do not allocate for zero-size types. The standard library // may assume that `free` is never called on the pointer returned for // `Box`. diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 570f4d370425d..8faf27d1aa415 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -51,7 +51,7 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> { Some(expr::Ignore)).bcx } -fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, +pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, align: u64) -> &'a Block<'a> { let _icx = push_ctxt("trans_exchange_free"); let ccx = cx.ccx(); @@ -120,8 +120,8 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) -> &'a Block<'a> { // NB: v is an *alias* of type t here, not a direct value. let _icx = push_ctxt("drop_ty"); - let ccx = bcx.ccx(); if ty::type_needs_drop(bcx.tcx(), t) { + let ccx = bcx.ccx(); let glue = get_drop_glue(ccx, t); let glue_type = get_drop_glue_type(ccx, t); let ptr = if glue_type != t { @@ -277,23 +277,11 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' ty::ty_uniq(content_ty) => { match ty::get(content_ty).sty { ty::ty_vec(mt, None) => { - let llbox = Load(bcx, v0); - let not_null = IsNotNull(bcx, llbox); - with_cond(bcx, not_null, |bcx| { - let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty); - // FIXME: #13994: the old `Box<[T]>` will not support sized deallocation - trans_exchange_free(bcx, llbox, 0, 8) - }) + tvec::make_drop_glue_unboxed(bcx, v0, mt.ty) } ty::ty_str => { - let llbox = Load(bcx, v0); - let not_null = IsNotNull(bcx, llbox); - with_cond(bcx, not_null, |bcx| { - let unit_ty = ty::sequence_element_type(bcx.tcx(), t); - let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty); - // FIXME: #13994: the old `Box` will not support sized deallocation - trans_exchange_free(bcx, llbox, 0, 8) - }) + let unit_ty = ty::sequence_element_type(bcx.tcx(), t); + tvec::make_drop_glue_unboxed(bcx, v0, unit_ty) } ty::ty_trait(..) => { let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 2aff12c2b68c5..fcc1b82787685 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -164,6 +164,10 @@ impl<'a, 'b> Reflector<'a, 'b> { }); self.visit("box", extra.as_slice()) } + ty::ty_ptr(ref mt) => { + let extra = self.c_mt(mt); + self.visit("ptr", extra.as_slice()) + } ty::ty_uniq(typ) => { match ty::get(typ).sty { ty::ty_vec(ref mt, None) => { @@ -188,17 +192,12 @@ impl<'a, 'b> Reflector<'a, 'b> { } } } - ty::ty_ptr(ref mt) => { - let extra = self.c_mt(mt); - self.visit("ptr", extra.as_slice()) - } ty::ty_rptr(_, ref mt) => { match ty::get(mt.ty).sty { ty::ty_vec(ref mt, None) => { - let (name, extra) = ("slice".to_string(), Vec::new()); + let extra = Vec::new(); let extra = extra.append(self.c_mt(mt).as_slice()); - self.visit(format!("evec_{}", name).as_slice(), - extra.as_slice()) + self.visit("evec_slice", extra.as_slice()) } ty::ty_str => self.visit("estr_slice", &[]), ty::ty_trait(..) => { diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 1241a85e95cfc..7b8537b15c555 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -17,7 +17,6 @@ use middle::lang_items::StrDupUniqFnLangItem; use middle::trans::base::*; use middle::trans::base; use middle::trans::build::*; -use middle::trans::callee; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; use middle::trans::common::*; @@ -25,7 +24,7 @@ use middle::trans::datum::*; use middle::trans::expr::{Dest, Ignore, SaveIn}; use middle::trans::expr; use middle::trans::glue; -use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc}; +use middle::trans::machine::{nonzero_llsize_of, llsize_of_alloc}; use middle::trans::type_::Type; use middle::trans::type_of; use middle::ty; @@ -34,14 +33,14 @@ use util::ppaux::ty_to_string; use syntax::ast; use syntax::parse::token::InternedString; -pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef { - let _icx = push_ctxt("tvec::get_fill"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill])) +fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef { + let _icx = push_ctxt("tvec::get_lenl"); + Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len])) } -pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { +fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_dataptr"); - GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u]) + Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base])) } pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { @@ -56,13 +55,21 @@ pub fn make_drop_glue_unboxed<'a>( vptr: ValueRef, unit_ty: ty::t) -> &'a Block<'a> { - let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); - let tcx = bcx.tcx(); - if ty::type_needs_drop(tcx, unit_ty) { - let fill = get_fill(bcx, vptr); + let not_null = IsNotNull(bcx, vptr); + with_cond(bcx, not_null, |bcx| { + let tcx = bcx.tcx(); + let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); + + let len = get_len(bcx, vptr); let dataptr = get_dataptr(bcx, vptr); - iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty) - } else { bcx } + let bcx = if ty::type_needs_drop(tcx, unit_ty) { + iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty) + } else { + bcx + }; + + glue::trans_exchange_free(bcx, dataptr, 0, 8) + }) } pub struct VecTypes { @@ -112,12 +119,11 @@ pub fn trans_fixed_vstore<'a>( }; } -pub fn trans_slice_vstore<'a>( - bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, - dest: expr::Dest) - -> &'a Block<'a> { +pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, + vstore_expr: &ast::Expr, + content_expr: &ast::Expr, + dest: expr::Dest) + -> &'a Block<'a> { /*! * &[...] allocates memory on the stack and writes the values into it, * returning a slice (pair of ptr, len). &"..." is similar except that @@ -150,17 +156,16 @@ pub fn trans_slice_vstore<'a>( // Handle the &[...] case: let vt = vec_types_from_expr(bcx, vstore_expr); let count = elements_required(bcx, content_expr); - debug!("vt={}, count={:?}", vt.to_string(ccx), count); - + debug!(" vt={}, count={:?}", vt.to_str(ccx), count); let llcount = C_uint(ccx, count); - let llfixed; - if count == 0 { + + let llfixed = if count == 0 { // Just create a zero-sized alloca to preserve // the non-null invariant of the inner slice ptr - llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); + base::arrayalloca(bcx, vt.llunit_ty, llcount) } else { // Make a fixed-length backing array and allocate it on the stack. - llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); + let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); // Arrange for the backing array to be cleaned up. let fixed_ty = ty::mk_vec(bcx.tcx(), @@ -176,7 +181,9 @@ pub fn trans_slice_vstore<'a>( // Generate the content into the backing array. bcx = write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(llfixed)); - } + + llfixed + }; // Finally, create the slice pair itself. match dest { @@ -198,7 +205,7 @@ pub fn trans_lit_str<'a>( -> &'a Block<'a> { /*! * Literal strings translate to slices into static memory. This is - * different from trans_slice_vstore() above because it does need to copy + * different from trans_slice_vstore() above because it doesn't need to copy * the content anywhere. */ @@ -214,17 +221,14 @@ pub fn trans_lit_str<'a>( let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), str_lit, false); let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref()); - Store(bcx, llcstr, - GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - Store(bcx, llbytes, - GEPi(bcx, lldest, [0u, abi::slice_elt_len])); + Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); + Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); bcx } } } } - pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, vstore_expr: &ast::Expr, content_expr: &ast::Expr) @@ -238,74 +242,47 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, let fcx = bcx.fcx; let ccx = fcx.ccx; - // Handle "".to_string(). - match content_expr.node { - ast::ExprLit(lit) => { - match lit.node { - ast::LitStr(ref s, _) => { - let llptrval = C_cstr(ccx, (*s).clone(), false); - let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx)); - let llsizeval = C_uint(ccx, s.get().len()); - let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx())); - let lldestval = rvalue_scratch_datum(bcx, - typ, - ""); - let alloc_fn = langcall(bcx, - Some(lit.span), - "", - StrDupUniqFnLangItem); - let bcx = callee::trans_lang_call( - bcx, - alloc_fn, - [ llptrval, llsizeval ], - Some(expr::SaveIn(lldestval.val))).bcx; - return DatumBlock::new(bcx, lldestval).to_expr_datumblock(); - } - _ => {} - } - } - _ => {} - } - - let vec_ty = node_id_type(bcx, vstore_expr.id); - let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); + let vt = vec_types_from_expr(bcx, vstore_expr); let count = elements_required(bcx, content_expr); + debug!(" vt={}, count={:?}", vt.to_str(ccx), count); + let llcount = C_uint(ccx, count); + let vec_ty = node_id_type(bcx, vstore_expr.id); - let llunitty = type_of::type_of(ccx, vt.unit_ty); - let unit_sz = nonzero_llsize_of(ccx, llunitty); - + let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty)); let fill = Mul(bcx, C_uint(ccx, count), unit_sz); - let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) } - else { fill }; - - let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type)); - - // ~[T] is not going to be changed to support alignment, since it's obsolete. + let alloc = if count < 4u { + Mul(bcx, C_int(ccx, 4), unit_sz) + } else { + fill + }; + let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to(); let align = C_uint(ccx, 8); - let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align); - Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill])); - Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc])); + let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx, + llty_ptr, + vec_ty, + alloc, + align); // Create a temporary scope lest execution should fail while // constructing the vector. let temp_scope = fcx.push_custom_cleanup_scope(); - - // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder - let content_ty = vt.unit_ty; + // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, + // this is a placeholder fcx.schedule_free_value(cleanup::CustomScope(temp_scope), - val, cleanup::HeapExchange, content_ty); - - let dataptr = get_dataptr(bcx, val); + dataptr, cleanup::HeapExchange, vt.unit_ty); - debug!("alloc_uniq_vec() returned val={}, dataptr={}", - bcx.val_to_string(val), bcx.val_to_string(dataptr)); + debug!(" alloc_uniq_vec() returned dataptr={}, len={}", + bcx.val_to_str(dataptr), count); - let bcx = write_content(bcx, &vt, vstore_expr, - content_expr, SaveIn(dataptr)); + let bcx = write_content(bcx, &vt, vstore_expr, + content_expr, SaveIn(dataptr)); fcx.pop_custom_cleanup_scope(temp_scope); - immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock() + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); + Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + DatumBlock(bcx, scratch.to_expr_datum()) } pub fn write_content<'a>( @@ -451,21 +428,19 @@ pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint { } } -pub fn get_fixed_base_and_byte_len(bcx: &Block, - llval: ValueRef, - unit_ty: ty::t, - vec_length: uint) - -> (ValueRef, ValueRef) { +pub fn get_fixed_base_and_len(bcx: &Block, + llval: ValueRef, + vec_length: uint) + -> (ValueRef, ValueRef) { /*! * Converts a fixed-length vector into the slice pair. * The vector should be stored in `llval` which should be by ref. */ let ccx = bcx.ccx(); - let vt = vec_types(bcx, unit_ty); - let base = GEPi(bcx, llval, [0u, 0u]); - let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size); + let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]); + let len = C_uint(ccx, vec_length); (base, len) } @@ -488,23 +463,13 @@ pub fn get_base_and_len(bcx: &Block, let base = GEPi(bcx, llval, [0u, 0u]); (base, C_uint(ccx, n)) } - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_vec(_, None) | ty::ty_str => { - assert!(!type_is_immediate(bcx.ccx(), vec_ty)); let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); - let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); - (base, count) + let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + (base, len) } - _ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"), - }, - ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_vec(_, None) | ty::ty_str => { - assert!(type_is_immediate(bcx.ccx(), vec_ty)); - let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); - let body = Load(bcx, llval); - (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size)) - } - _ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"), + _ => ccx.sess().bug("unexpected type in get_base_and_len"), }, _ => ccx.sess().bug("unexpected type in get_base_and_len"), } @@ -576,13 +541,15 @@ pub fn iter_vec_raw<'r, bcx: &'b Block<'b>, data_ptr: ValueRef, unit_ty: ty::t, - fill: ValueRef, + len: ValueRef, f: iter_vec_block<'r,'b>) -> &'b Block<'b> { let _icx = push_ctxt("tvec::iter_vec_raw"); let fcx = bcx.fcx; let vt = vec_types(bcx, unit_ty); + let fill = Mul(bcx, len, vt.llunit_size); + if vt.llunit_alloc_size == 0 { // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) iter_vec_loop(bcx, data_ptr, &vt, fill, f) diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index e9d92e45f62d9..99850fb93866b 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -215,7 +215,7 @@ impl Type { pub fn vec(ccx: &CrateContext, ty: &Type) -> Type { Type::struct_(ccx, - [Type::int(ccx), Type::int(ccx), Type::array(ty, 0)], + [Type::array(ty, 0), Type::int(ccx)], false) } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 8a445fc48398e..bc17824ca328a 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -169,14 +169,8 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(..) | ty::ty_ptr(..) => Type::i8p(cx), - ty::ty_uniq(ty) => { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { match ty::get(ty).sty { - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => Type::i8p(cx), - } - } - ty::ty_rptr(_, mt) => { - match ty::get(mt.ty).sty { ty::ty_vec(_, None) | ty::ty_str => { Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) } @@ -283,17 +277,10 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(typ) => { Type::at_box(cx, type_of(cx, typ)).ptr_to() } - ty::ty_uniq(typ) => { - match ty::get(typ).sty { - ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(), - ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(), - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => type_of(cx, typ).ptr_to(), - } - } ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(), - ty::ty_rptr(_, ref mt) => { - match ty::get(mt.ty).sty { + + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + match ty::get(ty).sty { ty::ty_vec(mt, None) => { let p_ty = type_of(cx, mt.ty).ptr_to(); let u_ty = Type::uint_from_ty(cx, ast::TyU); @@ -304,7 +291,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { cx.tn.find_type("str_slice").unwrap() } ty::ty_trait(..) => Type::opaque_trait(cx), - _ => type_of(cx, mt.ty).ptr_to(), + _ => type_of(cx, ty).ptr_to(), } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dc463ffe5df68..c00c462afae30 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1816,8 +1816,7 @@ pub fn type_is_boxed(ty: t) -> bool { pub fn type_is_region_ptr(ty: t) -> bool { match get(ty).sty { ty_rptr(_, mt) => match get(mt.ty).sty { - // FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this - // odd behaviour for now. (But ~[] were unique. I have no idea why). + // DST pointers should not be treated like regular pointers. ty_vec(_, None) | ty_str | ty_trait(..) => false, _ => true }, diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs index c722beb43ae95..015331b8be00e 100644 --- a/src/librustc_back/abi.rs +++ b/src/librustc_back/abi.rs @@ -23,11 +23,5 @@ pub static fn_field_box: uint = 1u; pub static trt_field_vtable: uint = 0u; pub static trt_field_box: uint = 1u; -pub static vec_elt_fill: uint = 0u; - -pub static vec_elt_alloc: uint = 1u; - -pub static vec_elt_elems: uint = 2u; - pub static slice_elt_base: uint = 0u; pub static slice_elt_len: uint = 1u; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index bbaac7a96e9ee..a9cbacb07bee5 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -18,6 +18,7 @@ use std::path; use std::rc::Rc; use std::gc::{Gc, GC}; use std::cell::{Cell, RefCell}; +use std::strbuf::StrBuf; pub trait Encoder { // Primitive types: diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index d0b4c6b1e4c74..9a56dd5c0e47b 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -268,7 +268,19 @@ pub struct Tm { pub tm_nsec: i32, } +impl Tm { + pub fn tm_zone<'a>(&'a self) -> &'a str { + self.tm_zone.as_slice() + } +} + pub fn empty_tm() -> Tm { + // 64 is the max size of the timezone buffer allocated on windows + // in rust_localtime. In glibc the max timezone size is supposedly 3. + let mut zone = StrBuf::new(); + for _ in range(0, 64) { + zone.push_char(' ') + } Tm { tm_sec: 0_i32, tm_min: 0_i32, @@ -280,6 +292,7 @@ pub fn empty_tm() -> Tm { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, + tm_zone: zone, tm_nsec: 0_i32, } } @@ -760,6 +773,7 @@ pub fn strptime(s: &str, format: &str) -> Result { 'Z' => { if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") { tm.tm_gmtoff = 0_i32; + tm.tm_zone = "UTC".into_strbuf(); Ok(pos + 3u) } else { // It's odd, but to maintain compatibility with c's @@ -784,6 +798,7 @@ pub fn strptime(s: &str, format: &str) -> Result { let (v, pos) = item; if v == 0_i32 { tm.tm_gmtoff = 0_i32; + tm.tm_zone = "UTC".into_strbuf(); } Ok(pos) @@ -813,6 +828,7 @@ pub fn strptime(s: &str, format: &str) -> Result { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, + tm_zone: StrBuf::new(), tm_nsec: 0_i32, }; let mut pos = 0u; @@ -859,6 +875,7 @@ pub fn strptime(s: &str, format: &str) -> Result { tm_yday: tm.tm_yday, tm_isdst: tm.tm_isdst, tm_gmtoff: tm.tm_gmtoff, + tm_zone: tm.tm_zone.clone(), tm_nsec: tm.tm_nsec, }) } else { result } @@ -1060,7 +1077,7 @@ pub fn strftime(format: &str, tm: &Tm) -> String { 'w' => (tm.tm_wday as int).to_string(), 'Y' => (tm.tm_year as int + 1900).to_string(), 'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100), - 'Z' => "".to_string(), // FIXME(pcwalton): Implement this. + 'Z' => tm.tm_zone.as_slice().to_owned(), 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = num::abs(tm.tm_gmtoff) / 60_i32; @@ -1186,6 +1203,7 @@ mod tests { assert_eq!(utc.tm_yday, 43_i32); assert_eq!(utc.tm_isdst, 0_i32); assert_eq!(utc.tm_gmtoff, 0_i32); + assert_eq!(utc.tm_zone(), "UTC"); assert_eq!(utc.tm_nsec, 54321_i32); } @@ -1207,6 +1225,12 @@ mod tests { assert_eq!(local.tm_yday, 43_i32); assert_eq!(local.tm_isdst, 0_i32); assert_eq!(local.tm_gmtoff, -28800_i32); + + // FIXME (#2350): We should probably standardize on the timezone + // abbreviation. + let zone = local.tm_zone(); + assert!(zone == "PST" || zone == "Pacific Standard Time"); + assert_eq!(local.tm_nsec, 54321_i32); } @@ -1249,6 +1273,7 @@ mod tests { assert!(tm.tm_wday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); + assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 0_i32); } Err(_) => () @@ -1272,6 +1297,7 @@ mod tests { assert!(tm.tm_yday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); + assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 12340000_i32); } } @@ -1383,10 +1409,10 @@ mod tests { assert!(test("6", "%w")); assert!(test("2009", "%Y")); assert!(test("09", "%y")); - assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == - 0); - assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == - 0); + assert!(strptime("UTC", "%Z").unwrap().tm_zone() == "UTC"); + assert!(strptime("PST", "%Z").unwrap().tm_zone() == ""); + assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == 0); + assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == 0); assert!(test("%", "%%")); // Test for #7256 diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index ba20f2c6f27f9..1a9b1c1c818b7 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -127,6 +127,15 @@ rust_list_dir_wfd_fp_buf(void* wfd) { } #endif +typedef struct +{ + size_t fill; // in bytes; if zero, heapified + size_t alloc; // in bytes + uint8_t *data; +} rust_vec; + +typedef rust_vec rust_str_buf; + typedef struct { int32_t tm_sec; int32_t tm_min; @@ -138,6 +147,7 @@ typedef struct { int32_t tm_yday; int32_t tm_isdst; int32_t tm_gmtoff; + rust_str_buf tm_zone; int32_t tm_nsec; } rust_tm; @@ -154,10 +164,8 @@ void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) { out_tm->tm_isdst = in_tm->tm_isdst; } -void tm_to_rust_tm(struct tm* in_tm, - rust_tm* out_tm, - int32_t gmtoff, - int32_t nsec) { +void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff, + const char *zone, int32_t nsec) { out_tm->tm_sec = in_tm->tm_sec; out_tm->tm_min = in_tm->tm_min; out_tm->tm_hour = in_tm->tm_hour; @@ -169,6 +177,13 @@ void tm_to_rust_tm(struct tm* in_tm, out_tm->tm_isdst = in_tm->tm_isdst; out_tm->tm_gmtoff = gmtoff; out_tm->tm_nsec = nsec; + + if (zone != NULL) { + size_t size = strlen(zone); + assert(out_tm->tm_zone.alloc >= size); + memcpy(out_tm->tm_zone.data, zone, size); + out_tm->tm_zone.fill = size; + } } #if defined(__WIN32__) @@ -210,7 +225,7 @@ rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; GMTIME(&s, &tm); - tm_to_rust_tm(&tm, timeptr, 0, nsec); + tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec); } void @@ -219,13 +234,28 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; LOCALTIME(&s, &tm); + const char* zone = NULL; #if defined(__WIN32__) int32_t gmtoff = -timezone; + wchar_t wbuffer[64] = {0}; + char buffer[256] = {0}; + // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418), + // so time zone should be converted from UTF-16 string. + // Since wcsftime depends on setlocale() result, + // instead we convert it using MultiByteToWideChar. + if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) { + // ANSI -> UTF-16 + MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t)); + // UTF-16 -> UTF-8 + WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); + zone = buffer; + } #else int32_t gmtoff = tm.tm_gmtoff; + zone = tm.tm_zone; #endif - tm_to_rust_tm(&tm, timeptr, gmtoff, nsec); + tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec); } int64_t From 37a94b80f207e86017e54056ced2dc9674907ae3 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 4 Aug 2014 14:19:02 +0200 Subject: [PATCH 2/5] Use temp vars for implicit coercion to ^[T] --- src/libcollections/bitv.rs | 2 +- src/libcollections/dlist.rs | 3 +- src/libcollections/hash/mod.rs | 3 +- src/libcollections/hash/sip.rs | 4 +- src/libcollections/ringbuf.rs | 18 +- src/libcollections/slice.rs | 219 ++++++++++++------ src/libcollections/str.rs | 50 ++-- src/libcollections/treemap.rs | 3 +- src/libcore/option.rs | 10 +- src/libcore/str.rs | 19 +- src/libnum/bigint.rs | 6 +- src/librand/isaac.rs | 18 +- src/librand/lib.rs | 6 +- src/libserialize/hex.rs | 5 +- src/libstd/ascii.rs | 12 +- src/libstd/io/buffered.rs | 62 +++-- src/libstd/io/comm_adapters.rs | 13 +- src/libstd/io/mem.rs | 38 +-- src/libstd/io/result.rs | 3 +- src/libstd/os.rs | 3 +- src/libstd/path/mod.rs | 5 +- src/libstd/rand/mod.rs | 9 +- src/test/bench/core-map.rs | 3 +- src/test/bench/core-set.rs | 2 +- src/test/run-pass/byte-literals.rs | 22 +- src/test/run-pass/running-with-no-runtime.rs | 24 +- src/test/run-pass/syntax-extension-bytes.rs | 12 +- .../run-pass/typeck_type_placeholder_1.rs | 5 +- .../vec-matching-legal-tail-element-borrow.rs | 1 + src/test/run-pass/vec-matching.rs | 9 +- src/test/run-pass/vec-to_str.rs | 7 +- 31 files changed, 381 insertions(+), 215 deletions(-) diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 10ebcbcab36b8..d13767077c7ac 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -2557,7 +2557,7 @@ mod tests { } fn rng() -> rand::IsaacRng { - let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; rand::SeedableRng::from_seed(seed) } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 2899bdc0ddb6f..418bb147d204a 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -1088,7 +1088,8 @@ mod tests { let n = list_from([1i,2,3]); spawn(proc() { check_links(&n); - assert_eq!(&[&1,&2,&3], n.iter().collect::>().as_slice()); + let a: &[_] = &[&1,&2,&3]; + assert_eq!(a, n.iter().collect::>().as_slice()); }); } diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index b867bb7be0422..ef26452a52902 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -346,7 +346,8 @@ mod tests { assert_eq!(hasher.hash(&'a'), 97); assert_eq!(hasher.hash(&("a")), 97 + 0xFF); - assert_eq!(hasher.hash(& &[1u8, 2u8, 3u8]), 9); + let cs: &[u8] = &[1u8, 2u8, 3u8]; + assert_eq!(hasher.hash(& cs), 9); unsafe { let ptr: *const int = mem::transmute(5i); diff --git a/src/libcollections/hash/sip.rs b/src/libcollections/hash/sip.rs index 09a0edd9e3a9a..f3798e5f9e009 100644 --- a/src/libcollections/hash/sip.rs +++ b/src/libcollections/hash/sip.rs @@ -495,8 +495,8 @@ mod tests { assert!(s != t && t != u); assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - let v = (&[1u8], &[0u8, 0], &[0u8]); - let w = (&[1u8, 0, 0, 0], &[], &[]); + let v: (&[u8], &[u8], &[u8]) = (&[1u8], &[0u8, 0], &[0u8]); + let w: (&[u8], &[u8], &[u8]) = (&[1u8, 0, 0, 0], &[], &[]); assert!(v != w); assert!(hash(&v) != hash(&w)); diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index c9b60e67edde3..d2cfb510bc058 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -865,12 +865,18 @@ mod tests { for i in range(0i, 5) { d.push_back(i); } - assert_eq!(d.iter().collect::>().as_slice(), &[&0,&1,&2,&3,&4]); + { + let b: &[_] = &[&0,&1,&2,&3,&4]; + assert_eq!(d.iter().collect::>().as_slice(), b); + } for i in range(6i, 9) { d.push_front(i); } - assert_eq!(d.iter().collect::>().as_slice(), &[&8,&7,&6,&0,&1,&2,&3,&4]); + { + let b: &[_] = &[&8,&7,&6,&0,&1,&2,&3,&4]; + assert_eq!(d.iter().collect::>().as_slice(), b); + } let mut it = d.iter(); let mut len = d.len(); @@ -890,12 +896,16 @@ mod tests { for i in range(0i, 5) { d.push_back(i); } - assert_eq!(d.iter().rev().collect::>().as_slice(), &[&4,&3,&2,&1,&0]); + { + let b: &[_] = &[&4,&3,&2,&1,&0]; + assert_eq!(d.iter().rev().collect::>().as_slice(), b); + } for i in range(6i, 9) { d.push_front(i); } - assert_eq!(d.iter().rev().collect::>().as_slice(), &[&4,&3,&2,&1,&0,&6,&7,&8]); + let b: &[_] = &[&4,&3,&2,&1,&0,&6,&7,&8]; + assert_eq!(d.iter().rev().collect::>().as_slice(), b); } #[test] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index bd8e18d1f3c1b..55723ec10a062 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -698,11 +698,13 @@ pub trait MutableOrdSlice { /// # Example /// /// ```rust - /// let v = &mut [0i, 1, 2]; + /// let v: &mut [_] = &mut [0i, 1, 2]; /// v.next_permutation(); - /// assert_eq!(v, &mut [0i, 2, 1]); + /// let b: &mut [_] = &mut [0i, 2, 1]; + /// assert!(v == b); /// v.next_permutation(); - /// assert_eq!(v, &mut [1i, 0, 2]); + /// let b: &mut [_] = &mut [1i, 0, 2]; + /// assert!(v == b); /// ``` fn next_permutation(self) -> bool; @@ -714,11 +716,13 @@ pub trait MutableOrdSlice { /// # Example /// /// ```rust - /// let v = &mut [1i, 0, 2]; + /// let v: &mut [_] = &mut [1i, 0, 2]; /// v.prev_permutation(); - /// assert_eq!(v, &mut [0i, 2, 1]); + /// let b: &mut [_] = &mut [0i, 2, 1]; + /// assert!(v == b); /// v.prev_permutation(); - /// assert_eq!(v, &mut [0i, 1, 2]); + /// let b: &mut [_] = &mut [0i, 1, 2]; + /// assert!(v == b); /// ``` fn prev_permutation(self) -> bool; } @@ -905,9 +909,11 @@ mod tests { #[test] fn test_tail() { let mut a = vec![11i]; - assert_eq!(a.tail(), &[]); + let b: &[int] = &[]; + assert_eq!(a.tail(), b); a = vec![11i, 12]; - assert_eq!(a.tail(), &[12]); + let b: &[int] = &[12]; + assert_eq!(a.tail(), b); } #[test] @@ -920,9 +926,11 @@ mod tests { #[test] fn test_tailn() { let mut a = vec![11i, 12, 13]; - assert_eq!(a.tailn(0), &[11, 12, 13]); + let b: &[int] = &[11, 12, 13]; + assert_eq!(a.tailn(0), b); a = vec![11i, 12, 13]; - assert_eq!(a.tailn(2), &[13]); + let b: &[int] = &[13]; + assert_eq!(a.tailn(2), b); } #[test] @@ -935,9 +943,11 @@ mod tests { #[test] fn test_init() { let mut a = vec![11i]; - assert_eq!(a.init(), &[]); + let b: &[int] = &[]; + assert_eq!(a.init(), b); a = vec![11i, 12]; - assert_eq!(a.init(), &[11]); + let b: &[int] = &[11]; + assert_eq!(a.init(), b); } #[test] @@ -950,9 +960,11 @@ mod tests { #[test] fn test_initn() { let mut a = vec![11i, 12, 13]; - assert_eq!(a.as_slice().initn(0), &[11, 12, 13]); + let b: &[int] = &[11, 12, 13]; + assert_eq!(a.as_slice().initn(0), b); a = vec![11i, 12, 13]; - assert_eq!(a.as_slice().initn(2), &[11]); + let b: &[int] = &[11]; + assert_eq!(a.as_slice().initn(2), b); } #[test] @@ -1005,18 +1017,22 @@ mod tests { #[test] fn test_slice_from() { - let vec = &[1i, 2, 3, 4]; + let vec: &[int] = &[1, 2, 3, 4]; assert_eq!(vec.slice_from(0), vec); - assert_eq!(vec.slice_from(2), &[3, 4]); - assert_eq!(vec.slice_from(4), &[]); + let b: &[int] = &[3, 4]; + assert_eq!(vec.slice_from(2), b); + let b: &[int] = &[]; + assert_eq!(vec.slice_from(4), b); } #[test] fn test_slice_to() { - let vec = &[1i, 2, 3, 4]; + let vec: &[int] = &[1, 2, 3, 4]; assert_eq!(vec.slice_to(4), vec); - assert_eq!(vec.slice_to(2), &[1, 2]); - assert_eq!(vec.slice_to(0), &[]); + let b: &[int] = &[1, 2]; + assert_eq!(vec.slice_to(2), b); + let b: &[int] = &[]; + assert_eq!(vec.slice_to(0), b); } @@ -1270,23 +1286,30 @@ mod tests { let v : &mut[int] = &mut[1i, 2, 3, 4, 5]; assert!(v.prev_permutation() == false); assert!(v.next_permutation()); - assert_eq!(v, &mut[1, 2, 3, 5, 4]); + let b: &mut[int] = &mut[1, 2, 3, 5, 4]; + assert!(v == b); assert!(v.prev_permutation()); - assert_eq!(v, &mut[1, 2, 3, 4, 5]); + let b: &mut[int] = &mut[1, 2, 3, 4, 5]; + assert!(v == b); assert!(v.next_permutation()); assert!(v.next_permutation()); - assert_eq!(v, &mut[1, 2, 4, 3, 5]); + let b: &mut[int] = &mut[1, 2, 4, 3, 5]; + assert!(v == b); assert!(v.next_permutation()); - assert_eq!(v, &mut[1, 2, 4, 5, 3]); + let b: &mut[int] = &mut[1, 2, 4, 5, 3]; + assert!(v == b); let v : &mut[int] = &mut[1i, 0, 0, 0]; assert!(v.next_permutation() == false); assert!(v.prev_permutation()); - assert_eq!(v, &mut[0, 1, 0, 0]); + let b: &mut[int] = &mut[0, 1, 0, 0]; + assert!(v == b); assert!(v.prev_permutation()); - assert_eq!(v, &mut[0, 0, 1, 0]); + let b: &mut[int] = &mut[0, 0, 1, 0]; + assert!(v == b); assert!(v.prev_permutation()); - assert_eq!(v, &mut[0, 0, 0, 1]); + let b: &mut[int] = &mut[0, 0, 0, 1]; + assert!(v == b); assert!(v.prev_permutation() == false); } @@ -1294,27 +1317,31 @@ mod tests { fn test_lexicographic_permutations_empty_and_short() { let empty : &mut[int] = &mut[]; assert!(empty.next_permutation() == false); - assert_eq!(empty, &mut[]); + let b: &mut[int] = &mut[]; + assert!(empty == b); assert!(empty.prev_permutation() == false); - assert_eq!(empty, &mut[]); + assert!(empty == b); let one_elem : &mut[int] = &mut[4i]; assert!(one_elem.prev_permutation() == false); - assert_eq!(one_elem, &mut[4]); + let b: &mut[int] = &mut[4]; + assert!(one_elem == b); assert!(one_elem.next_permutation() == false); - assert_eq!(one_elem, &mut[4]); + assert!(one_elem == b); let two_elem : &mut[int] = &mut[1i, 2]; assert!(two_elem.prev_permutation() == false); - assert_eq!(two_elem, &mut[1, 2]); + let b : &mut[int] = &mut[1, 2]; + let c : &mut[int] = &mut[2, 1]; + assert!(two_elem == b); assert!(two_elem.next_permutation()); - assert_eq!(two_elem, &mut[2, 1]); + assert!(two_elem == c); assert!(two_elem.next_permutation() == false); - assert_eq!(two_elem, &mut[2, 1]); + assert!(two_elem == c); assert!(two_elem.prev_permutation()); - assert_eq!(two_elem, &mut[1, 2]); + assert!(two_elem == b); assert!(two_elem.prev_permutation() == false); - assert_eq!(two_elem, &mut[1, 2]); + assert!(two_elem == b); } #[test] @@ -1468,7 +1495,10 @@ mod tests { assert_eq!(v.concat_vec(), vec![]); assert_eq!([vec![1i], vec![2i,3i]].concat_vec(), vec![1, 2, 3]); - assert_eq!([&[1i], &[2i,3i]].concat_vec(), vec![1, 2, 3]); + let v: [&[int], ..2] = [&[1], &[2, 3]]; + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]); + let v: [&[int], ..3] = [&[1], &[2], &[3]]; + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]); } #[test] @@ -1478,8 +1508,10 @@ mod tests { assert_eq!([vec![1i], vec![2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]); assert_eq!([vec![1i], vec![2i], vec![3i]].connect_vec(&0), vec![1, 0, 2, 0, 3]); - assert_eq!([&[1i], &[2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]); - assert_eq!([&[1i], &[2i], &[3]].connect_vec(&0), vec![1, 0, 2, 0, 3]); + let v: [&[int], ..2] = [&[1], &[2, 3]]; + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]); + let v: [&[int], ..3] = [&[1], &[2], &[3]]; + assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]); } #[test] @@ -1637,11 +1669,16 @@ mod tests { #[test] fn test_total_ord() { - [1i, 2, 3, 4].cmp(& &[1, 2, 3]) == Greater; - [1i, 2, 3].cmp(& &[1, 2, 3, 4]) == Less; - [1i, 2, 3, 4].cmp(& &[1, 2, 3, 4]) == Equal; - [1i, 2, 3, 4, 5, 5, 5, 5].cmp(& &[1, 2, 3, 4, 5, 6]) == Less; - [2i, 2].cmp(& &[1, 2, 3, 4]) == Greater; + let c: &[int] = &[1, 2, 3]; + [1, 2, 3, 4].cmp(& c) == Greater; + let c: &[int] = &[1, 2, 3, 4]; + [1, 2, 3].cmp(& c) == Less; + let c: &[int] = &[1, 2, 3, 6]; + [1, 2, 3, 4].cmp(& c) == Equal; + let c: &[int] = &[1, 2, 3, 4, 5, 6]; + [1, 2, 3, 4, 5, 5, 5, 5].cmp(& c) == Less; + let c: &[int] = &[1, 2, 3, 4]; + [2, 2].cmp(& c) == Greater; } #[test] @@ -1765,74 +1802,95 @@ mod tests { fn test_splitator() { let xs = &[1i,2,3,4,5]; + let splits: &[&[int]] = &[&[1], &[3], &[5]]; assert_eq!(xs.split(|x| *x % 2 == 0).collect::>().as_slice(), - &[&[1], &[3], &[5]]); + splits); + let splits: &[&[int]] = &[&[], &[2,3,4,5]]; assert_eq!(xs.split(|x| *x == 1).collect::>().as_slice(), - &[&[], &[2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4], &[]]; assert_eq!(xs.split(|x| *x == 5).collect::>().as_slice(), - &[&[1,2,3,4], &[]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.split(|x| *x == 10).collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[], &[], &[]]; assert_eq!(xs.split(|_| true).collect::>().as_slice(), - &[&[], &[], &[], &[], &[], &[]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.split(|x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).collect::>().as_slice(), splits); } #[test] fn test_splitnator() { let xs = &[1i,2,3,4,5]; + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[1], &[3,4,5]]; assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>().as_slice(), - &[&[1], &[3,4,5]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[4,5]]; assert_eq!(xs.splitn(3, |_| true).collect::>().as_slice(), - &[&[], &[], &[], &[4,5]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.splitn(1, |x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.splitn(1, |x| *x == 5).collect::>().as_slice(), splits); } #[test] fn test_rsplitator() { let xs = &[1i,2,3,4,5]; + let splits: &[&[int]] = &[&[5], &[3], &[1]]; assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::>().as_slice(), - &[&[5], &[3], &[1]]); + splits); + let splits: &[&[int]] = &[&[2,3,4,5], &[]]; assert_eq!(xs.split(|x| *x == 1).rev().collect::>().as_slice(), - &[&[2,3,4,5], &[]]); + splits); + let splits: &[&[int]] = &[&[], &[1,2,3,4]]; assert_eq!(xs.split(|x| *x == 5).rev().collect::>().as_slice(), - &[&[], &[1,2,3,4]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.split(|x| *x == 10).rev().collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.split(|x| *x == 5).rev().collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).rev().collect::>().as_slice(), splits); } #[test] fn test_rsplitnator() { let xs = &[1,2,3,4,5]; + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[5], &[1,2,3]]; assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>().as_slice(), - &[&[5], &[1,2,3]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[1,2]]; assert_eq!(xs.rsplitn(3, |_| true).collect::>().as_slice(), - &[&[], &[], &[], &[1,2]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>().as_slice(), splits); } #[test] fn test_windowsator() { let v = &[1i,2,3,4]; - assert_eq!(v.windows(2).collect::>().as_slice(), &[&[1,2], &[2,3], &[3,4]]); - assert_eq!(v.windows(3).collect::>().as_slice(), &[&[1i,2,3], &[2,3,4]]); + let wins: &[&[int]] = &[&[1,2], &[2,3], &[3,4]]; + assert_eq!(v.windows(2).collect::>().as_slice(), wins); + let wins: &[&[int]] = &[&[1i,2,3], &[2,3,4]]; + assert_eq!(v.windows(3).collect::>().as_slice(), wins); assert!(v.windows(6).next().is_none()); } @@ -1847,16 +1905,23 @@ mod tests { fn test_chunksator() { let v = &[1i,2,3,4,5]; - assert_eq!(v.chunks(2).collect::>().as_slice(), &[&[1i,2], &[3,4], &[5]]); - assert_eq!(v.chunks(3).collect::>().as_slice(), &[&[1i,2,3], &[4,5]]); - assert_eq!(v.chunks(6).collect::>().as_slice(), &[&[1i,2,3,4,5]]); + let chunks: &[&[int]] = &[&[1i,2], &[3,4], &[5]]; + assert_eq!(v.chunks(2).collect::>().as_slice(), chunks); + let chunks: &[&[int]] = &[&[1i,2,3], &[4,5]]; + assert_eq!(v.chunks(3).collect::>().as_slice(), chunks); + let chunks: &[&[int]] = &[&[1i,2,3,4,5]]; + assert_eq!(v.chunks(6).collect::>().as_slice(), chunks); - assert_eq!(v.chunks(2).rev().collect::>().as_slice(), &[&[5i], &[3,4], &[1,2]]); + let chunks: &[&[int]] = &[&[5i], &[3,4], &[1,2]]; + assert_eq!(v.chunks(2).rev().collect::>().as_slice(), chunks); let mut it = v.chunks(2); assert_eq!(it.indexable(), 3); - assert_eq!(it.idx(0).unwrap(), &[1,2]); - assert_eq!(it.idx(1).unwrap(), &[3,4]); - assert_eq!(it.idx(2).unwrap(), &[5]); + let chunk: &[int] = &[1,2]; + assert_eq!(it.idx(0).unwrap(), chunk); + let chunk: &[int] = &[3,4]; + assert_eq!(it.idx(1).unwrap(), chunk); + let chunk: &[int] = &[5]; + assert_eq!(it.idx(2).unwrap(), chunk); assert_eq!(it.idx(3), None); } @@ -1924,10 +1989,12 @@ mod tests { let empty_mut: &mut [int] = &mut[]; test_show_vec!(empty_mut, "[]".to_string()); - test_show_vec!(&mut[1i], "[1]".to_string()); - test_show_vec!(&mut[1i, 2, 3], "[1, 2, 3]".to_string()); - test_show_vec!(&mut[&mut[], &mut[1u], &mut[1u, 1u]], - "[[], [1], [1, 1]]".to_string()); + let v: &mut[int] = &mut[1]; + test_show_vec!(v, "[1]".to_string()); + let v: &mut[int] = &mut[1, 2, 3]; + test_show_vec!(v, "[1, 2, 3]".to_string()); + let v: &mut [&mut[uint]] = &mut[&mut[], &mut[1u], &mut[1u, 1u]]; + test_show_vec!(v, "[[], [1], [1, 1]]".to_string()); } #[test] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 9120b3889e77f..1145e1f357319 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1265,12 +1265,14 @@ mod tests { fn test_trim_left_chars() { let v: &[char] = &[]; assert_eq!(" *** foo *** ".trim_left_chars(v), " *** foo *** "); - assert_eq!(" *** foo *** ".trim_left_chars(&['*', ' ']), "foo *** "); - assert_eq!(" *** *** ".trim_left_chars(&['*', ' ']), ""); - assert_eq!("foo *** ".trim_left_chars(&['*', ' ']), "foo *** "); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_left_chars(chars), "foo *** "); + assert_eq!(" *** *** ".trim_left_chars(chars), ""); + assert_eq!("foo *** ".trim_left_chars(chars), "foo *** "); assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11"); - assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_left_chars(chars), "foo1bar12"); assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123"); } @@ -1278,12 +1280,14 @@ mod tests { fn test_trim_right_chars() { let v: &[char] = &[]; assert_eq!(" *** foo *** ".trim_right_chars(v), " *** foo *** "); - assert_eq!(" *** foo *** ".trim_right_chars(&['*', ' ']), " *** foo"); - assert_eq!(" *** *** ".trim_right_chars(&['*', ' ']), ""); - assert_eq!(" *** foo".trim_right_chars(&['*', ' ']), " *** foo"); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_right_chars(chars), " *** foo"); + assert_eq!(" *** *** ".trim_right_chars(chars), ""); + assert_eq!(" *** foo".trim_right_chars(chars), " *** foo"); assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar"); - assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_right_chars(chars), "12foo1bar"); assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar"); } @@ -1291,12 +1295,14 @@ mod tests { fn test_trim_chars() { let v: &[char] = &[]; assert_eq!(" *** foo *** ".trim_chars(v), " *** foo *** "); - assert_eq!(" *** foo *** ".trim_chars(&['*', ' ']), "foo"); - assert_eq!(" *** *** ".trim_chars(&['*', ' ']), ""); - assert_eq!("foo".trim_chars(&['*', ' ']), "foo"); + let chars: &[char] = &['*', ' ']; + assert_eq!(" *** foo *** ".trim_chars(chars), "foo"); + assert_eq!(" *** *** ".trim_chars(chars), ""); + assert_eq!("foo".trim_chars(chars), "foo"); assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar"); - assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar"); + let chars: &[char] = &['1', '2']; + assert_eq!("12foo1bar12".trim_chars(chars), "foo1bar"); assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar"); } @@ -1443,7 +1449,8 @@ mod tests { 184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97, 109 ]; - assert_eq!("".as_bytes(), &[]); + let b: &[u8] = &[]; + assert_eq!("".as_bytes(), b); assert_eq!("abc".as_bytes(), b"abc"); assert_eq!("ศไทย中华Việt Nam".as_bytes(), v.as_slice()); } @@ -1542,19 +1549,23 @@ mod tests { #[test] fn test_truncate_utf16_at_nul() { let v = []; - assert_eq!(truncate_utf16_at_nul(v), &[]); + let b: &[u16] = &[]; + assert_eq!(truncate_utf16_at_nul(v), b); let v = [0, 2, 3]; - assert_eq!(truncate_utf16_at_nul(v), &[]); + assert_eq!(truncate_utf16_at_nul(v), b); let v = [1, 0, 3]; - assert_eq!(truncate_utf16_at_nul(v), &[1]); + let b: &[u16] = &[1]; + assert_eq!(truncate_utf16_at_nul(v), b); let v = [1, 2, 0]; - assert_eq!(truncate_utf16_at_nul(v), &[1, 2]); + let b: &[u16] = &[1, 2]; + assert_eq!(truncate_utf16_at_nul(v), b); let v = [1, 2, 3]; - assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]); + let b: &[u16] = &[1, 2, 3]; + assert_eq!(truncate_utf16_at_nul(v), b); } #[test] @@ -2494,7 +2505,8 @@ mod bench { let s = "Mary had a little lamb, Little lamb, little-lamb."; let len = s.split(' ').count(); - b.iter(|| assert_eq!(s.split(&[' ']).count(), len)); + let c: &[char] = &[' ']; + b.iter(|| assert_eq!(s.split(c).count(), len)); } #[bench] diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 4ab33b05aaa63..8e5ffbd168660 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -1853,7 +1853,8 @@ mod test_treemap { check_equal(ctrl.as_slice(), &map); assert!(map.find(&5).is_none()); - let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(&[42]); + let seed: &[_] = &[42]; + let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); for _ in range(0u, 3) { for _ in range(0u, 90) { diff --git a/src/libcore/option.rs b/src/libcore/option.rs index bf8a92a4f950a..47df8ae68cdd2 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -221,8 +221,14 @@ impl Option { #[inline] pub fn as_mut_slice<'r>(&'r mut self) -> &'r mut [T] { match *self { - Some(ref mut x) => slice::mut_ref_slice(x), - None => &mut [] + Some(ref mut x) => { + let result: &mut [T] = slice::mut_ref_slice(x); + result + } + None => { + let result: &mut [T] = &mut []; + result + } } } diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 66564b1bf07dc..5cbeda94d0f86 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -918,8 +918,8 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> Utf16Items<'a> { /// /// // "ab\0d" /// v[2] = 0; -/// assert_eq!(str::truncate_utf16_at_nul(v), -/// &['a' as u16, 'b' as u16]); +/// let b: &[_] = &['a' as u16, 'b' as u16]; +/// assert_eq!(str::truncate_utf16_at_nul(v), b); /// ``` pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { match v.iter().position(|c| *c == 0) { @@ -1439,7 +1439,8 @@ pub trait StrSlice<'a> { /// /// ```rust /// assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar") - /// assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar") + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_chars(x), "foo1bar") /// assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar") /// ``` fn trim_chars(&self, to_trim: C) -> &'a str; @@ -1454,7 +1455,8 @@ pub trait StrSlice<'a> { /// /// ```rust /// assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11") - /// assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12") + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_left_chars(x), "foo1bar12") /// assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123") /// ``` fn trim_left_chars(&self, to_trim: C) -> &'a str; @@ -1469,7 +1471,8 @@ pub trait StrSlice<'a> { /// /// ```rust /// assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar") - /// assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar") + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_right_chars(x), "12foo1bar") /// assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar") /// ``` fn trim_right_chars(&self, to_trim: C) -> &'a str; @@ -1620,7 +1623,8 @@ pub trait StrSlice<'a> { /// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5)); /// /// // neither are found - /// assert_eq!(s.find(&['1', '2']), None); + /// let x: &[_] = &['1', '2']; + /// assert_eq!(s.find(x), None); /// ``` fn find(&self, search: C) -> Option; @@ -1644,7 +1648,8 @@ pub trait StrSlice<'a> { /// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12)); /// /// // searches for an occurrence of either `1` or `2`, but neither are found - /// assert_eq!(s.rfind(&['1', '2']), None); + /// let x: &[_] = &['1', '2']; + /// assert_eq!(s.rfind(x), None); /// ``` fn rfind(&self, search: C) -> Option; diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 48fc9fb4a38c6..ba45d2b2e73ff 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -1449,8 +1449,8 @@ mod biguint_tests { #[test] fn test_cmp() { - let data: Vec = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ] - .iter().map(|v| BigUint::from_slice(*v)).collect(); + let data: [&[_], ..7] = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ]; + let data: Vec = data.iter().map(|v| BigUint::from_slice(*v)).collect(); for (i, ni) in data.iter().enumerate() { for (j0, nj) in data.slice(i, data.len()).iter().enumerate() { let j = j0 + i; @@ -2311,7 +2311,7 @@ mod bigint_tests { #[test] fn test_cmp() { - let vs = [ &[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1] ]; + let vs: [&[BigDigit], ..4] = [ &[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1] ]; let mut nums = Vec::new(); for s in vs.iter().rev() { nums.push(BigInt::from_slice(Minus, *s)); diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 2fbfa6d6e85a0..0f7cda42a8a0c 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -13,7 +13,6 @@ use core::prelude::*; use core::iter::{range_step, Repeat}; use core::slice::raw; -use core::mem; use {Rng, SeedableRng, Rand}; @@ -46,6 +45,7 @@ static EMPTY: IsaacRng = IsaacRng { }; impl IsaacRng { + /// Create an ISAAC random number generator using the default /// fixed seed. pub fn new_unseeded() -> IsaacRng { @@ -225,7 +225,7 @@ impl Rand for IsaacRng { let ptr = ret.rsl.as_mut_ptr(); raw::mut_buf_as_slice(ptr as *mut u8, - mem::size_of_val(&ret.rsl), |slice| { + (RAND_SIZE*4) as uint, |slice| { other.fill_bytes(slice); }) } @@ -456,7 +456,7 @@ impl Rand for Isaac64Rng { let ptr = ret.rsl.as_mut_ptr(); raw::mut_buf_as_slice(ptr as *mut u8, - mem::size_of_val(&ret.rsl), |slice| { + (RAND_SIZE_64*8) as uint, |slice| { other.fill_bytes(slice); }) } @@ -497,7 +497,7 @@ mod test { #[test] fn test_rng_32_seeded() { - let seed = &[1, 23, 456, 7890, 12345]; + let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: IsaacRng = SeedableRng::from_seed(seed); let mut rb: IsaacRng = SeedableRng::from_seed(seed); assert!(order::equals(ra.gen_ascii_chars().take(100), @@ -505,7 +505,7 @@ mod test { } #[test] fn test_rng_64_seeded() { - let seed = &[1, 23, 456, 7890, 12345]; + let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); assert!(order::equals(ra.gen_ascii_chars().take(100), @@ -537,7 +537,7 @@ mod test { #[test] fn test_rng_32_true_values() { - let seed = &[1, 23, 456, 7890, 12345]; + let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: IsaacRng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector let v = Vec::from_fn(10, |_| ra.next_u32()); @@ -545,7 +545,7 @@ mod test { vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709, 4203127393, 264982119, 2765226902, 2737944514, 3900253796)); - let seed = &[12345, 67890, 54321, 9876]; + let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: IsaacRng = SeedableRng::from_seed(seed); // skip forward to the 10000th number for _ in range(0u, 10000) { rb.next_u32(); } @@ -557,7 +557,7 @@ mod test { } #[test] fn test_rng_64_true_values() { - let seed = &[1, 23, 456, 7890, 12345]; + let seed: &[_] = &[1, 23, 456, 7890, 12345]; let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector let v = Vec::from_fn(10, |_| ra.next_u64()); @@ -567,7 +567,7 @@ mod test { 4469761996653280935, 15552757044682284409, 6860251611068737823, 13722198873481261842)); - let seed = &[12345, 67890, 54321, 9876]; + let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); // skip forward to the 10000th number for _ in range(0u, 10000) { rb.next_u64(); } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 9c33b713e4a6b..5f460225d39a9 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -309,7 +309,8 @@ pub trait SeedableRng: Rng { /// ```rust /// use std::rand::{Rng, SeedableRng, StdRng}; /// - /// let mut rng: StdRng = SeedableRng::from_seed(&[1, 2, 3, 4]); + /// let seed: &[_] = &[1, 2, 3, 4]; + /// let mut rng: StdRng = SeedableRng::from_seed(seed); /// println!("{}", rng.gen::()); /// rng.reseed([5, 6, 7, 8]); /// println!("{}", rng.gen::()); @@ -323,7 +324,8 @@ pub trait SeedableRng: Rng { /// ```rust /// use std::rand::{Rng, SeedableRng, StdRng}; /// - /// let mut rng: StdRng = SeedableRng::from_seed(&[1, 2, 3, 4]); + /// let seed: &[_] = &[1, 2, 3, 4]; + /// let mut rng: StdRng = SeedableRng::from_seed(seed); /// println!("{}", rng.gen::()); /// ``` fn from_seed(seed: Seed) -> Self; diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index f33ecb5f19bc8..1d2fcc8b77b15 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -183,16 +183,17 @@ mod tests { #[test] pub fn test_from_hex_all_bytes() { for i in range(0u, 256) { + let ii: &[u8] = &[i as u8]; assert_eq!(format!("{:02x}", i as uint).as_slice() .from_hex() .unwrap() .as_slice(), - &[i as u8]); + ii); assert_eq!(format!("{:02X}", i as uint).as_slice() .from_hex() .unwrap() .as_slice(), - &[i as u8]); + ii); } } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b31baa88e0c84..f7b23163dfe48 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -609,11 +609,12 @@ mod tests { #[test] fn test_ascii_vec() { let test = &[40u8, 32u8, 59u8]; - assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59])); - assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59])); + let b: &[_] = v2ascii!([40, 32, 59]); + assert_eq!(test.to_ascii(), b); + assert_eq!("( ;".to_ascii(), b); let v = vec![40u8, 32u8, 59u8]; - assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59])); - assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59])); + assert_eq!(v.as_slice().to_ascii(), b); + assert_eq!("( ;".to_string().as_slice().to_ascii(), b); assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string()); assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string()); @@ -688,13 +689,12 @@ mod tests { assert_eq!((test1).to_ascii_opt(), None); let v = [40u8, 32u8, 59u8]; - let v2 = v2ascii!(&[40, 32, 59]); + let v2: &[_] = v2ascii!(&[40, 32, 59]); assert_eq!(v.to_ascii_opt(), Some(v2)); let v = [127u8, 128u8, 255u8]; assert_eq!(v.to_ascii_opt(), None); let v = "( ;"; - let v2 = v2ascii!(&[40, 32, 59]); assert_eq!(v.to_ascii_opt(), Some(v2)); assert_eq!("zoä华".to_ascii_opt(), None); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a9b0b33c59ad9..1d638e498d449 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -415,21 +415,25 @@ mod test { let mut buf = [0, 0, 0]; let nread = reader.read(buf); assert_eq!(Ok(2), nread); - assert_eq!(buf.as_slice(), &[0, 1, 0]); + let b: &[_] = &[0, 1, 0]; + assert_eq!(buf.as_slice(), b); let mut buf = [0]; let nread = reader.read(buf); assert_eq!(Ok(1), nread); - assert_eq!(buf.as_slice(), &[2]); + let b: &[_] = &[2]; + assert_eq!(buf.as_slice(), b); let mut buf = [0, 0, 0]; let nread = reader.read(buf); assert_eq!(Ok(1), nread); - assert_eq!(buf.as_slice(), &[3, 0, 0]); + let b: &[_] = &[3, 0, 0]; + assert_eq!(buf.as_slice(), b); let nread = reader.read(buf); assert_eq!(Ok(1), nread); - assert_eq!(buf.as_slice(), &[4, 0, 0]); + let b: &[_] = &[4, 0, 0]; + assert_eq!(buf.as_slice(), b); assert!(reader.read(buf).is_err()); } @@ -440,35 +444,41 @@ mod test { let mut writer = BufferedWriter::with_capacity(2, inner); writer.write([0, 1]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[]); + let b: &[_] = &[]; + assert_eq!(writer.get_ref().get_ref(), b); writer.write([2]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[0, 1]); + let b: &[_] = &[0, 1]; + assert_eq!(writer.get_ref().get_ref(), b); writer.write([3]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[0, 1]); + assert_eq!(writer.get_ref().get_ref(), b); writer.flush().unwrap(); - assert_eq!(&[0, 1, 2, 3], writer.get_ref().get_ref()); + let a: &[_] = &[0, 1, 2, 3]; + assert_eq!(a, writer.get_ref().get_ref()); writer.write([4]).unwrap(); writer.write([5]).unwrap(); - assert_eq!(&[0, 1, 2, 3], writer.get_ref().get_ref()); + assert_eq!(a, writer.get_ref().get_ref()); writer.write([6]).unwrap(); - assert_eq!(&[0, 1, 2, 3, 4, 5], + let a: &[_] = &[0, 1, 2, 3, 4, 5]; + assert_eq!(a, writer.get_ref().get_ref()); writer.write([7, 8]).unwrap(); - assert_eq!(&[0, 1, 2, 3, 4, 5, 6], + let a: &[_] = &[0, 1, 2, 3, 4, 5, 6]; + assert_eq!(a, writer.get_ref().get_ref()); writer.write([9, 10, 11]).unwrap(); - assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + assert_eq!(a, writer.get_ref().get_ref()); writer.flush().unwrap(); - assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + assert_eq!(a, writer.get_ref().get_ref()); } @@ -476,9 +486,11 @@ mod test { fn test_buffered_writer_inner_flushes() { let mut w = BufferedWriter::with_capacity(3, MemWriter::new()); w.write([0, 1]).unwrap(); - assert_eq!(&[], w.get_ref().get_ref()); + let a: &[_] = &[]; + assert_eq!(a, w.get_ref().get_ref()); let w = w.unwrap(); - assert_eq!(&[0, 1], w.get_ref()); + let a: &[_] = &[0, 1]; + assert_eq!(a, w.get_ref()); } // This is just here to make sure that we don't infinite loop in the @@ -519,20 +531,22 @@ mod test { fn test_line_buffer() { let mut writer = LineBufferedWriter::new(MemWriter::new()); writer.write([0]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[]); + let b: &[_] = &[]; + assert_eq!(writer.get_ref().get_ref(), b); writer.write([1]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[]); + assert_eq!(writer.get_ref().get_ref(), b); writer.flush().unwrap(); - assert_eq!(writer.get_ref().get_ref(), &[0, 1]); + let b: &[_] = &[0, 1]; + assert_eq!(writer.get_ref().get_ref(), b); writer.write([0, b'\n', 1, b'\n', 2]).unwrap(); - assert_eq!(writer.get_ref().get_ref(), - &[0, 1, 0, b'\n', 1, b'\n']); + let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n']; + assert_eq!(writer.get_ref().get_ref(), b); writer.flush().unwrap(); - assert_eq!(writer.get_ref().get_ref(), - &[0, 1, 0, b'\n', 1, b'\n', 2]); + let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2]; + assert_eq!(writer.get_ref().get_ref(), b); writer.write([3, b'\n']).unwrap(); - assert_eq!(writer.get_ref().get_ref(), - &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); + let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']; + assert_eq!(writer.get_ref().get_ref(), b); } #[test] diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index 53b5fbe3894ed..1c8b047f56f4d 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -154,26 +154,29 @@ mod test { assert_eq!(Ok(0), reader.read([])); assert_eq!(Ok(3), reader.read(buf)); - assert_eq!(&[1,2,3], buf.as_slice()); + let a: &[u8] = &[1,2,3]; + assert_eq!(a, buf.as_slice()); assert_eq!(Ok(3), reader.read(buf)); - assert_eq!(&[4,5,6], buf.as_slice()); + let a: &[u8] = &[4,5,6]; + assert_eq!(a, buf.as_slice()); assert_eq!(Ok(2), reader.read(buf)); - assert_eq!(&[7,8,6], buf.as_slice()); + let a: &[u8] = &[7,8,6]; + assert_eq!(a, buf.as_slice()); match reader.read(buf.as_mut_slice()) { Ok(..) => fail!(), Err(e) => assert_eq!(e.kind, io::EndOfFile), } - assert_eq!(&[7,8,6], buf.as_slice()); + assert_eq!(a, buf.as_slice()); // Ensure it continues to fail in the same way. match reader.read(buf.as_mut_slice()) { Ok(..) => fail!(), Err(e) => assert_eq!(e.kind, io::EndOfFile), } - assert_eq!(&[7,8,6], buf.as_slice()); + assert_eq!(a, buf.as_slice()); } #[test] diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index ea9d08171e6ce..21ab9c1fdd431 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -346,7 +346,8 @@ mod test { writer.write([0]).unwrap(); writer.write([1, 2, 3]).unwrap(); writer.write([4, 5, 6, 7]).unwrap(); - assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.get_ref(), b); } #[test] @@ -363,7 +364,8 @@ mod test { writer.write([]).unwrap(); assert_eq!(writer.tell(), Ok(8)); } - assert_eq!(buf.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(buf.as_slice(), b); } #[test] @@ -391,7 +393,8 @@ mod test { assert_eq!(writer.tell(), Ok(8)); } - assert_eq!(buf.as_slice(), &[1, 3, 2, 0, 0, 0, 0, 4]); + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; + assert_eq!(buf.as_slice(), b); } #[test] @@ -415,13 +418,16 @@ mod test { let mut buf = [0]; assert_eq!(reader.read(buf), Ok(1)); assert_eq!(reader.tell(), Ok(1)); - assert_eq!(buf.as_slice(), &[0]); + let b: &[_] = &[0]; + assert_eq!(buf.as_slice(), b); let mut buf = [0, ..4]; assert_eq!(reader.read(buf), Ok(4)); assert_eq!(reader.tell(), Ok(5)); - assert_eq!(buf.as_slice(), &[1, 2, 3, 4]); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf.as_slice(), b); assert_eq!(reader.read(buf), Ok(3)); - assert_eq!(buf.slice(0, 3), &[5, 6, 7]); + let b: &[_] = &[5, 6, 7]; + assert_eq!(buf.slice(0, 3), b); assert!(reader.read(buf).is_err()); let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3)); @@ -439,13 +445,16 @@ mod test { let mut buf = [0]; assert_eq!(reader.read(buf), Ok(1)); assert_eq!(reader.tell(), Ok(1)); - assert_eq!(buf.as_slice(), &[0]); + let b: &[_] = &[0]; + assert_eq!(buf.as_slice(), b); let mut buf = [0, ..4]; assert_eq!(reader.read(buf), Ok(4)); assert_eq!(reader.tell(), Ok(5)); - assert_eq!(buf.as_slice(), &[1, 2, 3, 4]); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf.as_slice(), b); assert_eq!(reader.read(buf), Ok(3)); - assert_eq!(buf.slice(0, 3), &[5, 6, 7]); + let b: &[_] = &[5, 6, 7]; + assert_eq!(buf.slice(0, 3), b); assert!(reader.read(buf).is_err()); let mut reader = BufReader::new(in_buf.as_slice()); assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3)); @@ -537,13 +546,16 @@ mod test { let mut r = MemReader::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); let mut buf = [0, ..3]; assert!(r.read_at_least(buf.len(), buf).is_ok()); - assert_eq!(buf.as_slice(), &[1, 2, 3]); + let b: &[_] = &[1, 2, 3]; + assert_eq!(buf.as_slice(), b); assert!(r.read_at_least(0, buf.mut_slice_to(0)).is_ok()); - assert_eq!(buf.as_slice(), &[1, 2, 3]); + assert_eq!(buf.as_slice(), b); assert!(r.read_at_least(buf.len(), buf).is_ok()); - assert_eq!(buf.as_slice(), &[4, 5, 6]); + let b: &[_] = &[4, 5, 6]; + assert_eq!(buf.as_slice(), b); assert!(r.read_at_least(buf.len(), buf).is_err()); - assert_eq!(buf.as_slice(), &[7, 8, 6]); + let b: &[_] = &[7, 8, 6]; + assert_eq!(buf.as_slice(), b); } fn do_bench_mem_writer(b: &mut Bencher, times: uint, len: uint) { diff --git a/src/libstd/io/result.rs b/src/libstd/io/result.rs index a69f6c10abf8e..03637079241d6 100644 --- a/src/libstd/io/result.rs +++ b/src/libstd/io/result.rs @@ -111,7 +111,8 @@ mod test { Ok(MemReader::new(vec!(0, 1, 2, 3))); let mut buf = [0, 0]; reader.read(buf).unwrap(); - assert_eq!(buf.as_slice(), &[0, 1]); + let b: &[_] = &[0, 1]; + assert_eq!(buf.as_slice(), b); } #[test] diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ad666d7003484..f452f8b23e7ba 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -295,7 +295,8 @@ pub fn env_as_bytes() -> Vec<(Vec,Vec)> { for p in input.iter() { let mut it = p.as_slice().splitn(1, |b| *b == b'='); let key = Vec::from_slice(it.next().unwrap()); - let val = Vec::from_slice(it.next().unwrap_or(&[])); + let default: &[u8] = &[]; + let val = Vec::from_slice(it.next().unwrap_or(default)); pairs.push((key, val)); } pairs diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index 38d04324fe417..50441cb534de1 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -846,7 +846,10 @@ impl<'a, P: GenericPath> Display<'a, P> { pub fn as_maybe_owned(&self) -> MaybeOwned<'a> { String::from_utf8_lossy(if self.filename { match self.path.filename() { - None => &[], + None => { + let result: &[u8] = &[]; + result + } Some(v) => v } } else { diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index b7bf75e39a558..b9b7a02b62f1b 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -531,7 +531,8 @@ mod test { r.shuffle(empty); let mut one = [1i]; r.shuffle(one); - assert_eq!(one.as_slice(), &[1]); + let b: &[_] = &[1]; + assert_eq!(one.as_slice(), b); let mut two = [1i, 2]; r.shuffle(two); @@ -539,7 +540,8 @@ mod test { let mut x = [1i, 1, 1]; r.shuffle(x); - assert_eq!(x.as_slice(), &[1, 1, 1]); + let b: &[_] = &[1, 1, 1]; + assert_eq!(x.as_slice(), b); } #[test] @@ -548,7 +550,8 @@ mod test { r.gen::(); let mut v = [1i, 1, 1]; r.shuffle(v); - assert_eq!(v.as_slice(), &[1, 1, 1]); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v.as_slice(), b); assert_eq!(r.gen_range(0u, 1u), 0u); } diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 5044d82a6eabb..f68ace395aaa5 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -100,7 +100,8 @@ fn main() { let mut rand = Vec::with_capacity(n_keys); { - let mut rng: IsaacRng = SeedableRng::from_seed(&[1, 1, 1, 1, 1, 1, 1]); + let seed: &[_] = &[1, 1, 1, 1, 1, 1, 1]; + let mut rng: IsaacRng = SeedableRng::from_seed(seed); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.gen(); diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 1d2d02d7d5926..7f85bc1d700af 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -164,7 +164,7 @@ fn main() { } }; - let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let max = 200000; { diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index 7fd7e3dbf0045..058dc426766bc 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -37,13 +37,16 @@ pub fn main() { _ => fail!() } - assert_eq!(b"a\n\r\t\\\'\"\0\xF0", - &[97u8, 10u8, 13u8, 9u8, 92u8, 39u8, 34u8, 0u8, 240u8]); + let expected: &[_] = &[97u8, 10u8, 13u8, 9u8, 92u8, 39u8, 34u8, 0u8, 240u8]; + assert_eq!(b"a\n\r\t\\\'\"\0\xF0", expected); + let expected: &[_] = &[97u8, 98u8]; assert_eq!(b"a\ - b", &[97u8, 98u8]); - assert_eq!(BAR, &[97u8, 240u8, 9u8]); + b", expected); + let expected: &[_] = &[97u8, 240u8, 9u8]; + assert_eq!(BAR, expected); - match &[97u8, 10u8] { + let val: &[_] = &[97u8, 10u8]; + match val { b"a\n" => {}, _ => fail!(), } @@ -55,9 +58,12 @@ pub fn main() { _ => 3u }, 2); - assert_eq!(BAZ, &[97u8, 92u8, 110u8]); - assert_eq!(br"a\n", &[97u8, 92u8, 110u8]); + let expected: &[_] = &[97u8, 92u8, 110u8]; + assert_eq!(BAZ, expected); + let expected: &[_] = &[97u8, 92u8, 110u8]; + assert_eq!(br"a\n", expected); assert_eq!(br"a\n", b"a\\n"); - assert_eq!(br###"a"##b"###, &[97u8, 34u8, 35u8, 35u8, 98u8]); + let expected: &[_] = &[97u8, 34u8, 35u8, 35u8, 98u8]; + assert_eq!(br###"a"##b"###, expected); assert_eq!(br###"a"##b"###, b"a\"##b"); } diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index 44435dc2398dc..3f559df4b7e7a 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -43,14 +43,22 @@ fn main() { let args = os::args(); let me = args.get(0).as_slice(); - pass(Command::new(me).arg(&[1u8]).output().unwrap()); - pass(Command::new(me).arg(&[2u8]).output().unwrap()); - pass(Command::new(me).arg(&[3u8]).output().unwrap()); - pass(Command::new(me).arg(&[4u8]).output().unwrap()); - pass(Command::new(me).arg(&[5u8]).output().unwrap()); - pass(Command::new(me).arg(&[6u8]).output().unwrap()); - pass(Command::new(me).arg(&[7u8]).output().unwrap()); - pass(Command::new(me).arg(&[8u8]).output().unwrap()); + let x: &[u8] = &[1u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[2u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[3u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[4u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[5u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[6u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[7u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[8u8]; + pass(Command::new(me).arg(x).output().unwrap()); } fn pass(output: ProcessOutput) { diff --git a/src/test/run-pass/syntax-extension-bytes.rs b/src/test/run-pass/syntax-extension-bytes.rs index 5b66d5f28a926..8d5333e5b3fc5 100644 --- a/src/test/run-pass/syntax-extension-bytes.rs +++ b/src/test/run-pass/syntax-extension-bytes.rs @@ -12,13 +12,17 @@ static static_vec: &'static [u8] = bytes!("abc", 0xFF, '!'); pub fn main() { let vec = bytes!("abc"); - assert_eq!(vec, &[97_u8, 98_u8, 99_u8]); + let expected: &[u8] = &[97_u8, 98_u8, 99_u8]; + assert_eq!(vec, expected); let vec = bytes!("null", 0); - assert_eq!(vec, &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]); + let expected: &[u8] = &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]; + assert_eq!(vec, expected); let vec = bytes!(' ', " ", 32, 32u8); - assert_eq!(vec, &[32_u8, 32_u8, 32_u8, 32_u8]); + let expected: &[u8] = &[32_u8, 32_u8, 32_u8, 32_u8]; + assert_eq!(vec, expected); - assert_eq!(static_vec, &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]); + let expected: &[u8] = &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]; + assert_eq!(static_vec, expected); } diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index f95e9ad7d83c9..10c91274f10f8 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -15,10 +15,11 @@ static CONSTEXPR: *const int = &413 as *const _; pub fn main() { let x: Vec<_> = range(0u, 5).collect(); - assert_eq!(x.as_slice(), &[0u,1,2,3,4]); + let expected: &[uint] = &[0,1,2,3,4]; + assert_eq!(x.as_slice(), expected); let x = range(0u, 5).collect::>(); - assert_eq!(x.as_slice(), &[0u,1,2,3,4]); + assert_eq!(x.as_slice(), expected); let y: _ = "hello"; assert_eq!(y.len(), 5); diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index c070e5dab77d0..2fd8a4ab256fd 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -10,6 +10,7 @@ pub fn main() { let x = &[1i, 2, 3, 4, 5]; + let x: &[int] = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { [1, ..ref tail] => &tail[0], diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 8ba8ba4482edc..76f3b7bc28077 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -23,12 +23,14 @@ fn b() { [a, b, ..c] => { assert_eq!(a, 1); assert_eq!(b, 2); - assert_eq!(c, &[3]); + let expected: &[_] = &[3]; + assert_eq!(c, expected); } } match x { [..a, b, c] => { - assert_eq!(a, &[1]); + let expected: &[_] = &[1]; + assert_eq!(a, expected); assert_eq!(b, 2); assert_eq!(c, 3); } @@ -36,7 +38,8 @@ fn b() { match x { [a, ..b, c] => { assert_eq!(a, 1); - assert_eq!(b, &[2]); + let expected: &[_] = &[2]; + assert_eq!(b, expected); assert_eq!(c, 3); } } diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index deb08a4608cc0..b96761f8b6493 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -9,11 +9,10 @@ // except according to those terms. pub fn main() { - assert_eq!((vec!(0i, 1)).to_string(), "[0, 1]".to_string()); - assert_eq!((&[1i, 2]).to_string(), "[1, 2]".to_string()); + assert_eq!((vec!(0, 1)).to_string(), "[0, 1]".to_string()); - let foo = vec!(3i, 4); - let bar = &[4i, 5]; + let foo = vec!(3, 4); + let bar: &[int] = &[4, 5]; assert_eq!(foo.to_string(), "[3, 4]".to_string()); assert_eq!(bar.to_string(), "[4, 5]".to_string()); From 3e626375d8d2226a203bf6ea6e98dab14774c59f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 4 Aug 2014 14:20:11 +0200 Subject: [PATCH 3/5] DST coercions and DST structs [breaking-change] 1. The internal layout for traits has changed from (vtable, data) to (data, vtable). If you were relying on this in unsafe transmutes, you might get some very weird and apparently unrelated errors. You should not be doing this! Prefer not to do this at all, but if you must, you should use raw::TraitObject rather than hardcoding rustc's internal representation into your code. 2. The minimal type of reference-to-vec-literals (e.g., `&[1, 2, 3]`) is now a fixed size vec (e.g., `&[int, ..3]`) where it used to be an unsized vec (e.g., `&[int]`). If you want the unszied type, you must explicitly give the type (e.g., `let x: &[_] = &[1, 2, 3]`). Note in particular where multiple blocks must have the same type (e.g., if and else clauses, vec elements), the compiler will not coerce to the unsized type without a hint. E.g., `[&[1], &[1, 2]]` used to be a valid expression of type '[&[int]]'. It no longer type checks since the first element now has type `&[int, ..1]` and the second has type &[int, ..2]` which are incompatible. 3. The type of blocks (including functions) must be coercible to the expected type (used to be a subtype). Mostly this makes things more flexible and not less (in particular, in the case of coercing function bodies to the return type). However, in some rare cases, this is less flexible. TBH, I'm not exactly sure of the exact effects. I think the change causes us to resolve inferred type variables slightly earlier which might make us slightly more restrictive. Possibly it only affects blocks with unreachable code. E.g., `if ... { fail!(); "Hello" }` used to type check, it no longer does. The fix is to add a semicolon after the string. --- src/liballoc/heap.rs | 6 + src/libcollections/slice.rs | 60 --- src/libcore/intrinsics.rs | 7 + src/libcore/raw.rs | 6 + src/libcore/slice.rs | 1 - src/libdebug/reflect.rs | 13 + src/libdebug/repr.rs | 14 + src/libgreen/context.rs | 2 +- src/liblibc/lib.rs | 2 +- src/librlibc/lib.rs | 2 +- src/librustc/front/test.rs | 11 +- src/librustc/lint/builtin.rs | 20 +- src/librustc/metadata/tydecode.rs | 4 +- src/librustc/metadata/tyencode.rs | 7 +- src/librustc/middle/astencode.rs | 272 +++++++--- src/librustc/middle/borrowck/mod.rs | 9 +- src/librustc/middle/cfg/construct.rs | 1 - src/librustc/middle/check_const.rs | 19 +- src/librustc/middle/check_static.rs | 10 +- src/librustc/middle/const_eval.rs | 10 - src/librustc/middle/expr_use_visitor.rs | 62 +-- src/librustc/middle/kind.rs | 20 +- src/librustc/middle/liveness.rs | 9 +- src/librustc/middle/mem_categorization.rs | 108 ++-- src/librustc/middle/region.rs | 4 - src/librustc/middle/trans/_match.rs | 8 +- src/librustc/middle/trans/adt.rs | 52 +- src/librustc/middle/trans/base.rs | 33 +- src/librustc/middle/trans/callee.rs | 6 +- src/librustc/middle/trans/common.rs | 3 +- src/librustc/middle/trans/consts.rs | 194 ++++--- src/librustc/middle/trans/datum.rs | 28 +- src/librustc/middle/trans/debuginfo.rs | 89 +--- src/librustc/middle/trans/expr.rs | 480 +++++++++++++----- src/librustc/middle/trans/glue.rs | 32 +- src/librustc/middle/trans/meth.rs | 39 +- src/librustc/middle/trans/reflect.rs | 61 ++- src/librustc/middle/trans/tvec.rs | 139 ++--- src/librustc/middle/trans/type_.rs | 11 +- src/librustc/middle/trans/type_of.rs | 91 +++- src/librustc/middle/ty.rs | 480 +++++++++++------- src/librustc/middle/ty_fold.rs | 17 +- src/librustc/middle/typeck/astconv.rs | 118 ++--- src/librustc/middle/typeck/check/_match.rs | 10 +- src/librustc/middle/typeck/check/demand.rs | 14 + src/librustc/middle/typeck/check/method.rs | 168 +++--- src/librustc/middle/typeck/check/mod.rs | 319 ++++++------ src/librustc/middle/typeck/check/regionck.rs | 81 ++- src/librustc/middle/typeck/check/vtable.rs | 262 ++++++---- src/librustc/middle/typeck/check/writeback.rs | 20 +- src/librustc/middle/typeck/coherence.rs | 7 +- src/librustc/middle/typeck/infer/coercion.rs | 306 +++++++---- src/librustc/middle/typeck/infer/combine.rs | 6 +- .../middle/typeck/infer/error_reporting.rs | 4 +- src/librustc/middle/typeck/infer/sub.rs | 13 + src/librustc/middle/typeck/variance.rs | 6 +- src/librustc/util/ppaux.rs | 11 +- src/librustc_back/abi.rs | 4 +- src/librustc_back/svh.rs | 2 - src/librustdoc/clean/mod.rs | 5 +- src/librustdoc/html/render.rs | 3 +- src/librustuv/homing.rs | 6 +- src/librustuv/lib.rs | 5 +- src/libstd/path/posix.rs | 93 ++-- src/libstd/path/windows.rs | 85 ++-- src/libsyntax/ast.rs | 11 - src/libsyntax/ext/build.rs | 11 +- src/libsyntax/fold.rs | 3 - src/libsyntax/parse/mod.rs | 3 +- src/libsyntax/parse/parser.rs | 78 +-- src/libsyntax/print/pprust.rs | 18 +- src/libsyntax/util/small_vector.rs | 5 +- src/libsyntax/visit.rs | 3 - .../const-cast-different-types.rs | 4 +- src/test/compile-fail/dst-bad-assign-2.rs | 46 ++ src/test/compile-fail/dst-bad-assign.rs | 46 ++ src/test/compile-fail/dst-bad-coerce1.rs | 32 ++ src/test/compile-fail/dst-bad-coerce2.rs | 31 ++ src/test/compile-fail/dst-bad-coerce3.rs | 35 ++ src/test/compile-fail/dst-bad-coerce4.rs | 22 + src/test/compile-fail/dst-bad-deep.rs | 25 + src/test/compile-fail/issue-10291.rs | 5 +- src/test/compile-fail/issue-13446.rs | 4 +- src/test/compile-fail/issue-4523.rs | 4 +- src/test/compile-fail/issue-4972.rs | 2 +- src/test/compile-fail/issue-5883.rs | 5 +- src/test/compile-fail/issue-7013.rs | 2 +- ...time-inference-give-expl-lifetime-param.rs | 10 +- src/test/compile-fail/lub-if.rs | 8 +- src/test/compile-fail/lub-match.rs | 4 +- .../regions-early-bound-error-method.rs | 2 +- .../compile-fail/regions-early-bound-error.rs | 2 +- .../compile-fail/regions-glb-free-free.rs | 4 +- src/test/compile-fail/regions-nested-fns.rs | 3 +- .../compile-fail/regions-ret-borrowed-1.rs | 2 +- src/test/compile-fail/regions-ret-borrowed.rs | 2 +- .../regions-return-stack-allocated-vec.rs | 2 +- .../trait-bounds-not-on-bare-trait.rs | 2 +- .../graphviz-flowgraph/f15.dot-expected.dot | 22 +- src/test/run-make/graphviz-flowgraph/f15.rs | 4 +- .../graphviz-flowgraph/f16.dot-expected.dot | 24 +- src/test/run-make/graphviz-flowgraph/f16.rs | 4 +- src/test/run-pass/check-static-slice.rs | 40 ++ src/test/run-pass/const-enum-vec-index.rs | 12 + src/test/run-pass/dst-struct-reflect.rs | 59 +++ src/test/run-pass/dst-struct-sole.rs | 84 +++ src/test/run-pass/dst-struct.rs | 127 +++++ src/test/run-pass/dst-trait.rs | 111 ++++ src/test/run-pass/evec-slice.rs | 2 +- src/test/run-pass/gc-vec.rs | 22 + src/test/run-pass/issue-7012.rs | 3 +- src/test/run-pass/issue-9259.rs | 2 +- src/test/run-pass/overloaded-deref-count.rs | 3 +- src/test/run-pass/reflect-visit-type.rs | 4 +- src/test/run-pass/smallest-hello-world.rs | 1 + src/test/run-pass/vec-dst.rs | 115 +++++ 116 files changed, 3243 insertions(+), 1822 deletions(-) create mode 100644 src/test/compile-fail/dst-bad-assign-2.rs create mode 100644 src/test/compile-fail/dst-bad-assign.rs create mode 100644 src/test/compile-fail/dst-bad-coerce1.rs create mode 100644 src/test/compile-fail/dst-bad-coerce2.rs create mode 100644 src/test/compile-fail/dst-bad-coerce3.rs create mode 100644 src/test/compile-fail/dst-bad-coerce4.rs create mode 100644 src/test/compile-fail/dst-bad-deep.rs create mode 100644 src/test/run-pass/check-static-slice.rs create mode 100644 src/test/run-pass/dst-struct-reflect.rs create mode 100644 src/test/run-pass/dst-struct-sole.rs create mode 100644 src/test/run-pass/dst-struct.rs create mode 100644 src/test/run-pass/dst-trait.rs create mode 100644 src/test/run-pass/gc-vec.rs create mode 100644 src/test/run-pass/vec-dst.rs diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index ab686cb01d66c..38216fa5b59b1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -12,6 +12,7 @@ // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` // and `nonnull` +use core::ptr::RawPtr; #[cfg(not(test))] use core::raw; #[cfg(not(test))] use util; @@ -69,6 +70,11 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint, /// the value returned by `usable_size` for the requested size. #[inline] pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) { + // FIXME(14395) This is only required for DST ~[T], it should be removed once + // we fix that representation to not use null pointers. + if ptr.is_null() { + return; + } imp::deallocate(ptr, size, align) } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 55723ec10a062..71b9673d27929 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -92,8 +92,6 @@ use core::iter::{range_step, MultiplicativeIterator}; use MutableSeq; use vec::Vec; -#[cfg(not(stage0))] -use raw::Slice; pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice}; pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems}; @@ -284,64 +282,6 @@ pub trait CloneableVector { impl<'a, T: Clone> CloneableVector for &'a [T] { /// Returns a copy of `v`. - #[cfg(not(stage0))] - fn to_owned(&self) -> ~[T] { - use num::CheckedMul; - use option::Expect; - - let len = self.len(); - - if len == 0 { - unsafe { - let slice: Slice = Slice{data: 0 as *T, len: 0}; - mem::transmute(slice) - } - } else { - let unit_size = mem::size_of::(); - let data_size = if unit_size == 0 { - len - } else { - let data_size = len.checked_mul(&unit_size); - data_size.expect("overflow in from_iter()") - }; - - unsafe { - // this should pass the real required alignment - let ret = allocate(data_size, 8) as *mut T; - - if unit_size > 0 { - // Be careful with the following loop. We want it to be optimized - // to a memcpy (or something similarly fast) when T is Copy. LLVM - // is easily confused, so any extra operations during the loop can - // prevent this optimization. - let mut i = 0; - let p = &mut (*ret) as *mut _ as *mut T; - try_finally( - &mut i, (), - |i, ()| while *i < len { - mem::move_val_init( - &mut(*p.offset(*i as int)), - self.unsafe_ref(*i).clone()); - *i += 1; - }, - |i| if *i < len { - // we must be failing, clean up after ourselves - for j in range(0, *i as int) { - ptr::read(&*p.offset(j)); - } - // FIXME: #13994 (should pass align and size here) - deallocate(ret as *mut u8, 0, 8); - }); - } - let slice: Slice = Slice{data: ret as *T, len: len}; - mem::transmute(slice) - } - } - } - - /// Returns a copy of `v`. - // NOTE: remove after snapshot - #[cfg(stage0)] #[inline] fn to_vec(&self) -> Vec { Vec::from_slice(*self) } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 84827c63572cf..4ecc1b8f45fc0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -93,6 +93,8 @@ pub trait TyVisitor { fn visit_char(&mut self) -> bool; fn visit_estr_slice(&mut self) -> bool; + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool; fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; @@ -101,8 +103,13 @@ pub trait TyVisitor { fn visit_rptr(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; fn visit_evec_slice(&mut self, mtbl: uint, inner: *const TyDesc) -> bool; + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *const TyDesc) -> bool; + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, + inner: *const TyDesc) -> bool; fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool; diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index da9fab0fc6f50..aa8a4976867a6 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -51,10 +51,16 @@ pub struct Procedure { /// /// This struct does not have a `Repr` implementation /// because there is no way to refer to all trait objects generically. +#[cfg(stage0)] pub struct TraitObject { pub vtable: *mut (), pub data: *mut (), } +#[cfg(not(stage0))] +pub struct TraitObject { + pub data: *(), + pub vtable: *(), +} /// This trait is meant to map equivalences between raw structs and their /// corresponding rust values. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 826f25101fb70..8c55662f16395 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1623,7 +1623,6 @@ pub mod bytes { - // // Boilerplate traits // diff --git a/src/libdebug/reflect.rs b/src/libdebug/reflect.rs index 0cbae6ee2d3a3..0d7209b599970 100644 --- a/src/libdebug/reflect.rs +++ b/src/libdebug/reflect.rs @@ -193,6 +193,8 @@ impl TyVisitor for MovePtrAdaptor { true } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool { @@ -237,6 +239,7 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, mtbl: uint, inner: *const TyDesc) -> bool { self.align(align); @@ -246,6 +249,16 @@ impl TyVisitor for MovePtrAdaptor { self.bump(sz); true } + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, + inner: *TyDesc) -> bool { + self.align(align); + if ! self.inner.visit_evec_fixed(n, sz, align, inner) { + return false; + } + self.bump(sz); + true + } fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool { self.align(align); diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index b85097e6623dc..c810e1f64737f 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -275,6 +275,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> { } // Type no longer exists, vestigial function. + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, _n: uint, _sz: uint, _align: uint) -> bool { fail!(); } @@ -328,6 +330,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> { }) } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, _: uint, inner: *const TyDesc) -> bool { let assumed_size = if sz == 0 { n } else { sz }; @@ -336,6 +340,16 @@ impl<'a> TyVisitor for ReprVisitor<'a> { }) } + #[cfg(not(stage0))] + fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, + inner: *TyDesc) -> bool { + let assumed_size = if sz == 0 { n } else { sz }; + self.get::<()>(|this, b| { + this.write_vec_range(b, assumed_size, inner) + }) + } + + fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { try!(self, self.writer.write([b'{'])); diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index 64537ea12d983..296615e15ffa0 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -112,7 +112,7 @@ impl Context { // the stack limit to 0 to make morestack never fail None => stack::record_rust_managed_stack_bounds(0, uint::MAX), } - rust_swap_registers(out_regs, in_regs) + rust_swap_registers(out_regs, in_regs); } } } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 949dd08eaa343..265d1e37ec389 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -302,7 +302,7 @@ extern {} /// A wrapper for a nullable pointer. Don't use this except for interacting /// with libc. Basically Option, but without the dependence on libstd. // If/when libprim happens, this can be removed in favor of that -pub enum Nullable { +pub enum Nullable { Null, NotNull(T) } diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index 739ec2cf43ffe..b43ad1eabf90c 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -49,7 +49,7 @@ // implementations below. If pointer arithmetic is done through integers the // optimizations start to break down. extern "rust-intrinsic" { - fn offset(dst: *const T, offset: int) -> *const T; + fn offset(dst: *const T, offset: int) -> *const T; } #[no_mangle] diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index ceb7dcc54560c..9984aba8d08ab 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -477,13 +477,14 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc { box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprVstore(box(GC) ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprVec(cx.testfns.iter().map(|test| { - mk_test_desc_and_fn_rec(cx, test) + node: ast::ExprAddrOf(box(GC) ast::MutImmutable, + box(GC) ast::Expr { + id: ast::DUMMY_NODE_ID, + node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| { + mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, - }, ast::ExprVstoreSlice), + }), span: DUMMY_SP, } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 80b4764014673..6cc1c6a7b37df 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1240,18 +1240,8 @@ impl LintPass for UnnecessaryAllocation { } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { - // Warn if string and vector literals with sigils, or boxing expressions, - // are immediately borrowed. + // Warn if boxing expressions are immediately borrowed. let allocation = match e.node { - ast::ExprVstore(e2, ast::ExprVstoreUniq) => { - match e2.node { - ast::ExprLit(lit) if ast_util::lit_is_str(lit) => { - VectorAllocation - } - ast::ExprVec(..) => VectorAllocation, - _ => return - } - } ast::ExprUnary(ast::UnUniq, _) | ast::ExprUnary(ast::UnBox, _) => BoxAllocation, @@ -1261,19 +1251,19 @@ impl LintPass for UnnecessaryAllocation { match cx.tcx.adjustments.borrow().find(&e.id) { Some(adjustment) => { match *adjustment { - ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => { + ty::AutoDerefRef(ty::AutoDerefRef { ref autoref, .. }) => { match (allocation, autoref) { - (VectorAllocation, Some(ty::AutoBorrowVec(..))) => { + (VectorAllocation, &Some(ty::AutoPtr(_, _, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, the sigil can be removed"); } (BoxAllocation, - Some(ty::AutoPtr(_, ast::MutImmutable))) => { + &Some(ty::AutoPtr(_, ast::MutImmutable, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } (BoxAllocation, - Some(ty::AutoPtr(_, ast::MutMutable))) => { + &Some(ty::AutoPtr(_, ast::MutMutable, None))) => { cx.span_lint(UNNECESSARY_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index b26a12d5cfc36..2ef5675caa177 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -377,9 +377,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { return ty::mk_rptr(st.tcx, r, mt); } 'V' => { - let mt = parse_mt(st, |x,y| conv(x,y)); + let t = parse_ty(st, |x,y| conv(x,y)); let sz = parse_size(st); - return ty::mk_vec(st.tcx, mt, sz); + return ty::mk_vec(st.tcx, t, sz); } 'v' => { return ty::mk_str(st.tcx); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index fc5e267aa9050..84ee49c207b0f 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -254,9 +254,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { enc_region(w, cx, r); enc_mt(w, cx, mt); } - ty::ty_vec(mt, sz) => { + ty::ty_vec(t, sz) => { mywrite!(w, "V"); - enc_mt(w, cx, mt); + enc_ty(w, cx, t); mywrite!(w, "/"); match sz { Some(n) => mywrite!(w, "{}|", n), @@ -292,6 +292,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { ty::ty_err => { mywrite!(w, "e"); } + ty::ty_open(_) => { + cx.diag.handler().bug("unexpected type in enc_sty (ty_open)"); + } } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3359d7ed030c4..260e38f20708f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -495,25 +495,7 @@ impl tr for def::Def { } // ______________________________________________________________________ -// Encoding and decoding of adjustment information - -impl tr for ty::AutoDerefRef { - fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef { - ty::AutoDerefRef { - autoderefs: self.autoderefs, - autoref: match self.autoref { - Some(ref autoref) => Some(autoref.tr(xcx)), - None => None - } - } - } -} - -impl tr for ty::AutoRef { - fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoRef { - self.map_region(|r| r.tr(xcx)) - } -} +// Encoding and decoding of ancillary information impl tr for ty::Region { fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region { @@ -961,6 +943,9 @@ trait rbml_writer_helpers { pty: ty::Polytype); fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs); fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment); + fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef); + fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef); + fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind); } impl<'a> rbml_writer_helpers for Encoder<'a> { @@ -1035,16 +1020,85 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { ty::AutoDerefRef(ref auto_deref_ref) => { this.emit_enum_variant("AutoDerefRef", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| auto_deref_ref.encode(this)) + this.emit_enum_variant_arg(0, + |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) }) } + } + }); + } - ty::AutoObject(store, b, def_id, ref substs) => { - this.emit_enum_variant("AutoObject", 2, 4, |this| { - this.emit_enum_variant_arg(0, |this| store.encode(this)); - this.emit_enum_variant_arg(1, |this| b.encode(this)); - this.emit_enum_variant_arg(2, |this| def_id.encode(this)); - this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs))) + fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef) { + self.emit_enum("AutoRef", |this| { + match autoref { + &ty::AutoPtr(r, m, None) => { + this.emit_enum_variant("AutoPtr", 0, 3, |this| { + this.emit_enum_variant_arg(0, |this| r.encode(this)); + this.emit_enum_variant_arg(1, |this| m.encode(this)); + this.emit_enum_variant_arg(2, + |this| this.emit_option(|this| this.emit_option_none())) + }) + } + &ty::AutoPtr(r, m, Some(box ref a)) => { + this.emit_enum_variant("AutoPtr", 0, 3, |this| { + this.emit_enum_variant_arg(0, |this| r.encode(this)); + this.emit_enum_variant_arg(1, |this| m.encode(this)); + this.emit_enum_variant_arg(2, |this| this.emit_option( + |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) + }) + } + &ty::AutoUnsize(ref uk) => { + this.emit_enum_variant("AutoUnsize", 1, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + }) + } + &ty::AutoUnsizeUniq(ref uk) => { + this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) + }) + } + &ty::AutoUnsafe(m) => { + this.emit_enum_variant("AutoUnsafe", 3, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) + }) + } + } + }); + } + + fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef) { + self.emit_struct("AutoDerefRef", 2, |this| { + this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); + this.emit_struct_field("autoref", 1, |this| { + this.emit_option(|this| { + match auto_deref_ref.autoref { + None => this.emit_option_none(), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + } + }) + }) + }); + } + + fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind) { + self.emit_enum("UnsizeKind", |this| { + match *uk { + ty::UnsizeLength(len) => { + this.emit_enum_variant("UnsizeLength", 0, 1, |this| { + this.emit_enum_variant_arg(0, |this| len.encode(this)) + }) + } + ty::UnsizeStruct(box ref uk, idx) => { + this.emit_enum_variant("UnsizeStruct", 1, 2, |this| { + this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))); + this.emit_enum_variant_arg(1, |this| idx.encode(this)) + }) + } + ty::UnsizeVtable(b, def_id, ref substs) => { + this.emit_enum_variant("UnsizeVtable", 2, 3, |this| { + this.emit_enum_variant_arg(0, |this| b.encode(this)); + this.emit_enum_variant_arg(1, |this| def_id.encode(this)); + this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs))) }) } } @@ -1227,9 +1281,30 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - for &adj in tcx.adjustments.borrow().find(&id).iter() { - match *adj { - ty::AutoDerefRef(adj) => { + for &adjustment in tcx.adjustments.borrow().find(&id).iter() { + match *adjustment { + _ if ty::adjust_is_object(adjustment) => { + let method_call = MethodCall::autoobject(id); + for &method in tcx.method_map.borrow().find(&method_call).iter() { + rbml_w.tag(c::tag_table_method_map, |ebml_w| { + rbml_w.id(id); + rbml_w.tag(c::tag_table_val, |rbml_w| { + encode_method_callee(ecx, rbml_w, method_call.adjustment, method) + }) + }) + } + + for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { + rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { + rbml_w.id(id); + rbml_w.tag(c::tag_table_val, |ebml_w| { + encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); + }) + }) + } + } + ty::AutoDerefRef(ref adj) => { + assert!(!ty::adjust_is_object(adjustment)); for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(id, autoderef); for &method in tcx.method_map.borrow().find(&method_call).iter() { @@ -1253,27 +1328,9 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } } - ty::AutoObject(..) => { - let method_call = MethodCall::autoobject(id); - for &method in tcx.method_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) - }) - }) - } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); - }) - }) - } + _ => { + assert!(!ty::adjust_is_object(adjustment)); } - _ => {} } rbml_w.tag(c::tag_table_adjustments, |rbml_w| { @@ -1321,6 +1378,9 @@ trait rbml_decoder_decoder_helpers { fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment; fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnboxedClosure; + fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef; + fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef; + fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind; fn convert_def_id(&mut self, xcx: &ExtendedDecodeContext, source: DefIdSource, @@ -1460,34 +1520,128 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment { self.read_enum("AutoAdjustment", |this| { - let variants = ["AutoAddEnv", "AutoDerefRef", "AutoObject"]; + let variants = ["AutoAddEnv", "AutoDerefRef"]; this.read_enum_variant(variants, |this, i| { Ok(match i { 0 => { let store: ty::TraitStore = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - ty:: AutoAddEnv(store.tr(xcx)) + ty::AutoAddEnv(store.tr(xcx)) } 1 => { let auto_deref_ref: ty::AutoDerefRef = + this.read_enum_variant_arg(0, + |this| Ok(this.read_auto_deref_ref(xcx))).unwrap(); + + ty::AutoDerefRef(auto_deref_ref) + } + _ => fail!("bad enum variant for ty::AutoAdjustment") + }) + }) + }).unwrap() + } + + fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef { + self.read_struct("AutoDerefRef", 2, |this| { + Ok(ty::AutoDerefRef { + autoderefs: this.read_struct_field("autoderefs", 0, |this| { + Decodable::decode(this) + }).unwrap(), + autoref: this.read_struct_field("autoref", 1, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_autoref(xcx))) + } else { + Ok(None) + } + }) + }).unwrap(), + }) + }).unwrap() + } + + fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef { + self.read_enum("AutoRef", |this| { + let variants = ["AutoPtr", + "AutoUnsize", + "AutoUnsizeUniq", + "AutoUnsafe"]; + this.read_enum_variant(variants, |this, i| { + Ok(match i { + 0 => { + let r: ty::Region = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + let m: ast::Mutability = + this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + let a: Option> = + this.read_enum_variant_arg(2, |this| this.read_option(|this, b| { + if b { + Ok(Some(box this.read_autoref(xcx))) + } else { + Ok(None) + } + })).unwrap(); + + ty::AutoPtr(r.tr(xcx), m, a) + } + 1 => { + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(xcx))).unwrap(); - ty::AutoDerefRef(auto_deref_ref.tr(xcx)) + ty::AutoUnsize(uk) } 2 => { - let store: ty::TraitStore = + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(xcx))).unwrap(); + + ty::AutoUnsizeUniq(uk) + } + 3 => { + let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - let b: ty::BuiltinBounds = + + ty::AutoUnsafe(m) + } + _ => fail!("bad enum variant for ty::AutoRef") + }) + }) + }).unwrap() + } + + fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind { + self.read_enum("UnsizeKind", |this| { + let variants = ["UnsizeLength", "UnsizeStruct", "UnsizeVtable"]; + this.read_enum_variant(variants, |this, i| { + Ok(match i { + 0 => { + let len: uint = + this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + + ty::UnsizeLength(len) + } + 1 => { + let uk: ty::UnsizeKind = + this.read_enum_variant_arg(0, + |this| Ok(this.read_unsize_kind(xcx))).unwrap(); + let idx: uint = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + + ty::UnsizeStruct(box uk, idx) + } + 2 => { + let b: ty::BuiltinBounds = + this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let def_id: ast::DefId = - this.read_enum_variant_arg(2, |this| Decodable::decode(this)).unwrap(); - let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(xcx))) - .unwrap(); + this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); + let substs = this.read_enum_variant_arg(2, + |this| Ok(this.read_substs(xcx))).unwrap(); - ty::AutoObject(store.tr(xcx), b, def_id.tr(xcx), substs) + ty::UnsizeVtable(b, def_id.tr(xcx), substs) } - _ => fail!("bad enum variant for ty::AutoAdjustment") + _ => fail!("bad enum variant for ty::UnsizeKind") }) }) }).unwrap() diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 9de55ccc46824..230786924d7c4 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -428,16 +428,15 @@ impl<'a> BorrowckCtxt<'a> { adj: &ty::AutoAdjustment) -> mc::cmt { let r = match *adj { - ty::AutoAddEnv(..) | ty::AutoObject(..) => { - // no autoderefs - self.mc().cat_expr_unadjusted(expr) - } - ty::AutoDerefRef( ty::AutoDerefRef { autoderefs: autoderefs, ..}) => { self.mc().cat_expr_autoderefd(expr, autoderefs) } + ty::AutoAddEnv(..) => { + // no autoderefs + self.mc().cat_expr_unadjusted(expr) + } }; match r { diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index fd3074e130e70..0d77b01d9706d 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -465,7 +465,6 @@ impl<'a> CFGBuilder<'a> { ast::ExprCast(e, _) | ast::ExprUnary(_, e) | ast::ExprParen(e) | - ast::ExprVstore(e, _) | ast::ExprField(e, _, _) => { self.straightline(expr, pred, [e]) } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 283d667f3a803..b0b2fe89c3f0f 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -62,7 +62,7 @@ fn check_item(v: &mut CheckCrateVisitor, it: &Item, _is_const: bool) { fn check_pat(v: &mut CheckCrateVisitor, p: &Pat, _is_const: bool) { fn is_str(e: &Expr) -> bool { match e.node { - ExprVstore(expr, ExprVstoreUniq) => { + ExprBox(_, expr) => { match expr.node { ExprLit(lit) => ast_util::lit_is_str(lit), _ => false, @@ -169,8 +169,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) { None => {} } } - ExprVstore(_, ExprVstoreMutSlice) | - ExprVstore(_, ExprVstoreSlice) | ExprVec(_) | ExprAddrOf(MutImmutable, _) | ExprParen(..) | @@ -179,13 +177,14 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) { ExprTup(..) | ExprRepeat(..) | ExprStruct(..) => { } - ExprAddrOf(..) => { - span_err!(v.tcx.sess, e.span, E0017, - "references in constants may only refer to immutable values"); - }, - ExprVstore(_, ExprVstoreUniq) => { - span_err!(v.tcx.sess, e.span, E0018, - "cannot allocate vectors in constant expressions"); + ExprAddrOf(_, inner) => { + match inner.node { + // Mutable slices are allowed. + ExprVec(_) => {} + _ => span_err!(v.tcx.sess, e.span, E0017, + "references in constants may only refer to immutable values"); + + } }, _ => { diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 8985e633ad464..042a5b8f60aaf 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -107,21 +107,19 @@ impl<'a> Visitor for CheckStaticVisitor<'a> { match e.node { ast::ExprField(..) | ast::ExprVec(..) | - ast::ExprBlock(..) | ast::ExprTup(..) | - ast::ExprVstore(_, ast::ExprVstoreSlice) => { + ast::ExprBlock(..) | ast::ExprTup(..) => { visit::walk_expr(self, e, is_const); } - ast::ExprVstore(_, ast::ExprVstoreMutSlice) => { + ast::ExprAddrOf(ast::MutMutable, _) => { span_err!(self.tcx.sess, e.span, E0020, "static items are not allowed to have mutable slices"); - }, + }, ast::ExprUnary(ast::UnBox, _) => { span_err!(self.tcx.sess, e.span, E0021, "static items are not allowed to have managed pointers"); } ast::ExprBox(..) | - ast::ExprUnary(ast::UnUniq, _) | - ast::ExprVstore(_, ast::ExprVstoreUniq) => { + ast::ExprUnary(ast::UnUniq, _) => { span_err!(self.tcx.sess, e.span, E0022, "static items are not allowed to have custom pointers"); } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index b6ad584c30305..03a7021b70d0b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -206,14 +206,6 @@ impl<'a> ConstEvalVisitor<'a> { ast::ExprVec(ref es) => join_all(es.iter().map(|e| self.classify(&**e))), - ast::ExprVstore(ref e, vstore) => { - match vstore { - ast::ExprVstoreSlice => self.classify(&**e), - ast::ExprVstoreUniq | - ast::ExprVstoreMutSlice => non_const - } - } - ast::ExprStruct(_, ref fs, None) => { let cs = fs.iter().map(|f| self.classify(&*f.expr)); join_all(cs) @@ -554,8 +546,6 @@ pub fn eval_const_expr_partial(tcx: &T, e: &Expr) } } ExprLit(ref lit) => Ok(lit_to_const(&**lit)), - // If we have a vstore, just keep going; it has to be a string - ExprVstore(ref e, _) => eval_const_expr_partial(tcx, &**e), ExprParen(ref e) => eval_const_expr_partial(tcx, &**e), ExprBlock(ref block) => { match block.expr { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 84b879227ae6c..67ee5c5e4be55 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -474,10 +474,6 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { self.walk_captures(expr) } - ast::ExprVstore(ref base, _) => { - self.consume_expr(&**base); - } - ast::ExprBox(ref place, ref base) => { self.consume_expr(&**place); self.consume_expr(&**base); @@ -672,11 +668,10 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { None => { } Some(adjustment) => { match *adjustment { - ty::AutoAddEnv(..) | - ty::AutoObject(..) => { - // Creating an object or closure consumes the - // input and stores it into the resulting rvalue. - debug!("walk_adjustment(AutoAddEnv|AutoObject)"); + ty::AutoAddEnv(..) => { + // Creating a closure consumes the input and stores it + // into the resulting rvalue. + debug!("walk_adjustment(AutoAddEnv)"); let cmt_unadjusted = return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); @@ -735,42 +730,39 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { fn walk_autoref(&mut self, expr: &ast::Expr, autoref: &ty::AutoRef, - autoderefs: uint) { - debug!("walk_autoref expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); + n: uint) { + debug!("walk_autoref expr={}", expr.repr(self.tcx())); - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, autoderefs)); + // Match for unique trait coercions first, since we don't need the + // call to cat_expr_autoderefd. + match *autoref { + ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) | + ty::AutoUnsize(ty::UnsizeVtable(..)) => { + assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ + AutoRefs, found: {}", n)); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + return; + } + _ => {} + } - debug!("walk_autoref: cmt_derefd={}", cmt_derefd.repr(self.tcx())); + let cmt_derefd = return_if_err!( + self.mc.cat_expr_autoderefd(expr, n)); + debug!("walk_adjustment: cmt_derefd={}", + cmt_derefd.repr(self.tcx())); match *autoref { - ty::AutoPtr(r, m) => { + ty::AutoPtr(r, m, _) => { self.delegate.borrow(expr.id, expr.span, cmt_derefd, r, ty::BorrowKind::from_mutbl(m), - AutoRef) - } - ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { - let cmt_index = self.mc.cat_index(expr, cmt_derefd, autoderefs+1); - self.delegate.borrow(expr.id, - expr.span, - cmt_index, - r, - ty::BorrowKind::from_mutbl(m), - AutoRef) - } - ty::AutoBorrowObj(r, m) => { - let cmt_deref = self.mc.cat_deref_obj(expr, cmt_derefd); - self.delegate.borrow(expr.id, - expr.span, - cmt_deref, - r, - ty::BorrowKind::from_mutbl(m), - AutoRef) + AutoRef); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {} } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index dbd7d6a5d6ac4..b96a75cba9480 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -405,14 +405,27 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { "repeated element will be copied"); } } + ExprAssign(ref lhs, _) | + ExprAssignOp(_, ref lhs, _) => { + let lhs_ty = ty::expr_ty(cx.tcx, &**lhs); + if !ty::type_is_sized(cx.tcx, lhs_ty) { + cx.tcx.sess.span_err(lhs.span, "dynamically sized type on lhs of assignment"); + } + } + ExprStruct(..) => { + let e_ty = ty::expr_ty(cx.tcx, e); + if !ty::type_is_sized(cx.tcx, e_ty) { + cx.tcx.sess.span_err(e.span, "trying to initialise a dynamically sized struct"); + } + } _ => {} } // Search for auto-adjustments to find trait coercions. match cx.tcx.adjustments.borrow().find(&e.id) { Some(adjustment) => { - match *adjustment { - ty::AutoObject(..) => { + match adjustment { + adj if ty::adjust_is_object(adj) => { let source_ty = ty::expr_ty(cx.tcx, e); let target_ty = ty::expr_ty_adjusted(cx.tcx, e); let method_call = MethodCall { @@ -425,8 +438,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { e.span, method_call); } - ty::AutoAddEnv(..) | - ty::AutoDerefRef(..) => {} + _ => {} } } None => {} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 2062fa97777d5..38288bf301161 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { } // otherwise, live nodes are not required: - ExprIndex(..) | ExprField(..) | ExprVstore(..) | ExprVec(..) | + ExprIndex(..) | ExprField(..) | ExprVec(..) | ExprCall(..) | ExprMethodCall(..) | ExprTup(..) | ExprBinary(..) | ExprAddrOf(..) | ExprCast(..) | ExprUnary(..) | ExprBreak(_) | @@ -1119,10 +1119,6 @@ impl<'a> Liveness<'a> { // Uninteresting cases: just propagate in rev exec order - ExprVstore(ref expr, _) => { - self.propagate_through_expr(&**expr, succ) - } - ExprVec(ref exprs) => { self.propagate_through_exprs(exprs.as_slice(), succ) } @@ -1449,8 +1445,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { // no correctness conditions related to liveness ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) | ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) | - ExprVstore(..) | ExprVec(..) | ExprTup(..) | - ExprBinary(..) | + ExprVec(..) | ExprTup(..) | ExprBinary(..) | ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) | ExprAgain(..) | ExprLit(_) | ExprBlock(..) | ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ef1e0515156c0..155b69d0a84c2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -205,7 +205,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option { Some(deref_interior(InteriorField(PositionalField(0)))) } - ty::ty_vec(_, Some(_)) => { + ty::ty_vec(_, _) | ty::ty_str => { Some(deref_interior(InteriorElement(element_kind(t)))) } @@ -214,11 +214,12 @@ pub fn opt_deref_kind(t: ty::t) -> Option { } pub fn deref_kind(tcx: &ty::ctxt, t: ty::t) -> deref_kind { + debug!("deref_kind {}", ty_to_str(tcx, t)); match opt_deref_kind(t) { Some(k) => k, None => { tcx.sess.bug( - format!("deref_cat() invoked on non-derefable type {}", + format!("deref_kind() invoked on non-derefable type {}", ty_to_string(tcx, t)).as_slice()); } } @@ -411,13 +412,6 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { Some(adjustment) => { match *adjustment { - ty::AutoObject(..) => { - // Implicitly cast a concrete object to trait object. - // Result is an rvalue. - let expr_ty = if_ok!(self.expr_ty_adjusted(expr)); - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) - } - ty::AutoAddEnv(..) => { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. @@ -485,7 +479,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } None => { let base_cmt = if_ok!(self.cat_expr(&**base)); - Ok(self.cat_index(expr, base_cmt, 0)) + Ok(self.cat_index(expr, base_cmt)) } } } @@ -504,7 +498,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprUnboxedFn(..) | ast::ExprRet(..) | ast::ExprUnary(..) | - ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) | + ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | ast::ExprBinary(..) | ast::ExprWhile(..) | ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) | @@ -703,7 +697,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { -> cmt { match self.typer.temporary_scope(id) { Some(scope) => { - self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) + match ty::get(expr_ty).sty { + ty::ty_vec(_, Some(0)) => self.cat_rvalue(id, span, ty::ReStatic, expr_ty), + _ => self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty) + } } None => { self.cat_rvalue(id, span, ty::ReStatic, expr_ty) @@ -751,10 +748,11 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { implicit: bool) -> cmt { let adjustment = match self.typer.adjustments().borrow().find(&node.id()) { - Some(&ty::AutoObject(..)) => typeck::AutoObject, + Some(adj) if ty::adjust_is_object(adj) => typeck::AutoObject, _ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt), _ => typeck::NoAdjustment }; + let method_call = typeck::MethodCall { expr_id: node.id(), adjustment: adjustment @@ -820,13 +818,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { pub fn cat_index(&self, elt: &N, - mut base_cmt: cmt, - derefs: uint) + mut base_cmt: cmt) -> cmt { - //! Creates a cmt for an indexing operation (`[]`); this - //! indexing operation may occurs as part of an - //! AutoBorrowVec, which when converting a `~[]` to an `&[]` - //! effectively takes the address of the 0th element. + //! Creates a cmt for an indexing operation (`[]`). //! //! One subtle aspect of indexing that may not be //! immediately obvious: for anything other than a fixed-length @@ -839,20 +833,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { //! cmt containing both this deref and the indexing, //! presuming that `base_cmt` is not of fixed-length type. //! - //! In the event that a deref is needed, the "deref count" - //! is taken from the parameter `derefs`. See the comment - //! on the def'n of `root_map_key` in borrowck/mod.rs - //! for more details about deref counts; the summary is - //! that `derefs` should be 0 for an explicit indexing - //! operation and N+1 for an indexing that is part of - //! an auto-adjustment, where N is the number of autoderefs - //! in that adjustment. - //! //! # Parameters //! - `elt`: the AST node being indexed //! - `base_cmt`: the cmt of `elt` - //! - `derefs`: the deref number to be used for - //! the implicit index deref, if any (see above) let method_call = typeck::MethodCall::expr(elt.id()); let method_ty = self.typer.node_method_ty(method_call); @@ -865,7 +848,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } None => { match ty::array_element_ty(base_cmt.ty) { - Some(ref mt) => mt.ty, + Some(ty) => ty, None => { self.tcx().sess.span_bug( elt.span(), @@ -876,30 +859,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } }; - return match deref_kind(self.tcx(), base_cmt.ty) { - deref_ptr(ptr) => { - // for unique ptrs, we inherit mutability from the - // owning reference. - let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); - - // the deref is explicit in the resulting cmt - let deref_cmt = Rc::new(cmt_ { - id:elt.id(), - span:elt.span(), - cat:cat_deref(base_cmt.clone(), derefs, ptr), - mutbl:m, - ty:element_ty - }); - - interior(elt, deref_cmt, base_cmt.ty, m.inherit(), element_ty) - } - - deref_interior(_) => { - // fixed-length vectors have no deref - let m = base_cmt.mutbl.inherit(); - interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty) - } - }; + let m = base_cmt.mutbl.inherit(); + return interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty); fn interior(elt: &N, of_cmt: cmt, @@ -917,6 +878,37 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } } + // Takes either a vec or a reference to a vec and returns the cmt for the + // underlying vec. + fn deref_vec(&self, + elt: &N, + base_cmt: cmt) + -> cmt { + match deref_kind(self.tcx(), base_cmt.ty) { + deref_ptr(ptr) => { + // for unique ptrs, we inherit mutability from the + // owning reference. + let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr); + + // the deref is explicit in the resulting cmt + Rc::new(cmt_ { + id:elt.id(), + span:elt.span(), + cat:cat_deref(base_cmt.clone(), 0, ptr), + mutbl:m, + ty: match ty::deref(base_cmt.ty, false) { + Some(mt) => mt.ty, + None => self.tcx().sess.bug("Found non-derefable type") + } + }) + } + + deref_interior(_) => { + base_cmt + } + } + } + pub fn cat_slice_pattern(&self, vec_cmt: cmt, slice_pat: &ast::Pat) @@ -935,7 +927,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(), slice_pat, slice_ty); - let cmt_slice = self.cat_index(slice_pat, vec_cmt, 0); + let cmt_slice = self.cat_index(slice_pat, self.deref_vec(slice_pat, vec_cmt)); return Ok((cmt_slice, slice_mutbl, slice_r)); fn vec_slice_info(tcx: &ty::ctxt, @@ -951,7 +943,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { match ty::get(slice_ty).sty { ty::ty_rptr(r, ref mt) => match ty::get(mt.ty).sty { - ty::ty_vec(slice_mt, None) => (slice_mt.mutbl, r), + ty::ty_vec(_, None) => (mt.mutbl, r), _ => vec_slice_info(tcx, pat, mt.ty), }, @@ -1143,7 +1135,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { } ast::PatVec(ref before, slice, ref after) => { - let elt_cmt = self.cat_index(pat, cmt, 0); + let elt_cmt = self.cat_index(pat, self.deref_vec(pat, cmt)); for before_pat in before.iter() { if_ok!(self.cat_pattern(elt_cmt.clone(), &**before_pat, |x,y,z| op(x,y,z))); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5f5a324857ab9..1a884eaea2132 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -740,10 +740,6 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, visitor, &*field.expr, blk_id); } } - ast::ExprVstore(ref subexpr, _) => { - visitor.region_maps.record_rvalue_scope(subexpr.id, blk_id); - record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id); - } ast::ExprVec(ref subexprs) | ast::ExprTup(ref subexprs) => { for subexpr in subexprs.iter() { diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index d8bdeb0abf6d5..4a26d4f800210 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -289,8 +289,8 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> { return adt::trans_case(bcx, &**repr, disr_val); } range(ref l1, ref l2) => { - let (l1, _) = consts::const_expr(ccx, &**l1, true); - let (l2, _) = consts::const_expr(ccx, &**l2, true); + let (l1, _, _) = consts::const_expr(ccx, &**l1, true); + let (l2, _, _) = consts::const_expr(ccx, &**l2, true); return range_result(Result::new(bcx, l1), Result::new(bcx, l2)); } vec_len(n, vec_len_eq, _) => { @@ -692,7 +692,7 @@ fn extract_vec_elems<'a>( let vec_datum = match_datum(bcx, val, pat_id); let (base, len) = vec_datum.get_vec_base_and_len(bcx); let vec_ty = node_id_type(bcx, pat_id); - let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)); + let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty))); let mut elems = Vec::from_fn(elem_count, |i| { match slice { @@ -863,7 +863,7 @@ fn compare_values<'a>( match ty::get(rhs_t).sty { ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { ty::ty_str => compare_str(cx, lhs, rhs, rhs_t), - ty::ty_vec(mt, _) => match ty::get(mt.ty).sty { + ty::ty_vec(ty, _) => match ty::get(ty).sty { ty::ty_uint(ast::TyU8) => { // NOTE: cast &[u8] to &str and abuse the str_eq lang item, // which calls memcmp(). diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 57f8f8d6692f0..3bcefe7ec9dbb 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -127,8 +127,11 @@ pub enum Repr { /// For structs, and struct-like parts of anything fancier. pub struct Struct { - pub size: u64, - pub align: u64, + // If the struct is DST, then we will not know its size. We must be careful + // never to use such a struct when a fixed size is required (e.g., stack + // allocation). + pub size: Option, + pub align: Option, pub packed: bool, pub fields: Vec } @@ -265,7 +268,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { mk_struct(cx, ftys.as_slice(), false) }).collect(), dtor); } - _ => cx.sess().bug("adt::represent_type called on non-ADT type") + _ => cx.sess().bug(format!("adt::represent_type called on non-ADT type: {}", + ty_to_str(cx.tcx(), t)).as_slice()) } } @@ -284,8 +288,9 @@ pub enum PointerField { impl Case { fn is_zerolen(&self, cx: &CrateContext) -> bool { - mk_struct(cx, self.tys.as_slice(), false).size == 0 + mk_struct(cx, self.tys.as_slice(), false).size.unwrap() == 0 } + fn find_ptr(&self) -> Option { use back::abi::{fn_field_code, slice_elt_base, trt_field_box}; @@ -342,13 +347,22 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec< } fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct { - let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::>(); - let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); - Struct { - size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, - align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, - packed: packed, - fields: Vec::from_slice(tys), + if tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty)) { + let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::>(); + let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); + Struct { + size: Some(machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64), + align: Some(machine::llalign_of_min(cx, llty_rec) /*bad*/as u64), + packed: packed, + fields: Vec::from_slice(tys), + } + } else { + Struct { + size: None, + align: None, + packed: packed, + fields: Vec::from_slice(tys), + } } } @@ -496,9 +510,9 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool // of the size. // // FIXME #10604: this breaks when vector types are present. - let size = sts.iter().map(|st| st.size).max().unwrap(); - let most_aligned = sts.iter().max_by(|st| st.align).unwrap(); - let align = most_aligned.align; + let size = sts.iter().map(|st| st.size.unwrap()).max().unwrap(); + let most_aligned = sts.iter().max_by(|st| st.align.unwrap()).unwrap(); + let align = most_aligned.align.unwrap(); let discr_ty = ll_inttype(cx, ity); let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64; let align_units = (size + align - 1) / align - 1; @@ -892,12 +906,12 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr, } General(ity, ref cases, _) => { let case = cases.get(discr as uint); - let max_sz = cases.iter().map(|x| x.size).max().unwrap(); + let max_sz = cases.iter().map(|x| x.size.unwrap()).max().unwrap(); let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true); let contents = build_const_struct(ccx, case, (vec!(lldiscr)).append(vals).as_slice()); - C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(), + C_struct(ccx, contents.append([padding(ccx, max_sz - case.size.unwrap())]).as_slice(), false) } Univariant(ref st, _dro) => { @@ -988,9 +1002,9 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef]) offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64; } - assert!(offset <= st.size); - if offset != st.size { - cfields.push(padding(ccx, st.size - offset)); + assert!(offset <= st.size.unwrap()); + if offset != st.size.unwrap() { + cfields.push(padding(ccx, st.size.unwrap() - offset)); } cfields diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 7c2f251bd1685..b27afdb864b97 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -195,16 +195,6 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llvm::NoReturnAttribute as uint64_t) } } - // `~` pointer return values never alias because ownership is transferred - ty::ty_uniq(t) - => match ty::get(t).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {} - _ => unsafe { - llvm::LLVMAddReturnAttribute(llfn, - lib::llvm::NoAliasAttribute as c_uint, - lib::llvm::NoReturnAttribute as uint64_t); - } - }, _ => {} } @@ -965,14 +955,23 @@ pub fn invoke<'a>( llfn: ValueRef, llargs: Vec , fn_ty: ty::t, - call_info: Option) + call_info: Option, + // FIXME(15064) is_lang_item is a horrible hack, please remove it + // at the soonest opportunity. + is_lang_item: bool) -> (ValueRef, &'a Block<'a>) { let _icx = push_ctxt("invoke_"); if bcx.unreachable.get() { return (C_null(Type::i8(bcx.ccx())), bcx); } - let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + // FIXME(15064) Lang item methods may (in the reflect case) not have proper + // types, so doing an attribute lookup will fail. + let attributes = if is_lang_item { + Vec::new() + } else { + get_fn_llvm_attributes(bcx.ccx(), fn_ty) + }; match bcx.opt_node_id { None => { @@ -2311,9 +2310,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) match ty::get(ret_ty).sty { // `~` pointer return values never alias because ownership // is transferred - ty::ty_uniq(it) if match ty::get(it).sty { - ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false - } => {} + ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {} ty::ty_uniq(_) => { attrs.ret(llvm::NoAliasAttribute); } @@ -2324,9 +2321,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) match ty::get(ret_ty).sty { // These are not really pointers but pairs, (pointer, len) ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty { - ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false - } => {} + ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {} ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); attrs.ret(llvm::DereferenceableAttribute(llret_sz)); @@ -2593,7 +2588,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. - let (v, inlineable) = consts::const_expr(ccx, &**expr, is_local); + let (v, inlineable, _) = consts::const_expr(ccx, &**expr, is_local); ccx.const_values.borrow_mut().insert(id, v); let mut inlineable = inlineable; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index d50b30c754521..1283cc19528a6 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -51,6 +51,7 @@ use middle::typeck; use middle::typeck::coherence::make_substs_for_receiver_types; use middle::typeck::MethodCall; use util::ppaux::Repr; +use util::ppaux::ty_to_string; use std::gc::Gc; use syntax::abi as synabi; @@ -853,7 +854,8 @@ pub fn trans_call_inner<'a>( llfn, llargs, callee_ty, - call_info); + call_info, + dest.is_none()); bcx = b; llresult = llret; @@ -1194,6 +1196,8 @@ pub fn trans_arg_datum<'a>( let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty); debug!("casting actual type ({}) to match formal ({})", bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty)); + debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty), + ty_to_string(bcx.tcx(), formal_arg_ty)); val = PointerCast(bcx, val, llformal_arg_ty); } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index fefd3e326515d..f0876442ff5ae 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -65,12 +65,13 @@ fn type_is_newtype_immediate(ccx: &CrateContext, ty: ty::t) -> bool { pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool { use middle::trans::machine::llsize_of_alloc; use middle::trans::type_of::sizing_type_of; + let tcx = ccx.tcx(); let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) || ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) || type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) || ty::type_is_simd(tcx, ty); - if simple && !ty::type_is_trait(ty) { + if simple && !ty::type_is_fat_ptr(tcx, ty) { return true; } match ty::get(ty).sty { diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 07f0dbaf73fc0..e65a10b3bb243 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -11,11 +11,9 @@ use back::abi; use llvm; -use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, - False}; +use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False}; use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; - use metadata::csearch; use middle::const_eval; use middle::def; @@ -98,12 +96,17 @@ pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { } } +// Helper function because we don't have tuple-swizzling. +fn first_two((a, b, _): (R, S, T)) -> (R, S) { + (a, b) +} + fn const_vec(cx: &CrateContext, e: &ast::Expr, es: &[Gc], is_local: bool) -> (ValueRef, Type, bool) { let vec_ty = ty::expr_ty(cx.tcx(), e); let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); let llunitty = type_of::type_of(cx, unit_ty); - let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, &**e, is_local))); + let (vs, inlineable) = vec::unzip(es.iter().map(|e| first_two(const_expr(cx, &**e, is_local)))); // If the vector contains enums, an LLVM array won't work. let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, vs.as_slice(), false) @@ -119,7 +122,8 @@ pub fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef { llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name) }); llvm::LLVMSetInitializer(gv, cv); - llvm::LLVMSetGlobalConstant(gv, True); + llvm::LLVMSetGlobalConstant(gv, + if mutbl == ast::MutImmutable {True} else {False}); SetLinkage(gv, PrivateLinkage); gv } @@ -131,7 +135,6 @@ fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef { None => v }; unsafe { - assert_eq!(llvm::LLVMIsGlobalConstant(v), True); llvm::LLVMGetInitializer(v) } } @@ -146,25 +149,25 @@ fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool) -> (ValueRef, ty::t) { match ty::deref(t, explicit) { Some(ref mt) => { - assert!(mt.mutbl != ast::MutMutable); - let dv = match ty::get(t).sty { + match ty::get(t).sty { ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => { - match ty::get(mt.ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => { - cx.sess().bug("unexpected unsized type") - } - _ => const_deref_ptr(cx, v), + if ty::type_is_sized(cx.tcx(), mt.ty) { + (const_deref_ptr(cx, v), mt.ty) + } else { + // Derefing a fat pointer does not change the representation, + // just the type to ty_open. + (v, ty::mk_open(cx.tcx(), mt.ty)) } } ty::ty_enum(..) | ty::ty_struct(..) => { - const_deref_newtype(cx, v, t) + assert!(mt.mutbl != ast::MutMutable); + (const_deref_newtype(cx, v, t), mt.ty) } _ => { cx.sess().bug(format!("unexpected dereferenceable type {}", ty_to_string(cx.tcx(), t)).as_slice()) } - }; - (dv, mt.ty) + } } None => { cx.sess().bug(format!("can't dereference const of type {}", @@ -193,12 +196,12 @@ pub fn get_const_val(cx: &CrateContext, !cx.non_inlineable_statics.borrow().contains(&def_id.node)) } -pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) { +pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool, ty::t) { let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local); let mut llconst = llconst; let mut inlineable = inlineable; let ety = ty::expr_ty(cx.tcx(), e); - let ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e); + let mut ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e); let opt_adj = cx.tcx.adjustments.borrow().find_copy(&e.id); match opt_adj { None => { } @@ -219,51 +222,64 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef format!("unexpected static function: {:?}", store).as_slice()) } - ty::AutoObject(..) => { - cx.sess() - .span_unimpl(e.span, - "unimplemented const coercion to trait \ - object"); - } ty::AutoDerefRef(ref adj) => { let mut ty = ety; - let mut maybe_ptr = None; - for _ in range(0, adj.autoderefs) { + // Save the last autoderef in case we can avoid it. + for _ in range(0, adj.autoderefs-1) { let (dv, dt) = const_deref(cx, llconst, ty, false); - maybe_ptr = Some(llconst); llconst = dv; ty = dt; } match adj.autoref { - None => { } + None => { + let (dv, dt) = const_deref(cx, llconst, ty, false); + llconst = dv; + + // If we derefed a fat pointer then we will have an + // open type here. So we need to update the type with + // the one returned from const_deref. + ety_adjusted = dt; + } Some(ref autoref) => { - // Don't copy data to do a deref+ref. - let llptr = match maybe_ptr { - Some(ptr) => ptr, - None => { - inlineable = false; - const_addr_of(cx, llconst) - } - }; match *autoref { - ty::AutoUnsafe(m) | - ty::AutoPtr(ty::ReStatic, m) => { - assert!(m != ast::MutMutable); - llconst = llptr; + ty::AutoUnsafe(_) | + ty::AutoPtr(ty::ReStatic, _, None) => { + // Don't copy data to do a deref+ref + // (i.e., skip the last auto-deref). + if adj.autoderefs == 0 { + inlineable = false; + llconst = const_addr_of(cx, llconst, ast::MutImmutable); + } } - ty::AutoBorrowVec(ty::ReStatic, m) => { - assert!(m != ast::MutMutable); - assert_eq!(abi::slice_elt_base, 0); - assert_eq!(abi::slice_elt_len, 1); + ty::AutoPtr(ty::ReStatic, _, Some(box ty::AutoUnsize(..))) => { + if adj.autoderefs > 0 { + // Seeing as we are deref'ing here and take a reference + // again to make the pointer part of the far pointer below, + // we just skip the whole thing. We still need the type + // though. This works even if we don't need to deref + // because of byref semantics. Note that this is not just + // an optimisation, it is necessary for mutable vectors to + // work properly. + let (_, dt) = const_deref(cx, llconst, ty, false); + ty = dt; + } + match ty::get(ty).sty { - ty::ty_vec(_, Some(len)) => { + ty::ty_vec(unit_ty, Some(len)) => { + inlineable = false; + let llunitty = type_of::type_of(cx, unit_ty); + let llptr = const_ptrcast(cx, llconst, llunitty); + assert_eq!(abi::slice_elt_base, 0); + assert_eq!(abi::slice_elt_len, 1); llconst = C_struct(cx, [ llptr, C_uint(cx, len) ], false); } - _ => {} + _ => cx.sess().span_bug(e.span, + format!("unimplemented type in const unsize: {}", + ty_to_str(cx.tcx(), ty)).as_slice()) } } _ => { @@ -294,7 +310,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety), csize, tsize).as_slice()); } - (llconst, inlineable) + (llconst, inlineable, ety_adjusted) } // the bool returned is whether this expression can be inlined into other crates @@ -302,7 +318,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) { let map_list = |exprs: &[Gc]| { - exprs.iter().map(|e| const_expr(cx, &**e, is_local)) + exprs.iter().map(|e| first_two(const_expr(cx, &**e, is_local))) .fold((Vec::new(), true), |(l, all_inlineable), (val, inlineable)| { (l.append_one(val), all_inlineable && inlineable) @@ -315,8 +331,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, (consts::const_lit(cx, e, (**lit).clone()), true) } ast::ExprBinary(b, ref e1, ref e2) => { - let (te1, _) = const_expr(cx, &**e1, is_local); - let (te2, _) = const_expr(cx, &**e2, is_local); + let (te1, _, _) = const_expr(cx, &**e1, is_local); + let (te2, _, _) = const_expr(cx, &**e2, is_local); let te2 = base::cast_shift_const_rhs(b, te1, te2); @@ -397,7 +413,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }, true) }, ast::ExprUnary(u, ref e) => { - let (te, _) = const_expr(cx, &**e, is_local); + let (te, _, _) = const_expr(cx, &**e, is_local); let ty = ty::expr_ty(cx.tcx(), &**e); let is_float = ty::type_is_fp(ty); return (match u { @@ -413,9 +429,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }, true) } ast::ExprField(ref base, field, _) => { - let bt = ty::expr_ty_adjusted(cx.tcx(), &**base); + let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); let brepr = adt::represent_type(cx, bt); - let (bv, inlineable) = const_expr(cx, &**base, is_local); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable) @@ -423,8 +438,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, } ast::ExprIndex(ref base, ref index) => { - let bt = ty::expr_ty_adjusted(cx.tcx(), &**base); - let (bv, inlineable) = const_expr(cx, &**base, is_local); + let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); let iv = match const_eval::eval_const_expr(cx.tcx(), &**index) { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, @@ -433,16 +447,29 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, }; let (arr, len) = match ty::get(bt).sty { ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)), - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_open(ty) => match ty::get(ty).sty { ty::ty_vec(_, None) | ty::ty_str => { let e1 = const_get_elt(cx, bv, [0]); (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1])) }, _ => cx.sess().span_bug(base.span, - "index-expr base must be a vector or string type") + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) + }, + ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { + ty::ty_vec(_, Some(u)) => { + (const_deref_ptr(cx, bv), C_uint(cx, u)) + }, + _ => cx.sess().span_bug(base.span, + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) }, _ => cx.sess().span_bug(base.span, - "index-expr base must be a vector or string type") + format!("index-expr base must be a vector \ + or string type, found {}", + ty_to_str(cx.tcx(), bt)).as_slice()) }; let len = llvm::LLVMConstIntGetZExtValue(len) as u64; @@ -467,10 +494,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, ast::ExprCast(ref base, _) => { let ety = ty::expr_ty(cx.tcx(), e); let llty = type_of::type_of(cx, ety); - let basety = ty::expr_ty(cx.tcx(), &**base); - let (v, inlineable) = const_expr(cx, &**base, is_local); - return (match (expr::cast_type_kind(basety), - expr::cast_type_kind(ety)) { + let (v, inlineable, basety) = const_expr(cx, &**base, is_local); + return (match (expr::cast_type_kind(cx.tcx(), basety), + expr::cast_type_kind(cx.tcx(), ety)) { (expr::cast_integral, expr::cast_integral) => { let s = ty::type_is_signed(basety) as Bool; @@ -494,7 +520,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let repr = adt::represent_type(cx, basety); let discr = adt::const_get_discrim(cx, &*repr, v); let iv = C_integral(cx.int_type, discr, false); - let ety_cast = expr::cast_type_kind(ety); + let ety_cast = expr::cast_type_kind(cx.tcx(), ety); match ety_cast { expr::cast_integral => { let s = ty::type_is_signed(ety) as Bool; @@ -516,9 +542,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, } }, inlineable) } - ast::ExprAddrOf(ast::MutImmutable, ref sub) => { - let (e, _) = const_expr(cx, &**sub, is_local); - (const_addr_of(cx, e), false) + ast::ExprAddrOf(mutbl, ref sub) => { + let (e, _, _) = const_expr(cx, &**sub, is_local); + (const_addr_of(cx, e, mutbl), false) } ast::ExprTup(ref es) => { let ety = ty::expr_ty(cx.tcx(), e); @@ -540,10 +566,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate() .map(|(ix, &field_ty)| { match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) { - Some(ref f) => const_expr(cx, &*f.expr, is_local), + Some(ref f) => first_two(const_expr(cx, &*f.expr, is_local)), None => { match base_val { - Some((bv, inlineable)) => { + Some((bv, inlineable, _)) => { (adt::const_get_field(cx, &*repr, bv, discr, ix), inlineable) } @@ -563,34 +589,6 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, is_local); (v, inlineable) } - ast::ExprVstore(ref sub, store @ ast::ExprVstoreSlice) | - ast::ExprVstore(ref sub, store @ ast::ExprVstoreMutSlice) => { - match sub.node { - ast::ExprLit(ref lit) => { - match lit.node { - ast::LitStr(..) => { const_expr(cx, &**sub, is_local) } - _ => { cx.sess().span_bug(e.span, "bad const-slice lit") } - } - } - ast::ExprVec(ref es) => { - let (cv, llunitty, _) = const_vec(cx, - e, - es.as_slice(), - is_local); - let llty = val_ty(cv); - let gv = "const".with_c_str(|name| { - llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name) - }); - llvm::LLVMSetInitializer(gv, cv); - llvm::LLVMSetGlobalConstant(gv, - if store == ast::ExprVstoreMutSlice { False } else { True }); - SetLinkage(gv, PrivateLinkage); - let p = const_ptrcast(cx, gv, llunitty); - (C_struct(cx, [p, C_uint(cx, es.len())], false), false) - } - _ => cx.sess().span_bug(e.span, "bad const-slice expr") - } - } ast::ExprRepeat(ref elem, ref count) => { let vec_ty = ty::expr_ty(cx.tcx(), e); let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); @@ -669,10 +667,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, _ => cx.sess().span_bug(e.span, "expected a struct or variant def") } } - ast::ExprParen(ref e) => { const_expr(cx, &**e, is_local) } + ast::ExprParen(ref e) => first_two(const_expr(cx, &**e, is_local)), ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => const_expr(cx, &**expr, is_local), + Some(ref expr) => first_two(const_expr(cx, &**expr, is_local)), None => (C_nil(cx), true) } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index f69a8af9c08d3..b7803d404b5bc 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -450,6 +450,8 @@ impl Datum { name: &str, expr_id: ast::NodeId) -> DatumBlock<'a, Lvalue> { + assert!(ty::lltype_is_sized(bcx.tcx(), self.ty), + "Trying to convert unsized value to lval"); self.match_kind( |l| DatumBlock::new(bcx, l), |r| { @@ -504,12 +506,28 @@ impl Datum { self.val } - pub fn get_element(&self, - ty: ty::t, - gep: |ValueRef| -> ValueRef) - -> Datum { + // Extracts a component of a compound data structure (e.g., a field from a + // struct). Note that if self is an opened, unsized type then the returned + // datum may also be unsized _without the size information_. It is the + // callers responsibility to package the result in some way to make a valid + // datum in that case (e.g., by making a fat pointer or opened pair). + pub fn get_element<'a>(&self, + bcx: &'a Block<'a>, + ty: ty::t, + gep: |ValueRef| -> ValueRef) + -> Datum { + let val = match ty::get(self.ty).sty { + _ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val), + ty::ty_open(_) => { + let base = Load(bcx, expr::get_dataptr(bcx, self.val)); + gep(base) + } + _ => bcx.tcx().sess.bug( + format!("Unexpected unsized type in get_element: {}", + bcx.ty_to_str(self.ty)).as_slice()) + }; Datum { - val: gep(self.val), + val: val, kind: Lvalue, ty: ty, } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index db674b4028f24..31b3122446493 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -402,7 +402,7 @@ impl TypeMap { let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); unique_type_id.push_str(inner_type_id.as_slice()); }, - ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => { + ty::ty_vec(inner_type, optional_length) => { match optional_length { Some(len) => { unique_type_id.push_str(format!("[{}]", len).as_slice()); @@ -595,18 +595,6 @@ impl TypeMap { UniqueTypeId(interner_key) } - fn get_unique_type_id_of_heap_vec_box(&mut self, - cx: &CrateContext, - element_type: ty::t) - -> UniqueTypeId { - let element_type_id = self.get_unique_type_id_of_type(cx, element_type); - let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}", - self.get_unique_type_id_as_string(element_type_id) - .as_slice()); - let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id)); - UniqueTypeId(interner_key) - } - fn get_unique_type_id_of_gc_box(&mut self, cx: &CrateContext, element_type: ty::t) @@ -2811,26 +2799,13 @@ fn subroutine_type_metadata(cx: &CrateContext, } fn trait_pointer_metadata(cx: &CrateContext, - // trait_pointer_type must be the type of the fat - // pointer to the concrete trait object - trait_pointer_type: ty::t, + trait_object_type: ty::t, unique_type_id: UniqueTypeId) -> DIType { // The implementation provided here is a stub. It makes sure that the trait // type is assigned the correct name, size, namespace, and source location. // But it does not describe the trait's methods. - let trait_object_type = match ty::get(trait_pointer_type).sty { - ty::ty_uniq(pointee_type) => pointee_type, - ty::ty_rptr(_, ty::mt { ty, .. }) => ty, - _ => { - let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_pointer_type); - cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \ - trait_pointer_metadata(): {}", - pp_type_name.as_slice()).as_slice()); - } - }; - let def_id = match ty::get(trait_object_type).sty { ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id, _ => { @@ -2842,11 +2817,11 @@ fn trait_pointer_metadata(cx: &CrateContext, }; let trait_pointer_type_name = - compute_debuginfo_type_name(cx, trait_pointer_type, false); + compute_debuginfo_type_name(cx, trait_object_type, false); let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); - let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type); + let trait_llvm_type = type_of::type_of(cx, trait_object_type); composite_type_metadata(cx, trait_pointer_llvm_type, @@ -2914,56 +2889,32 @@ fn type_metadata(cx: &CrateContext, ty::ty_box(pointee_type) => { at_box_metadata(cx, t, pointee_type, unique_type_id) } - ty::ty_vec(ref mt, Some(len)) => { - fixed_vec_metadata(cx, unique_type_id, mt.ty, len, usage_site_span) + ty::ty_vec(typ, Some(len)) => { + fixed_vec_metadata(cx, unique_type_id, typ, len, usage_site_span) } - ty::ty_uniq(pointee_type) => { - match ty::get(pointee_type).sty { - ty::ty_vec(ref mt, None) => { - let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span); - pointer_type_metadata(cx, t, vec_metadata) - } - ty::ty_str => { - let i8_t = ty::mk_i8(); - let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span); - pointer_type_metadata(cx, t, vec_metadata) - } - ty::ty_trait(..) => { - MetadataCreationResult::new( + // FIXME Can we do better than this for unsized vec/str fields? + ty::ty_vec(typ, None) => fixed_vec_metadata(cx, unique_type_id, typ, 0, usage_site_span), + ty::ty_str => fixed_vec_metadata(cx, unique_type_id, ty::mk_i8(), 0, usage_site_span), + ty::ty_trait(..) => { + MetadataCreationResult::new( trait_pointer_metadata(cx, t, unique_type_id), - false) - } - _ => { - let pointee_metadata = type_metadata(cx, - pointee_type, - usage_site_span); - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return metadata, - None => { /* proceed normally */ } - }; - - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), - false) - } - } + false) } - ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - match ty::get(mt.ty).sty { - ty::ty_vec(ref mt, None) => { - vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span) + ty::ty_uniq(ty) | ty::ty_ptr(ty::mt{ty, ..}) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + match ty::get(ty).sty { + ty::ty_vec(typ, None) => { + vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span) } ty::ty_str => { vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span) } ty::ty_trait(..) => { MetadataCreationResult::new( - trait_pointer_metadata(cx, t, unique_type_id), + trait_pointer_metadata(cx, ty, unique_type_id), false) } _ => { - let pointee = type_metadata(cx, mt.ty, usage_site_span); + let pointee_metadata = type_metadata(cx, ty, usage_site_span); match debug_context(cx).type_map .borrow() @@ -2972,7 +2923,8 @@ fn type_metadata(cx: &CrateContext, None => { /* proceed normally */ } }; - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false) + MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false) } } } @@ -3471,7 +3423,6 @@ fn populate_scope_map(cx: &CrateContext, ast::ExprAgain(_) | ast::ExprPath(_) => {} - ast::ExprVstore(ref sub_exp, _) | ast::ExprCast(ref sub_exp, _) | ast::ExprAddrOf(_, ref sub_exp) | ast::ExprField(ref sub_exp, _, _) | diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ead90dbe36b2c..657cd72c25543 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -40,6 +40,7 @@ use metadata::csearch; use middle::def; use middle::lang_items::MallocFnLangItem; use middle::mem_categorization::Typer; +use middle::subst; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; @@ -62,8 +63,8 @@ use middle::trans::inline; use middle::trans::tvec; use middle::trans::type_of; use middle::ty::struct_fields; -use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe}; -use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef}; +use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe}; +use middle::ty::{AutoPtr}; use middle::ty; use middle::typeck; use middle::typeck::MethodCall; @@ -160,6 +161,14 @@ pub fn trans<'a>(bcx: &'a Block<'a>, return DatumBlock::new(bcx, datum); } +pub fn get_len(bcx: &Block, fat_ptr: ValueRef) -> ValueRef { + GEPi(bcx, fat_ptr, [0u, abi::slice_elt_len]) +} + +pub fn get_dataptr(bcx: &Block, fat_ptr: ValueRef) -> ValueRef { + GEPi(bcx, fat_ptr, [0u, abi::slice_elt_base]) +} + fn apply_adjustments<'a>(bcx: &'a Block<'a>, expr: &ast::Expr, datum: Datum) @@ -184,71 +193,243 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, datum = unpack_datum!(bcx, add_env(bcx, expr, datum)); } AutoDerefRef(ref adj) => { - if adj.autoderefs > 0 { + // Extracting a value from a box counts as a deref, but if we are + // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing + // a deref (and wouldn't if we could treat Box like a normal struct). + let autoderefs = match adj.autoref { + Some(ty::AutoUnsizeUniq(..)) => adj.autoderefs - 1, + _ => adj.autoderefs + }; + + if autoderefs > 0 { datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, datum, adj.autoderefs)); + bcx, deref_multiple(bcx, expr, datum, autoderefs)); } - datum = match adj.autoref { - None => { - datum - } - Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr - Some(AutoPtr(..)) => { - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) - } - Some(AutoBorrowVec(..)) => { - unpack_datum!(bcx, auto_slice(bcx, expr, datum)) + match adj.autoref { + Some(ref a) => { + datum = unpack_datum!(bcx, apply_autoref(a, + bcx, + expr, + datum)); } - Some(AutoBorrowVecRef(..)) => { - unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum)) - } - Some(AutoBorrowObj(..)) => { - unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum)) - } - }; - } - AutoObject(..) => { - let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr); - let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust"); - bcx = meth::trans_trait_cast( - bcx, datum, expr.id, SaveIn(scratch.val)); - datum = scratch.to_expr_datum(); + _ => {} + } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock {bcx: bcx, datum: datum}; - fn auto_slice<'a>( - bcx: &'a Block<'a>, - expr: &ast::Expr, - datum: Datum) - -> DatumBlock<'a, Expr> { - // This is not the most efficient thing possible; since slices - // are two words it'd be better if this were compiled in - // 'dest' mode, but I can't find a nice way to structure the - // code and keep it DRY that accommodates that use case at the - // moment. + fn apply_autoref<'a>(autoref: &ty::AutoRef, + bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + let mut datum = datum; + + let datum = match autoref { + &AutoUnsafe(..) => { + debug!(" AutoUnsafe"); + unpack_datum!(bcx, ref_ptr(bcx, expr, datum)) + } + &AutoPtr(_, _, ref a) => { + debug!(" AutoPtr"); + match a { + &Some(box ref a) => datum = unpack_datum!(bcx, + apply_autoref(a, bcx, expr, datum)), + _ => {} + } + unpack_datum!(bcx, ref_ptr(bcx, expr, datum)) + } + &ty::AutoUnsize(ref k) => { + debug!(" AutoUnsize"); + unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k)) + } + + &ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => { + debug!(" AutoUnsizeUniq(UnsizeLength)"); + unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len)) + } + &ty::AutoUnsizeUniq(ref k) => { + debug!(" AutoUnsizeUniq"); + unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k)) + } + }; + DatumBlock::new(bcx, datum) + } + + fn ref_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum) + -> DatumBlock<'a, Expr> { + if !ty::type_is_sized(bcx.tcx(), datum.ty) { + debug!("Taking address of unsized type {}", + bcx.ty_to_str(datum.ty)); + ref_fat_ptr(bcx, expr, datum) + } else { + debug!("Taking address of sized type {}", + bcx.ty_to_str(datum.ty)); + auto_ref(bcx, datum, expr) + } + } + + // Retrieve the information we are losing (making dynamic) in an unsizing + // adjustment. + fn unsized_info<'a>(bcx: &'a Block<'a>, + kind: &ty::UnsizeKind, + id: ast::NodeId, + sized_ty: ty::t) -> ValueRef { + match kind { + &ty::UnsizeLength(len) => C_uint(bcx.ccx(), len), + &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(sized_ty).sty { + ty::ty_struct(_, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let sized_ty = ty_substs.get(tp_index); + unsized_info(bcx, k, id, *sized_ty) + } + _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", + bcx.ty_to_str(sized_ty)).as_slice()) + }, + &ty::UnsizeVtable(..) => + PointerCast(bcx, + meth::vtable_ptr(bcx, id, sized_ty), + Type::vtable_ptr(bcx.ccx())) + } + } + + fn unsize_expr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum, + k: &ty::UnsizeKind) + -> DatumBlock<'a, Expr> { + let tcx = bcx.tcx(); + let datum_ty = datum.ty; + let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); + let dest_ty = ty::mk_open(tcx, unsized_ty); + // Closures for extracting and manipulating the data and payload parts of + // the fat pointer. + let base = match k { + &ty::UnsizeStruct(..) => + |bcx, val| PointerCast(bcx, + val, + type_of::type_of(bcx.ccx(), unsized_ty).ptr_to()), + &ty::UnsizeLength(..) => + |bcx, val| GEPi(bcx, val, [0u, 0u]), + &ty::UnsizeVtable(..) => + |_bcx, val| PointerCast(bcx, val, Type::i8p(bcx.ccx())) + }; + let info = |bcx, _val| unsized_info(bcx, k, expr.id, datum_ty); + into_fat_ptr(bcx, expr, datum, dest_ty, base, info) + } + + fn ref_fat_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum) + -> DatumBlock<'a, Expr> { + let tcx = bcx.tcx(); + let dest_ty = ty::close_type(tcx, datum.ty); + let base = |bcx, val| Load(bcx, get_dataptr(bcx, val)); + let len = |bcx, val| Load(bcx, get_len(bcx, val)); + into_fat_ptr(bcx, expr, datum, dest_ty, base, len) + } + + fn into_fat_ptr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum, + dest_ty: ty::t, + base: |&'a Block<'a>, ValueRef| -> ValueRef, + info: |&'a Block<'a>, ValueRef| -> ValueRef) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + let base = base(bcx, lval.val); + let info = info(bcx, lval.val); + + let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr"); + Store(bcx, base, get_dataptr(bcx, scratch.val)); + Store(bcx, info, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + + fn unsize_unique_vec<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum, + len: uint) + -> DatumBlock<'a, Expr> { let mut bcx = bcx; let tcx = bcx.tcx(); - let unit_ty = ty::sequence_element_type(tcx, datum.ty); - // Arrange cleanup, if not already done. This is needed in - // case we are auto-slicing an owned vector or some such. - let datum = unpack_datum!( - bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id)); + let datum_ty = datum.ty; + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id)); + + let ll_len = C_uint(bcx.ccx(), len); + let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty)); + let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None)); + let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique"); + + if len == 0 { + Store(bcx, + C_null(type_of::type_of(bcx.ccx(), unit_ty).ptr_to()), + get_dataptr(bcx, scratch.val)); + } else { + // Box<[(), ..n]> will not allocate, but ~[()] expects an + // allocation of n bytes, so we must allocate here (yuck). + let llty = type_of::type_of(bcx.ccx(), unit_ty); + if llsize_of_alloc(bcx.ccx(), llty) == 0 { + let ptr_unit_ty = type_of::type_of(bcx.ccx(), unit_ty).ptr_to(); + let align = C_uint(bcx.ccx(), 8); + let alloc_result = malloc_raw_dyn(bcx, ptr_unit_ty, vec_ty, ll_len, align); + bcx = alloc_result.bcx; + let base = get_dataptr(bcx, scratch.val); + Store(bcx, alloc_result.val, base); + } else { + let base = get_dataptr(bcx, scratch.val); + let base = PointerCast(bcx, + base, + type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); + bcx = lval.store_to(bcx, base); + } + } + + Store(bcx, ll_len, get_len(bcx, scratch.val)); + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + + fn unsize_unique_expr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum, + k: &ty::UnsizeKind) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + let tcx = bcx.tcx(); + + let datum_ty = datum.ty; + let unboxed_ty = match ty::get(datum_ty).sty { + ty::ty_uniq(t) => t, + _ => bcx.sess().bug(format!("Expected ty_uniq, found {}", + bcx.ty_to_str(datum_ty)).as_slice()) + }; + let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span)); + + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id)); - let (base, len) = datum.get_vec_base_and_len(bcx); + let scratch = rvalue_scratch_datum(bcx, result_ty, "__fat_ptr"); + let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty); + let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to()); + bcx = lval.store_to(bcx, base); - // this type may have a different region/mutability than the - // real one, but it will have the same runtime representation - let slice_ty = ty::mk_slice(tcx, ty::ReStatic, - ty::mt { ty: unit_ty, mutbl: ast::MutImmutable }); + let info = unsized_info(bcx, k, expr.id, unboxed_ty); + Store(bcx, info, get_len(bcx, scratch.val)); - let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust"); - Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock::new(bcx, scratch.to_expr_datum()) } @@ -267,32 +448,6 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, let def = ty::resolve_expr(bcx.tcx(), expr); closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr) } - - fn auto_slice_and_ref<'a>( - bcx: &'a Block<'a>, - expr: &ast::Expr, - datum: Datum) - -> DatumBlock<'a, Expr> { - let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum); - auto_ref(bcx, datum, expr) - } - - fn auto_borrow_obj<'a>(mut bcx: &'a Block<'a>, - expr: &ast::Expr, - source_datum: Datum) - -> DatumBlock<'a, Expr> { - let tcx = bcx.tcx(); - let target_obj_ty = expr_ty_adjusted(bcx, expr); - debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx)); - - // Arrange cleanup, if not already done. This is needed in - // case we are auto-borrowing a Box to &Trait - let datum = unpack_datum!( - bcx, source_datum.to_lvalue_datum(bcx, "autoborrowobj", expr.id)); - let mut datum = datum.to_expr_datum(); - datum.ty = target_obj_ty; - DatumBlock::new(bcx, datum) - } } pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>, @@ -398,20 +553,25 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, ast::ExprIndex(base, idx) => { trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id)) } - ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => { - fcx.push_ast_cleanup_scope(contents.id); - let datum = unpack_datum!( - bcx, tvec::trans_uniq_vstore(bcx, expr, &**contents)); - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); - DatumBlock::new(bcx, datum) - } ast::ExprBox(_, ref contents) => { // Special case for `Box` and `Gc` let box_ty = expr_ty(bcx, expr); let contents_ty = expr_ty(bcx, &**contents); match ty::get(box_ty).sty { ty::ty_uniq(..) => { - trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) + match contents.node { + ast::ExprRepeat(..) | ast::ExprVec(..) => { + // Special case for owned vectors. + fcx.push_ast_cleanup_scope(contents.id); + let datum = unpack_datum!( + bcx, tvec::trans_uniq_vec(bcx, expr, &**contents)); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); + DatumBlock::new(bcx, datum) + } + _ => { + trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) + } + } } ty::ty_box(..) => { trans_managed_expr(bcx, box_ty, &**contents, contents_ty) @@ -419,6 +579,7 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, _ => bcx.sess().span_bug(expr.span, "expected unique or managed box") } + } ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, (**lit).clone()), ast::ExprBinary(op, ref lhs, ref rhs) => { @@ -428,7 +589,19 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, trans_unary(bcx, expr, op, &**x) } ast::ExprAddrOf(_, ref x) => { - trans_addr_of(bcx, expr, &**x) + match x.node { + ast::ExprRepeat(..) | ast::ExprVec(..) => { + // Special case for slices. + fcx.push_ast_cleanup_scope(x.id); + let datum = unpack_datum!( + bcx, tvec::trans_slice_vec(bcx, expr, &**x)); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id); + DatumBlock::new(bcx, datum) + } + _ => { + trans_addr_of(bcx, expr, &**x) + } + } } ast::ExprCast(ref val, _) => { // Datum output mode means this is a scalar cast: @@ -454,14 +627,28 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_rec_field"); let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field")); - let repr = adt::represent_type(bcx.ccx(), base_datum.ty); - with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| { - let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys); - let d = base_datum.get_element( - field_tys[ix].mt.ty, - |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); + let bare_ty = ty::unopen_type(base_datum.ty); + let repr = adt::represent_type(bcx.ccx(), bare_ty); + with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| { + let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys); + let d = base_datum.get_element( + bcx, + field_tys[ix].mt.ty, + |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix)); + + if ty::type_is_sized(bcx.tcx(), d.ty) { DatumBlock { datum: d.to_expr_datum(), bcx: bcx } - }) + } else { + debug!("nrc: {}", bcx.ty_to_str(d.ty)) + let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), ""); + Store(bcx, d.val, get_dataptr(bcx, scratch.val)); + let info = Load(bcx, get_len(bcx, base_datum.val)); + Store(bcx, info, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + + } + }) } fn trans_index<'a>(bcx: &'a Block<'a>, @@ -727,7 +914,6 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); let mut bcx = bcx; let tcx = bcx.tcx(); - let fcx = bcx.fcx; match expr.node { ast::ExprParen(ref e) => { @@ -772,14 +958,8 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, } } } - ast::ExprVstore(ref contents, ast::ExprVstoreSlice) | - ast::ExprVstore(ref contents, ast::ExprVstoreMutSlice) => { - fcx.push_ast_cleanup_scope(contents.id); - bcx = tvec::trans_slice_vstore(bcx, expr, &**contents, dest); - fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id) - } ast::ExprVec(..) | ast::ExprRepeat(..) => { - tvec::trans_fixed_vstore(bcx, expr, expr, dest) + tvec::trans_fixed_vstore(bcx, expr, dest) } ast::ExprFnBlock(_, ref decl, ref body) | ast::ExprProc(ref decl, ref body) => { @@ -1168,6 +1348,21 @@ pub fn trans_adt<'a>(mut bcx: &'a Block<'a>, fcx.schedule_drop_mem(scope, dest, e_ty); } + for base in optbase.iter() { + // FIXME #6573: is it sound to use the destination's repr on the base? + // And, would it ever be reasonable to be here with discr != 0? + let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base")); + for &(i, t) in base.fields.iter() { + let datum = base_datum.get_element( + bcx, + t, + |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i)); + assert!(ty::type_is_sized(bcx.tcx(), datum.ty)); + let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); + bcx = datum.store_to(bcx, dest); + } + } + adt::trans_set_discr(bcx, &*repr, addr, discr); fcx.pop_custom_cleanup_scope(custom_cleanup_scope); @@ -1301,8 +1496,28 @@ fn trans_addr_of<'a>(bcx: &'a Block<'a>, let _icx = push_ctxt("trans_addr_of"); let mut bcx = bcx; let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of")); - let ty = expr_ty(bcx, expr); - return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock(); + match ty::get(sub_datum.ty).sty { + ty::ty_open(_) => { + // Opened DST value, close to a fat pointer + debug!("Closing fat pointer {}", bcx.ty_to_str(sub_datum.ty)); + + let scratch = rvalue_scratch_datum(bcx, + ty::close_type(bcx.tcx(), sub_datum.ty), + "fat_addr_of"); + let base = Load(bcx, get_dataptr(bcx, sub_datum.val)); + Store(bcx, base, get_dataptr(bcx, scratch.val)); + + let len = Load(bcx, get_len(bcx, sub_datum.val)); + Store(bcx, len, get_len(bcx, scratch.val)); + + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + _ => { + // Sized value, ref to a thin pointer + let ty = expr_ty(bcx, expr); + immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock() + } + } } // Important to get types for both lhs and rhs, because one might be _|_ @@ -1590,15 +1805,18 @@ pub enum cast_kind { cast_other, } -pub fn cast_type_kind(t: ty::t) -> cast_kind { +pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind { match ty::get(t).sty { ty::ty_char => cast_integral, ty::ty_float(..) => cast_float, ty::ty_ptr(..) => cast_pointer, - ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{ - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other, - _ => cast_pointer, - }, + ty::ty_rptr(_, mt) => { + if ty::type_is_sized(tcx, mt.ty) { + cast_pointer + } else { + cast_other + } + } ty::ty_bare_fn(..) => cast_pointer, ty::ty_int(..) => cast_integral, ty::ty_uint(..) => cast_integral, @@ -1618,8 +1836,8 @@ fn trans_imm_cast<'a>(bcx: &'a Block<'a>, let t_in = expr_ty(bcx, expr); let t_out = node_id_type(bcx, id); - let k_in = cast_type_kind(t_in); - let k_out = cast_type_kind(t_out); + let k_in = cast_type_kind(bcx.tcx(), t_in); + let k_out = cast_type_kind(bcx.tcx(), t_out); let s_in = k_in == cast_integral && ty::type_is_signed(t_in); let ll_t_in = type_of::arg_type_of(ccx, t_in); let ll_t_out = type_of::arg_type_of(ccx, t_out); @@ -1807,10 +2025,14 @@ fn deref_once<'a>(bcx: &'a Block<'a>, let r = match ty::get(datum.ty).sty { ty::ty_uniq(content_ty) => { - match ty::get(content_ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) - => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"), - _ => deref_owned_pointer(bcx, expr, datum, content_ty), + if ty::type_is_sized(bcx.tcx(), content_ty) { + deref_owned_pointer(bcx, expr, datum, content_ty) + } else { + // A fat pointer and an opened DST value have the same represenation + // just different types. + DatumBlock::new(bcx, Datum::new(datum.val, + ty::mk_open(bcx.tcx(), content_ty), + datum.kind)) } } @@ -1825,21 +2047,21 @@ fn deref_once<'a>(bcx: &'a Block<'a>, ty::ty_ptr(ty::mt { ty: content_ty, .. }) | ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => { - match ty::get(content_ty).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) - => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"), - _ => { - assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty)); - - let ptr = datum.to_llscalarish(bcx); - - // Always generate an lvalue datum, even if datum.mode is - // an rvalue. This is because datum.mode is only an - // rvalue for non-owning pointers like &T or *T, in which - // case cleanup *is* scheduled elsewhere, by the true - // owner (or, in the case of *T, by the user). - DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr)) - } + if ty::type_is_sized(bcx.tcx(), content_ty) { + let ptr = datum.to_llscalarish(bcx); + + // Always generate an lvalue datum, even if datum.mode is + // an rvalue. This is because datum.mode is only an + // rvalue for non-owning pointers like &T or *T, in which + // case cleanup *is* scheduled elsewhere, by the true + // owner (or, in the case of *T, by the user). + DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr)) + } else { + // A fat pointer and an opened DST value have the same represenation + // just different types. + DatumBlock::new(bcx, Datum::new(datum.val, + ty::mk_open(bcx.tcx(), content_ty), + datum.kind)) } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 8faf27d1aa415..2994378f91caf 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -98,18 +98,14 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) => ty::mk_box(tcx, ty::mk_i8()), - ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => { - match ty::get(typ).sty { - ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => t, - _ => { - let llty = sizing_type_of(ccx, typ); - // `Box` does not allocate. - if llsize_of_alloc(ccx, llty) == 0 { - ty::mk_i8() - } else { - ty::mk_uniq(tcx, ty::mk_i8()) - } - } + ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) + && ty::type_is_sized(tcx, typ) => { + let llty = sizing_type_of(ccx, typ); + // `Box` does not allocate. + if llsize_of_alloc(ccx, llty) == 0 { + ty::mk_i8() + } else { + ty::mk_uniq(tcx, ty::mk_i8()) } } _ => t @@ -276,8 +272,8 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' } ty::ty_uniq(content_ty) => { match ty::get(content_ty).sty { - ty::ty_vec(mt, None) => { - tvec::make_drop_glue_unboxed(bcx, v0, mt.ty) + ty::ty_vec(ty, None) => { + tvec::make_drop_glue_unboxed(bcx, v0, ty) } ty::ty_str => { let unit_ty = ty::sequence_element_type(bcx.tcx(), t); @@ -297,7 +293,13 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' }) } _ => { - let llbox = Load(bcx, v0); + let llval = if ty::type_is_sized(bcx.tcx(), content_ty) { + v0 + } else { + // The Box is a fat pointer + GEPi(bcx, v0, [0, abi::trt_field_box]) + }; + let llbox = Load(bcx, llval); let not_null = IsNotNull(bcx, llbox); with_cond(bcx, not_null, |bcx| { let bcx = drop_ty(bcx, llbox, content_ty); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a9a308fc16d1b..3dc0904041911 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -666,6 +666,26 @@ fn emit_vtable_methods(bcx: &Block, }).collect() } +pub fn vtable_ptr<'a>(bcx: &'a Block<'a>, + id: ast::NodeId, + self_ty: ty::t) -> ValueRef { + let ccx = bcx.ccx(); + let origins = { + let vtable_map = ccx.tcx.vtable_map.borrow(); + // This trait cast might be because of implicit coercion + let adjs = ccx.tcx.adjustments.borrow(); + let adjust = adjs.find(&id); + let method_call = if adjust.is_some() && ty::adjust_is_object(adjust.unwrap()) { + MethodCall::autoobject(id) + } else { + MethodCall::expr(id) + }; + let vres = vtable_map.get(&method_call).get_self().unwrap(); + resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) + }; + get_vtable(bcx, self_ty, origins) +} + pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, datum: Datum, id: ast::NodeId, @@ -688,27 +708,16 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, SaveIn(dest) => dest }; - let ccx = bcx.ccx(); let v_ty = datum.ty; - let llbox_ty = type_of(bcx.ccx(), datum.ty); + let llbox_ty = type_of(bcx.ccx(), v_ty); // Store the pointer into the first half of pair. - let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); - llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to()); + let llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); + let llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to()); bcx = datum.store_to(bcx, llboxdest); // Store the vtable into the second half of pair. - let origins = { - let vtable_map = ccx.tcx.vtable_map.borrow(); - // This trait cast might be because of implicit coercion - let method_call = match ccx.tcx.adjustments.borrow().find(&id) { - Some(&ty::AutoObject(..)) => MethodCall::autoobject(id), - _ => MethodCall::expr(id) - }; - let vres = vtable_map.get(&method_call).get_self().unwrap(); - resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) - }; - let vtable = get_vtable(bcx, v_ty, origins); + let vtable = vtable_ptr(bcx, id, v_ty); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to()); Store(bcx, vtable, llvtabledest); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index fcc1b82787685..7b6d3430ae0dc 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -94,6 +94,7 @@ impl<'a, 'b> Reflector<'a, 'b> { ty::MethodTraitItem(ref method) => (*method).clone(), }; let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone()); + debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_str(tcx, mth_ty)); let v = self.visitor_val; debug!("passing {} args:", args.len()); let mut bcx = self.bcx; @@ -149,13 +150,21 @@ impl<'a, 'b> Reflector<'a, 'b> { ty::ty_float(ast::TyF32) => self.leaf("f32"), ty::ty_float(ast::TyF64) => self.leaf("f64"), + ty::ty_open(_) | ty::ty_str | ty::ty_vec(_, None) | ty::ty_trait(..) => { + // Unfortunately we can't do anything here because at runtime we + // pass around the value by pointer (*u8). But unsized pointers are + // fat and so we can't just cast them to *u8 and back. So we have + // to work with the pointer directly (see ty_rptr/ty_uniq). See + // ty_struct for where this causes issues. + fail!("Can't reflect unsized type") + } + // Should rename to vec_*. - ty::ty_vec(ref mt, Some(sz)) => { - let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice()); - let extra = extra.append(self.c_mt(mt).as_slice()); + ty::ty_vec(ty, Some(sz)) => { + let mut extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice()); + extra.push(self.c_tydesc(ty)); self.visit("evec_fixed", extra.as_slice()) } - ty::ty_vec(..) | ty::ty_str | ty::ty_trait(..) => fail!("unexpected unsized type"), // Should remove mt from box and uniq. ty::ty_box(typ) => { let extra = self.c_mt(&ty::mt { @@ -170,12 +179,6 @@ impl<'a, 'b> Reflector<'a, 'b> { } ty::ty_uniq(typ) => { match ty::get(typ).sty { - ty::ty_vec(ref mt, None) => { - let extra = Vec::new(); - let extra = extra.append(self.c_mt(mt).as_slice()); - self.visit("evec_uniq", extra.as_slice()) - } - ty::ty_str => self.visit("estr_uniq", &[]), ty::ty_trait(..) => { let extra = [ self.c_slice(token::intern_and_get_ident( @@ -183,6 +186,12 @@ impl<'a, 'b> Reflector<'a, 'b> { ]; self.visit("trait", extra); } + // FIXME(15049) allow reflection of Box<[T]>. You'll need to + // restore visit_evec_uniq. + ty::ty_vec(_, None) => { + fail!("Box<[T]> theoretically doesn't exist, so don't try to reflect it") + } + ty::ty_str => fail!("Can't reflect Box which shouldn't be used anyway"), _ => { let extra = self.c_mt(&ty::mt { ty: typ, @@ -194,9 +203,8 @@ impl<'a, 'b> Reflector<'a, 'b> { } ty::ty_rptr(_, ref mt) => { match ty::get(mt.ty).sty { - ty::ty_vec(ref mt, None) => { - let extra = Vec::new(); - let extra = extra.append(self.c_mt(mt).as_slice()); + ty::ty_vec(ty, None) => { + let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl}); self.visit("evec_slice", extra.as_slice()) } ty::ty_str => self.visit("estr_slice", &[]), @@ -266,21 +274,34 @@ impl<'a, 'b> Reflector<'a, 'b> { special_idents::unnamed_field.name; } + // This and the type_is_sized check on individual field types are + // because we cannot reflect unsized types (see note above). We + // just pretend the unsized field does not exist and print nothing. + // This is sub-optimal. + let len = if ty::type_is_sized(tcx, t) { + fields.len() + } else { + assert!(fields.len() > 0); + fields.len() - 1 + }; + let extra = (vec!( self.c_slice( token::intern_and_get_ident(ty_to_string(tcx, t).as_slice())), self.c_bool(named_fields), - self.c_uint(fields.len()) + self.c_uint(len) )).append(self.c_size_and_align(t).as_slice()); self.bracketed("class", extra.as_slice(), |this| { for (i, field) in fields.iter().enumerate() { - let extra = (vec!( - this.c_uint(i), - this.c_slice(token::get_ident(field.ident)), - this.c_bool(named_fields) - )).append(this.c_mt(&field.mt).as_slice()); - this.visit("class_field", extra.as_slice()); + if ty::type_is_sized(tcx, field.mt.ty) { + let extra = (vec!( + this.c_uint(i), + this.c_slice(token::get_ident(field.ident)), + this.c_bool(named_fields) + )).append(this.c_mt(&field.mt).as_slice()); + this.visit("class_field", extra.as_slice()); + } } }) } diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 7b8537b15c555..0ec18977139ed 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -35,12 +35,12 @@ use syntax::parse::token::InternedString; fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_lenl"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len])) + Load(bcx, expr::get_len(bcx, vptr)) } fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef { let _icx = push_ctxt("tvec::get_dataptr"); - Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base])) + Load(bcx, expr::get_dataptr(bcx, vptr)) } pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { @@ -68,7 +68,10 @@ pub fn make_drop_glue_unboxed<'a>( bcx }; - glue::trans_exchange_free(bcx, dataptr, 0, 8) + let not_null = IsNotNull(bcx, dataptr); + with_cond(bcx, not_null, |bcx| { + glue::trans_exchange_free(bcx, dataptr, 0, 8) + }) }) } @@ -92,8 +95,7 @@ impl VecTypes { pub fn trans_fixed_vstore<'a>( bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, + expr: &ast::Expr, dest: expr::Dest) -> &'a Block<'a> { //! @@ -103,49 +105,53 @@ pub fn trans_fixed_vstore<'a>( // to store the array of the suitable size, so all we have to do is // generate the content. - debug!("trans_fixed_vstore(vstore_expr={}, dest={:?})", - bcx.expr_to_string(vstore_expr), dest.to_string(bcx.ccx())); + debug!("trans_fixed_vstore(expr={}, dest={:?})", + bcx.expr_to_string(expr), dest.to_string(bcx.ccx())); - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, expr); return match dest { - Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest), + Ignore => write_content(bcx, &vt, expr, expr, dest), SaveIn(lldest) => { // lldest will have type *[T x N], but we want the type *T, // so use GEP to convert: let lldest = GEPi(bcx, lldest, [0, 0]); - write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest)) + write_content(bcx, &vt, expr, expr, SaveIn(lldest)) } }; } -pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr, - dest: expr::Dest) - -> &'a Block<'a> { +pub fn trans_slice_vec<'a>(bcx: &'a Block<'a>, + slice_expr: &ast::Expr, + content_expr: &ast::Expr) + -> DatumBlock<'a, Expr> { /*! * &[...] allocates memory on the stack and writes the values into it, - * returning a slice (pair of ptr, len). &"..." is similar except that - * the memory can be statically allocated. + * returning the vector (the caller must make the reference). "..." is + * similar except that the memory can be statically allocated and we return + * a reference (strings are always by-ref). */ let fcx = bcx.fcx; let ccx = fcx.ccx; let mut bcx = bcx; - debug!("trans_slice_vstore(vstore_expr={}, dest={})", - bcx.expr_to_string(vstore_expr), dest.to_string(ccx)); + debug!("trans_slice_vec(slice_expr={})", + bcx.expr_to_string(slice_expr)); + + let vec_ty = node_id_type(bcx, slice_expr.id); - // Handle the &"..." case: + // Handle the "..." case (returns a slice since strings are always unsized): match content_expr.node { ast::ExprLit(lit) => { match lit.node { ast::LitStr(ref s, _) => { - return trans_lit_str(bcx, - content_expr, - s.clone(), - dest) + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + bcx = trans_lit_str(bcx, + content_expr, + s.clone(), + SaveIn(scratch.val)); + return DatumBlock::new(bcx, scratch.to_expr_datum()); } _ => {} } @@ -154,11 +160,16 @@ pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, } // Handle the &[...] case: - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); debug!(" vt={}, count={:?}", vt.to_str(ccx), count); let llcount = C_uint(ccx, count); + let fixed_ty = ty::mk_vec(bcx.tcx(), + vt.unit_ty, + Some(count)); + let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to(); + let llfixed = if count == 0 { // Just create a zero-sized alloca to preserve // the non-null invariant of the inner slice ptr @@ -168,33 +179,19 @@ pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>, let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); // Arrange for the backing array to be cleaned up. - let fixed_ty = ty::mk_vec(bcx.tcx(), - ty::mt {ty: vt.unit_ty, - mutbl: ast::MutMutable}, - Some(count)); - let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to(); let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty); let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id); fcx.schedule_lifetime_end(cleanup_scope, llfixed_casted); fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty); // Generate the content into the backing array. - bcx = write_content(bcx, &vt, vstore_expr, + bcx = write_content(bcx, &vt, slice_expr, content_expr, SaveIn(llfixed)); - llfixed + llfixed_casted }; - // Finally, create the slice pair itself. - match dest { - Ignore => {} - SaveIn(lldest) => { - Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); - } - } - - return bcx; + immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock() } pub fn trans_lit_str<'a>( @@ -229,24 +226,23 @@ pub fn trans_lit_str<'a>( } } -pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, - vstore_expr: &ast::Expr, - content_expr: &ast::Expr) - -> DatumBlock<'a, Expr> { +pub fn trans_uniq_vec<'a>(bcx: &'a Block<'a>, + uniq_expr: &ast::Expr, + content_expr: &ast::Expr) + -> DatumBlock<'a, Expr> { /*! * ~[...] and "...".to_string() allocate boxes in the exchange heap and write * the array elements into them. */ - debug!("trans_uniq_vstore(vstore_expr={})", bcx.expr_to_string(vstore_expr)); + debug!("trans_uniq_vec(vstore_expr={})", bcx.expr_to_string(uniq_expr)); let fcx = bcx.fcx; let ccx = fcx.ccx; - let vt = vec_types_from_expr(bcx, vstore_expr); + let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); debug!(" vt={}, count={:?}", vt.to_str(ccx), count); - let llcount = C_uint(ccx, count); - let vec_ty = node_id_type(bcx, vstore_expr.id); + let vec_ty = node_id_type(bcx, uniq_expr.id); let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty)); let fill = Mul(bcx, C_uint(ccx, count), unit_sz); @@ -274,15 +270,19 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>, debug!(" alloc_uniq_vec() returned dataptr={}, len={}", bcx.val_to_str(dataptr), count); - let bcx = write_content(bcx, &vt, vstore_expr, + let bcx = write_content(bcx, &vt, uniq_expr, content_expr, SaveIn(dataptr)); fcx.pop_custom_cleanup_scope(temp_scope); - let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); - Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); - DatumBlock(bcx, scratch.to_expr_datum()) + if ty::type_is_sized(bcx.tcx(), vec_ty) { + immediate_rvalue_bcx(bcx, dataptr, vec_ty).to_expr_datumblock() + } else { + let scratch = rvalue_scratch_datum(bcx, vec_ty, ""); + Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); + Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + DatumBlock::new(bcx, scratch.to_expr_datum()) + } } pub fn write_content<'a>( @@ -439,11 +439,19 @@ pub fn get_fixed_base_and_len(bcx: &Block, let ccx = bcx.ccx(); - let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]); + let base = expr::get_dataptr(bcx, llval); let len = C_uint(ccx, vec_length); (base, len) } +fn get_slice_base_and_len(bcx: &Block, + llval: ValueRef) + -> (ValueRef, ValueRef) { + let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); + let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + (base, len) +} + pub fn get_base_and_len(bcx: &Block, llval: ValueRef, vec_ty: ty::t) @@ -459,15 +467,18 @@ pub fn get_base_and_len(bcx: &Block, let ccx = bcx.ccx(); match ty::get(vec_ty).sty { - ty::ty_vec(_, Some(n)) => { - let base = GEPi(bcx, llval, [0u, 0u]); - (base, C_uint(ccx, n)) - } + ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n), + ty::ty_open(ty) => match ty::get(ty).sty { + ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval), + _ => ccx.sess().bug("unexpected type in get_base_and_len") + }, + + // Only used for pattern matching. ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { - ty::ty_vec(_, None) | ty::ty_str => { - let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); - let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); - (base, len) + ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval), + ty::ty_vec(_, Some(n)) => { + let base = GEPi(bcx, Load(bcx, llval), [0u, 0u]); + (base, C_uint(ccx, n)) } _ => ccx.sess().bug("unexpected type in get_base_and_len"), }, diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index 99850fb93866b..017d61137e4b0 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -231,9 +231,16 @@ impl Type { ], false) } + pub fn vtable_ptr(ccx: &CrateContext) -> Type { + Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to() + } + pub fn opaque_trait(ccx: &CrateContext) -> Type { - let vtable = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to(); - Type::struct_(ccx, [vtable, Type::i8p(ccx)], false) + Type::struct_(ccx, [Type::opaque_trait_data(ccx).ptr_to(), Type::vtable_ptr(ccx)], false) + } + + pub fn opaque_trait_data(ccx: &CrateContext) -> Type { + Type::i8(ccx) } pub fn kind(&self) -> TypeKind { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index bc17824ca328a..9608672928d61 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -15,6 +15,7 @@ use middle::trans::adt; use middle::trans::common::*; use middle::trans::foreign; use middle::ty; +use util::ppaux; use util::ppaux::Repr; use middle::trans::type_::Type; @@ -160,6 +161,11 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { } let llsizingty = match ty::get(t).sty { + _ if !ty::lltype_is_sized(cx.tcx(), t) => { + cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + } + ty::ty_nil | ty::ty_bot => Type::nil(cx), ty::ty_bool => Type::bool(cx), ty::ty_char => Type::char(cx), @@ -170,20 +176,18 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(..) | ty::ty_ptr(..) => Type::i8p(cx), ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { - match ty::get(ty).sty { - ty::ty_vec(_, None) | ty::ty_str => { - Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) - } - ty::ty_trait(..) => Type::opaque_trait(cx), - _ => Type::i8p(cx), + if ty::type_is_sized(cx.tcx(), ty) { + Type::i8p(cx) + } else { + Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) } } ty::ty_bare_fn(..) => Type::i8p(cx), ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false), - ty::ty_vec(mt, Some(size)) => { - Type::array(&sizing_type_of(cx, mt.ty), size as u64) + ty::ty_vec(ty, Some(size)) => { + Type::array(&sizing_type_of(cx, ty), size as u64) } ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => { @@ -202,11 +206,15 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { } } - ty::ty_infer(..) | ty::ty_param(..) | - ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => { - cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()", - ty::get(t).sty).as_slice()) + ty::ty_open(_) => { + Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false) + } + + ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => { + cx.sess().bug(format!("fictitious type {} in sizing_type_of()", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) } + ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => fail!("unreachable") }; cx.llsizingtypes.borrow_mut().insert(t, llsizingty); @@ -223,13 +231,22 @@ pub fn arg_type_of(cx: &CrateContext, t: ty::t) -> Type { // NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { + fn type_of_unsize_info(cx: &CrateContext, t: ty::t) -> Type { + match ty::get(ty::unsized_part_of_type(cx.tcx(), t)).sty { + ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU), + ty::ty_trait(_) => Type::vtable_ptr(cx), + _ => fail!("Unexpected type returned from unsized_part_of_type : {}", + t.repr(cx.tcx())) + } + } + // Check the cache. match cx.lltypes.borrow().find(&t) { Some(&llty) => return llty, None => () } - debug!("type_of {} {:?}", t.repr(cx.tcx()), t); + debug!("type_of {} {:?}", t.repr(cx.tcx()), ty::get(t).sty); // Replace any typedef'd types with their equivalent non-typedef // type. This ensures that all LLVM nominal types that contain @@ -281,24 +298,33 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { match ty::get(ty).sty { - ty::ty_vec(mt, None) => { - let p_ty = type_of(cx, mt.ty).ptr_to(); - let u_ty = Type::uint_from_ty(cx, ast::TyU); - Type::struct_(cx, [p_ty, u_ty], false) - } ty::ty_str => { - // This means we get a nicer name in the output + // This means we get a nicer name in the output (str is always + // unsized). cx.tn.find_type("str_slice").unwrap() } ty::ty_trait(..) => Type::opaque_trait(cx), + _ if !ty::type_is_sized(cx.tcx(), ty) => { + let p_ty = type_of(cx, ty).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, ty)], false) + } _ => type_of(cx, ty).ptr_to(), } } - ty::ty_vec(ref mt, Some(n)) => { - Type::array(&type_of(cx, mt.ty), n as u64) + ty::ty_vec(ty, Some(n)) => { + Type::array(&type_of(cx, ty), n as u64) + } + ty::ty_vec(ty, None) => { + type_of(cx, ty) } + ty::ty_trait(..) => { + Type::opaque_trait_data(cx) + } + + ty::ty_str => Type::i8(cx), + ty::ty_bare_fn(_) => { type_of_fn_from_ty(cx, t).ptr_to() } @@ -326,12 +352,27 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { } } - ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"), - ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"), - ty::ty_trait(..) => cx.sess().bug("type_of with unsized ty_trait"), + ty::ty_open(t) => match ty::get(t).sty { + ty::ty_struct(..) => { + let p_ty = type_of(cx, t).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_vec(ty, None) => { + let p_ty = type_of(cx, ty).ptr_to(); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_str => { + let p_ty = Type::i8p(cx); + Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false) + } + ty::ty_trait(..) => Type::opaque_trait(cx), + _ => cx.sess().bug(format!("ty_open with sized type: {}", + ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + }, + ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), ty::ty_param(..) => cx.sess().bug("type_of with ty_param"), - ty::ty_err(..) => cx.sess().bug("type_of with ty_err") + ty::ty_err(..) => cx.sess().bug("type_of with ty_err"), }; debug!("--> mapped t={} {:?} to llty={}", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c00c462afae30..486ed71457471 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -263,37 +263,141 @@ pub enum Variance { #[deriving(Clone)] pub enum AutoAdjustment { AutoAddEnv(ty::TraitStore), - AutoDerefRef(AutoDerefRef), - AutoObject(ty::TraitStore, - ty::BuiltinBounds, - ast::DefId, /* Trait ID */ - subst::Substs /* Trait substitutions */) + AutoDerefRef(AutoDerefRef) } -#[deriving(Clone, Decodable, Encodable)] +#[deriving(Clone, PartialEq)] +pub enum UnsizeKind { + // [T, ..n] -> [T], the uint field is n. + UnsizeLength(uint), + // An unsize coercion applied to the tail field of a struct. + // The uint is the index of the type parameter which is unsized. + UnsizeStruct(Box, uint), + UnsizeVtable(ty::BuiltinBounds, + ast::DefId, /* Trait ID */ + subst::Substs /* Trait substitutions */) +} + +#[deriving(Clone)] pub struct AutoDerefRef { pub autoderefs: uint, pub autoref: Option } -#[deriving(Clone, Decodable, Encodable, PartialEq, Show)] +#[deriving(Clone, PartialEq)] pub enum AutoRef { /// Convert from T to &T - AutoPtr(Region, ast::Mutability), + /// The third field allows us to wrap other AutoRef adjustments. + AutoPtr(Region, ast::Mutability, Option>), - /// Convert from ~[]/&[] to &[] or str - AutoBorrowVec(Region, ast::Mutability), + /// Convert [T, ..n] to [T] (or similar, depending on the kind) + AutoUnsize(UnsizeKind), - /// Convert from ~[]/&[] to &&[] or str - AutoBorrowVecRef(Region, ast::Mutability), + /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. + /// With DST and Box a library type, this should be replaced by UnsizeStruct. + AutoUnsizeUniq(UnsizeKind), /// Convert from T to *T + /// Value to thin pointer AutoUnsafe(ast::Mutability), +} + +// Ugly little helper function. The bool in the returned tuple is true if there +// is an 'unsize to trait object' adjustment at the bottom of the adjustment. If +// that is surrounded by an AutoPtr, then we also return the region of the +// AutoPtr (in the third argument). The second bool is true if the adjustment is +// unique. +fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { + fn unsize_kind_region(k: &UnsizeKind) -> (bool, bool, Option) { + match k { + &UnsizeVtable(..) => (true, false, None), + &UnsizeStruct(box ref k, _) => unsize_kind_region(k), + _ => (false, false, None) + } + } + + match autoref { + &AutoUnsize(ref k) => unsize_kind_region(k), + &AutoUnsizeUniq(ref k) => match k { + &UnsizeVtable(..) => (true, true, None), + _ => (false, false, None) + }, + &AutoPtr(adj_r, _, Some(box ref autoref)) => { + let (b, u, r) = autoref_object_region(autoref); + if r.is_some() || u { + (b, u, r) + } else { + (b, u, Some(adj_r)) + } + } + _ => (false, false, None) + } +} + +// If the adjustment introduces a borrowed reference to a trait object, then +// returns the region of the borrowed reference. +pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option { + match adj { + &AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { + let (b, _, r) = autoref_object_region(autoref); + if b { + r + } else { + None + } + } + _ => None + } +} + +// Returns true if there is a trait cast at the bottom of the adjustment. +pub fn adjust_is_object(adj: &AutoAdjustment) -> bool { + match adj { + &AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { + let (b, _, _) = autoref_object_region(autoref); + b + } + _ => false + } +} + +// If possible, returns the type expected from the given adjustment. This is not +// possible if the adjustment depends on the type of the adjusted expression. +pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { + fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { + match autoref { + &AutoUnsize(ref k) => match k { + &UnsizeVtable(bounds, def_id, ref substs) => { + Some(mk_trait(cx, def_id, substs.clone(), bounds)) + } + _ => None + }, + &AutoUnsizeUniq(ref k) => match k { + &UnsizeVtable(bounds, def_id, ref substs) => { + Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) + } + _ => None + }, + &AutoPtr(r, m, Some(box ref autoref)) => { + match type_of_autoref(cx, autoref) { + Some(t) => Some(mk_rptr(cx, r, mt {mutbl: m, ty: t})), + None => None + } + } + _ => None + } + } - /// Convert from Box/&Trait to &Trait - AutoBorrowObj(Region, ast::Mutability), + match adj { + &AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { + type_of_autoref(cx, autoref) + } + _ => None + } } + + /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. pub struct TransmuteRestriction { @@ -802,7 +906,7 @@ pub enum sty { ty_box(t), ty_uniq(t), ty_str, - ty_vec(mt, Option), // Second field is length. + ty_vec(t, Option), // Second field is length. ty_ptr(mt), ty_rptr(Region, mt), ty_bare_fn(BareFnTy), @@ -813,6 +917,12 @@ pub enum sty { ty_tup(Vec), ty_param(ParamTy), // type parameter + ty_open(t), // A deref'ed fat pointer, i.e., a dynamically sized value + // and its size. Only ever used in trans. It is not necessary + // earlier since we don't need to distinguish a DST with its + // size (e.g., in a deref) vs a DST with the size elsewhere ( + // e.g., in a field). + ty_infer(InferTy), // something used only during inference/typeck ty_err, // Also only used during inference/typeck, to represent // the type of an erroneous expression (helps cut down @@ -1377,10 +1487,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_trait(box ty::TyTrait { ref substs, .. }) => { flags |= sflags(substs); } - &ty_box(tt) | &ty_uniq(tt) => { + &ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => { flags |= get(tt).flags } - &ty_ptr(ref m) | &ty_vec(ref m, _) => { + &ty_ptr(ref m) => { flags |= get(m.ty).flags; } &ty_rptr(r, ref m) => { @@ -1558,14 +1668,14 @@ pub fn mk_nil_ptr(cx: &ctxt) -> t { mk_ptr(cx, mt {ty: mk_nil(), mutbl: ast::MutImmutable}) } -pub fn mk_vec(cx: &ctxt, tm: mt, sz: Option) -> t { - mk_t(cx, ty_vec(tm, sz)) +pub fn mk_vec(cx: &ctxt, t: t, sz: Option) -> t { + mk_t(cx, ty_vec(t, sz)) } pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t { mk_rptr(cx, r, mt { - ty: mk_vec(cx, tm, None), + ty: mk_vec(cx, tm.ty, None), mutbl: tm.mutbl }) } @@ -1643,6 +1753,8 @@ pub fn mk_param_from_def(cx: &ctxt, def: &TypeParameterDef) -> t { mk_param(cx, def.space, def.index, def.def_id) } +pub fn mk_open(cx: &ctxt, t: t) -> t { mk_t(cx, ty_open(t)) } + pub fn walk_ty(ty: t, f: |t|) { maybe_walk_ty(ty, |t| { f(t); true }); } @@ -1653,10 +1765,9 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(..) | - ty_err => {} - ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f), - ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { + ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => {} + ty_box(ty) | ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f), + ty_ptr(ref tm) | ty_rptr(_, ref tm) => { maybe_walk_ty(tm.ty, f); } ty_enum(_, ref substs) | ty_struct(_, ref substs) | @@ -1775,14 +1886,11 @@ pub fn type_is_simd(cx: &ctxt, ty: t) -> bool { pub fn sequence_element_type(cx: &ctxt, ty: t) -> t { match get(ty).sty { - ty_vec(mt, _) => mt.ty, - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => mt.ty, - ty_str => mk_mach_uint(ast::TyU8), - _ => cx.sess.bug("sequence_element_type called on non-sequence value"), - }, - _ => cx.sess.bug("sequence_element_type called on non-sequence value"), + ty_vec(ty, _) => ty, + ty_str => mk_mach_uint(ast::TyU8), + ty_open(ty) => sequence_element_type(cx, ty), + _ => cx.sess.bug(format!("sequence_element_type called on non-sequence value: {}", + ty_to_string(cx, ty)).as_slice()), } } @@ -1815,11 +1923,7 @@ pub fn type_is_boxed(ty: t) -> bool { pub fn type_is_region_ptr(ty: t) -> bool { match get(ty).sty { - ty_rptr(_, mt) => match get(mt.ty).sty { - // DST pointers should not be treated like regular pointers. - ty_vec(_, None) | ty_str | ty_trait(..) => false, - _ => true - }, + ty_rptr(..) => true, _ => false } } @@ -1841,6 +1945,13 @@ pub fn type_is_unique(ty: t) -> bool { } } +pub fn type_is_fat_ptr(cx: &ctxt, ty: t) -> bool { + match get(ty).sty { + ty_rptr(_, mt{ty, ..}) | ty_uniq(ty) if !type_is_sized(cx, ty) => true, + _ => false, + } +} + /* A scalar type is one that denotes an atomic datum, with no sub-components. (A ty_ptr is scalar because it represents a non-managed pointer, so its @@ -2232,7 +2343,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { // Scalar and unique types are sendable, and durable ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_bare_fn(_) | ty::ty_char | ty_str => { + ty_bare_fn(_) | ty::ty_char => { TC::None } @@ -2267,10 +2378,15 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - ty_vec(mt, _) => { - tc_mt(cx, mt, cache) + ty_vec(t, Some(_)) => { + tc_ty(cx, t, cache) } + ty_vec(t, None) => { + tc_ty(cx, t, cache) | TC::Nonsized + } + ty_str => TC::Nonsized, + ty_struct(did, ref substs) => { let flds = struct_fields(cx, did, substs); let mut res = @@ -2370,7 +2486,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { kind_bounds_to_contents(cx, tp_def.bounds.builtin_bounds, tp_def.bounds.trait_bounds.as_slice()) - } + } ty_infer(_) => { // This occurs during coherence, but shouldn't occur at other @@ -2378,6 +2494,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { TC::All } + ty_open(t) => { + let result = tc_ty(cx, t, cache); + assert!(!result.is_sized(cx)) + result.unsafe_pointer() | TC::Nonsized + } + ty_err => { cx.sess.bug("asked to compute contents of error type"); } @@ -2539,7 +2661,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { // normal vectors, since they don't necessarily have the // possibility to have length zero. ty_vec(_, Some(0)) => false, // don't need no contents - ty_vec(mt, Some(_)) => type_requires(cx, seen, r_ty, mt.ty), + ty_vec(ty, Some(_)) => type_requires(cx, seen, r_ty, ty), ty_nil | ty_bot | @@ -2557,7 +2679,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { ty_vec(_, None) => { false } - ty_box(typ) | ty_uniq(typ) => { + ty_box(typ) | ty_uniq(typ) | ty_open(typ) => { type_requires(cx, seen, r_ty, typ) } ty_rptr(_, ref mt) => { @@ -2680,8 +2802,8 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. - ty_vec(mt, Some(_)) => { - type_structurally_recursive(cx, sp, seen, mt.ty) + ty_vec(ty, Some(_)) => { + type_structurally_recursive(cx, sp, seen, ty) } // Push struct and enum def-ids onto `seen` before recursing. @@ -2800,11 +2922,40 @@ pub fn type_is_machine(ty: t) -> bool { } // Is the type's representation size known at compile time? -#[allow(dead_code)] // leaving in for DST -pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool { +pub fn type_is_sized(cx: &ctxt, ty: t) -> bool { type_contents(cx, ty).is_sized(cx) } +pub fn lltype_is_sized(cx: &ctxt, ty: t) -> bool { + match get(ty).sty { + ty_open(_) => true, + _ => type_contents(cx, ty).is_sized(cx) + } +} + +// Return the smallest part of t which is unsized. Fails if t is sized. +// 'Smallest' here means component of the static representation of the type; not +// the size of an object at runtime. +pub fn unsized_part_of_type(cx: &ctxt, ty: t) -> t { + match get(ty).sty { + ty_str | ty_trait(..) | ty_vec(..) => ty, + ty_struct(_, ref substs) => { + // Exactly one of the type parameters must be unsized. + for tp in substs.types.get_vec(subst::TypeSpace).iter() { + if !type_is_sized(cx, *tp) { + return unsized_part_of_type(cx, *tp); + } + } + fail!("Unsized struct type with no unsized type params?"); + } + _ => { + assert!(type_is_sized(cx, ty), + "unsized_part_of_type failed even though ty is unsized"); + fail!("called unsized_part_of_type with sized ty"); + } + } +} + // Whether a type is enum like, that is an enum type with only nullary // constructors pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool { @@ -2827,33 +2978,47 @@ pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool { // Some types---notably unsafe ptrs---can only be dereferenced explicitly. pub fn deref(t: t, explicit: bool) -> Option { match get(t).sty { - ty_box(typ) | ty_uniq(typ) => match get(typ).sty { - // Don't deref ~[] etc., might need to generalise this to all DST. - ty_vec(_, None) | ty_str | ty_trait(..) => None, - _ => Some(mt { - ty: typ, + ty_box(ty) | ty_uniq(ty) => { + Some(mt { + ty: ty, mutbl: ast::MutImmutable, - }), - }, - ty_rptr(_, mt) => match get(mt.ty).sty { - // Don't deref &[], might need to generalise this to all DST. - ty_vec(_, None) | ty_str | ty_trait(..) => None, - _ => Some(mt), + }) }, + ty_rptr(_, mt) => Some(mt), ty_ptr(mt) if explicit => Some(mt), _ => None } } -// Returns the type of t[i] -pub fn index(t: t) -> Option { +pub fn close_type(cx: &ctxt, t: t) -> t { match get(t).sty { - ty_vec(mt, Some(_)) => Some(mt), - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => Some(mt), - _ => None, - }, + ty_open(t) => mk_rptr(cx, ReStatic, mt {ty: t, mutbl:ast::MutImmutable}), + _ => cx.sess.bug(format!("Trying to close a non-open type {}", + ty_to_str(cx, t)).as_slice()) + } +} + +pub fn type_content(t: t) -> t { + match get(t).sty { + ty_box(ty) | ty_uniq(ty) => ty, + ty_rptr(_, mt) |ty_ptr(mt) => mt.ty, + _ => t + } + +} + +// Extract the unsized type in an open type (or just return t if it is not open). +pub fn unopen_type(t: t) -> t { + match get(t).sty { + ty_open(t) => t, + _ => t + } +} + +// Returns the type of t[i] +pub fn index(ty: t) -> Option { + match get(ty).sty { + ty_vec(t, _) => Some(t), _ => None } } @@ -2861,15 +3026,10 @@ pub fn index(t: t) -> Option { // Returns the type of elements contained within an 'array-like' type. // This is exactly the same as the above, except it supports strings, // which can't actually be indexed. -pub fn array_element_ty(t: t) -> Option { - match get(t).sty { - ty_vec(mt, Some(_)) => Some(mt), - ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | - ty_box(t) | ty_uniq(t) => match get(t).sty { - ty_vec(mt, None) => Some(mt), - ty_str => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}), - _ => None, - }, +pub fn array_element_ty(t: t) -> Option { + match get(ty).sty { + ty_vec(t, _) => Some(t), + ty_str => Some(ty: mk_u8()), _ => None } } @@ -3152,56 +3312,7 @@ pub fn adjust_ty(cx: &ctxt, match adj.autoref { None => adjusted_ty, - Some(ref autoref) => { - match *autoref { - AutoPtr(r, m) => { - mk_rptr(cx, r, mt { - ty: adjusted_ty, - mutbl: m - }) - } - - AutoBorrowVec(r, m) => { - borrow_vec(cx, span, r, m, adjusted_ty) - } - - AutoBorrowVecRef(r, m) => { - adjusted_ty = borrow_vec(cx, - span, - r, - m, - adjusted_ty); - mk_rptr(cx, r, mt { - ty: adjusted_ty, - mutbl: ast::MutImmutable - }) - } - - AutoUnsafe(m) => { - mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) - } - - AutoBorrowObj(r, m) => { - borrow_obj(cx, span, r, m, adjusted_ty) - } - } - } - } - } - - AutoObject(store, bounds, def_id, ref substs) => { - - let tr = mk_trait(cx, def_id, substs.clone(), bounds); - match store { - UniqTraitStore => { - mk_uniq(cx, tr) - } - RegionTraitStore(r, m) => { - mk_rptr(cx, r, mt { - ty: tr, - mutbl: m - }) - } + Some(ref autoref) => adjust_for_autoref(cx, span, adjusted_ty, autoref) } } } @@ -3209,57 +3320,64 @@ pub fn adjust_ty(cx: &ctxt, None => unadjusted_ty }; - fn borrow_vec(cx: &ctxt, - span: Span, - r: Region, - m: ast::Mutability, - ty: ty::t) -> ty::t { - match get(ty).sty { - ty_uniq(t) | ty_ptr(mt{ty: t, ..}) | - ty_rptr(_, mt{ty: t, ..}) => match get(t).sty { - ty::ty_vec(mt, None) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}), - ty::ty_str => ty::mk_str_slice(cx, r, m), - _ => { - cx.sess.span_bug( - span, - format!("borrow-vec associated with bad sty: {:?}", - get(ty).sty).as_slice()); - } - }, - ty_vec(mt, Some(_)) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}), + fn adjust_for_autoref(cx: &ctxt, + span: Span, + ty: ty::t, + autoref: &AutoRef) -> ty::t{ + match *autoref { + AutoPtr(r, m, ref a) => { + let adjusted_ty = match a { + &Some(box ref a) => adjust_for_autoref(cx, span, ty, a), + &None => ty + }; + mk_rptr(cx, r, mt { + ty: adjusted_ty, + mutbl: m + }) + } - ref s => { - cx.sess.span_bug( - span, - format!("borrow-vec associated with bad sty: {:?}", - s).as_slice()); + AutoUnsafe(m) => { + mk_ptr(cx, mt {ty: ty, mutbl: m}) } + + AutoUnsize(ref k) => unsize_ty(cx, ty, k, span), + AutoUnsizeUniq(ref k) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)), } } +} - fn borrow_obj(cx: &ctxt, span: Span, r: Region, - m: ast::Mutability, ty: ty::t) -> ty::t { - match get(ty).sty { - ty_uniq(t) | ty_rptr(_, mt{ty: t, ..}) => match get(t).sty { - ty_trait(box ty::TyTrait {def_id, ref substs, bounds, .. }) => { - mk_rptr(cx, r, mt { - ty: ty::mk_trait(cx, def_id, substs.clone(), bounds), - mutbl: m - }) - } - _ => { - cx.sess.span_bug( - span, - format!("borrow-trait-obj associated with bad sty: {:?}", - get(ty).sty).as_slice()); - } - }, - ref s => { - cx.sess.span_bug( - span, - format!("borrow-trait-obj associated with bad sty: {:?}", - s).as_slice()); +// Take a sized type and a sizing adjustment and produce an unsized version of +// the type. +pub fn unsize_ty(cx: &ctxt, + ty: ty::t, + kind: &UnsizeKind, + span: Span) + -> ty::t { + match kind { + &UnsizeLength(len) => match get(ty).sty { + ty_vec(t, Some(n)) => { + assert!(len == n); + mk_vec(cx, t, None) + } + _ => cx.sess.span_bug(span, + format!("UnsizeLength with bad sty: {}", + ty_to_str(cx, ty)).as_slice()) + }, + &UnsizeStruct(box ref k, tp_index) => match get(ty).sty { + ty_struct(did, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let old_ty = ty_substs.get(tp_index); + let new_ty = unsize_ty(cx, *old_ty, k, span); + let mut unsized_substs = substs.clone(); + *unsized_substs.types.get_mut_vec(subst::TypeSpace).get_mut(tp_index) = new_ty; + mk_struct(cx, did, unsized_substs) } + _ => cx.sess.span_bug(span, + format!("UnsizeStruct with bad sty: {}", + ty_to_str(cx, ty)).as_slice()) + }, + &UnsizeVtable(bounds, def_id, ref substs) => { + mk_trait(cx, def_id, substs.clone(), bounds) } } } @@ -3267,11 +3385,11 @@ pub fn adjust_ty(cx: &ctxt, impl AutoRef { pub fn map_region(&self, f: |Region| -> Region) -> AutoRef { match *self { - ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m), - ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m), - ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m), + ty::AutoPtr(r, m, None) => ty::AutoPtr(f(r), m, None), + ty::AutoPtr(r, m, Some(ref a)) => ty::AutoPtr(f(r), m, Some(box a.map_region(f))), + ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), + ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), ty::AutoUnsafe(m) => ty::AutoUnsafe(m), - ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(f(r), m), } } } @@ -3422,8 +3540,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprUnboxedFn(..) | ast::ExprBlock(..) | ast::ExprRepeat(..) | - ast::ExprVstore(_, ast::ExprVstoreSlice) | - ast::ExprVstore(_, ast::ExprVstoreMutSlice) | ast::ExprVec(..) => { RvalueDpsExpr } @@ -3473,8 +3589,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLit(_) | // Note: LitStr is carved out above ast::ExprUnary(..) | ast::ExprAddrOf(..) | - ast::ExprBinary(..) | - ast::ExprVstore(_, ast::ExprVstoreUniq) => { + ast::ExprBinary(..) => { RvalueDatumExpr } @@ -3579,6 +3694,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { } } ty_err => "type error".to_string(), + ty_open(_) => "opened DST".to_string(), } } @@ -4940,15 +5056,12 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { ty_uniq(_) => { byte!(10); } - ty_vec(m, Some(n)) => { + ty_vec(_, Some(n)) => { byte!(11); - mt(&mut state, m); n.hash(&mut state); - 1u8.hash(&mut state); } - ty_vec(m, None) => { + ty_vec(_, None) => { byte!(11); - mt(&mut state, m); 0u8.hash(&mut state); } ty_ptr(m) => { @@ -4997,6 +5110,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { hash!(p.idx); did(&mut state, p.def_id); } + ty_open(_) => byte!(22), ty_infer(_) => unreachable!(), ty_err => byte!(23), ty_unboxed_closure(d, r) => { diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 9f475bfd9d5d0..b246b5ce7a952 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -360,8 +360,11 @@ pub fn super_fold_sty(this: &mut T, ty::ty_ptr(ref tm) => { ty::ty_ptr(tm.fold_with(this)) } - ty::ty_vec(ref tm, sz) => { - ty::ty_vec(tm.fold_with(this), sz) + ty::ty_vec(typ, sz) => { + ty::ty_vec(typ.fold_with(this), sz) + } + ty::ty_open(typ) => { + ty::ty_open(typ.fold_with(this)) } ty::ty_enum(tid, ref substs) => { ty::ty_enum(tid, substs.fold_with(this)) @@ -420,11 +423,13 @@ pub fn super_fold_autoref(this: &mut T, -> ty::AutoRef { match *autoref { - ty::AutoPtr(r, m) => ty::AutoPtr(r.fold_with(this), m), - ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(r.fold_with(this), m), - ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(r.fold_with(this), m), + ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), + ty::AutoPtr(r, m, Some(ref a)) => { + ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, a.clone()))) + } ty::AutoUnsafe(m) => ty::AutoUnsafe(m), - ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(r.fold_with(this), m), + ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), + ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 129a039a267ba..08e78b35e4d58 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -398,10 +398,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option { Some(ty::mk_mach_float(ft)) } ast::TyStr => { - span_err!(tcx.sess, ast_ty.span, E0037, - "bare `str` is not a type"); - // return /something/ so they can at least get more errors - Some(ty::mk_uniq(tcx, ty::mk_str(tcx))) + Some(ty::mk_str(tcx)) } } } @@ -462,21 +459,7 @@ pub fn ast_ty_to_builtin_ty { - span_err!(this.tcx().sess, path.span, E0111, - "`Box` is not a type"); - ty::mk_err() - } - ty::ty_vec(_, None) => { - span_err!(this.tcx().sess, path.span, E0112, - "`Box<[T]>` is not a type"); - ty::mk_err() - } - _ => ty::mk_uniq(this.tcx(), typ), - } - })) + |typ| ty::mk_uniq(this.tcx(), typ))); } span_err!(this.tcx().sess, path.span, E0113, "not enough type parameters supplied to `Box`"); @@ -537,12 +520,6 @@ enum PointerTy { Uniq } -fn ast_ty_to_mt(this: &AC, - rscope: &RS, - ty: &ast::Ty) -> ty::mt { - ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable} -} - pub fn trait_ref_for_unboxed_function( this: &AC, @@ -601,11 +578,8 @@ fn mk_pointer { - let mut mt = ast_ty_to_mt(this, rscope, &**ty); - if a_seq_ty.mutbl == ast::MutMutable { - mt.mutbl = ast::MutMutable; - } - return constr(ty::mk_vec(tcx, mt, None)); + let ty = ast_ty_to_ty(this, rscope, &**ty); + return constr(ty::mk_vec(tcx, ty, None)); } ast::TyUnboxedFn(ref unboxed_function) => { let ty::TraitRef { @@ -662,37 +636,33 @@ fn mk_pointer { let result = ast_path_to_trait_ref( this, rscope, trait_def_id, None, path); - let trait_store = match ptr_ty { - Uniq => ty::UniqTraitStore, - RPtr(r) => { - ty::RegionTraitStore(r, a_seq_ty.mutbl) - } - _ => { - tcx.sess.span_err( - path.span, - "~trait or &trait are the only supported \ - forms of casting-to-trait"); - return ty::mk_err(); - } + let static_region = match ptr_ty { + RPtr(r) if r == ty::ReStatic => true, + _ => false }; let bounds = conv_builtin_bounds(this.tcx(), path.span, bounds, - trait_store); + static_region); let tr = ty::mk_trait(tcx, result.def_id, result.substs.clone(), bounds); - // We could just match on ptr_ty, but we need to pass a trait - // store to conv_builtin_bounds, so mathc twice for now. - return match trait_store { - ty::UniqTraitStore => { + return match ptr_ty { + Uniq => { return ty::mk_uniq(tcx, tr); } - ty::RegionTraitStore(r, m) => { - return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr}); + RPtr(r) => { + return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_ty.mutbl, ty: tr}); } - } + _ => { + tcx.sess.span_err( + path.span, + "~trait or &trait are the only supported \ + forms of casting-to-trait"); + return ty::mk_err(); + } + }; } _ => {} } @@ -738,10 +708,7 @@ pub fn ast_ty_to_ty( |ty| ty::mk_uniq(tcx, ty)) } ast::TyVec(ty) => { - tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type"); - // return /something/ so they can at least get more errors - let vec_ty = ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), None); - ty::mk_uniq(tcx, vec_ty) + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), None) } ast::TyPtr(ref mt) => { ty::mk_ptr(tcx, ty::mt { @@ -777,15 +744,14 @@ pub fn ast_ty_to_ty( let bound_region = opt_ast_region_to_region(this, rscope, ast_ty.span, region); - let store = ty::RegionTraitStore(bound_region, ast::MutMutable); - // Use corresponding trait store to figure out default bounds // if none were specified. let bounds = conv_builtin_bounds(this.tcx(), ast_ty.span, &f.bounds, - store); + bound_region == ty::ReStatic); + let store = ty::RegionTraitStore(bound_region, ast::MutMutable); let fn_decl = ty_of_closure(this, ast_ty.id, f.fn_style, @@ -803,7 +769,7 @@ pub fn ast_ty_to_ty( let bounds = conv_builtin_bounds(this.tcx(), ast_ty.span, &f.bounds, - ty::UniqTraitStore); + false); let fn_decl = ty_of_closure(this, ast_ty.id, @@ -841,15 +807,17 @@ pub fn ast_ty_to_ty( _ => { }, } match a_def { - def::DefTrait(_) => { - let path_str = path_to_string(path); - tcx.sess.span_err( - ast_ty.span, - format!("reference to trait `{name}` where a \ - type is expected; try `Box<{name}>` or \ - `&{name}`", - name=path_str).as_slice()); - ty::mk_err() + def::DefTrait(trait_def_id) => { + let result = ast_path_to_trait_ref( + this, rscope, trait_def_id, None, path); + let bounds = conv_builtin_bounds(this.tcx(), + path.span, + bounds, + false); + ty::mk_trait(tcx, + result.def_id, + result.substs.clone(), + bounds) } def::DefTy(did) | def::DefStruct(did) => { ast_path_to_ty(this, rscope, did, path).ty @@ -887,10 +855,10 @@ pub fn ast_ty_to_ty( Ok(ref r) => { match *r { const_eval::const_int(i) => - ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), Some(i as uint)), const_eval::const_uint(i) => - ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), + ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), Some(i as uint)), _ => { tcx.sess.span_fatal( @@ -1211,7 +1179,7 @@ pub fn ty_of_closure( fn conv_builtin_bounds(tcx: &ty::ctxt, span: Span, ast_bounds: &Option>, - store: ty::TraitStore) + static_region: bool) -> ty::BuiltinBounds { //! Converts a list of bounds from the AST into a `BuiltinBounds` //! struct. Reports an error if any of the bounds that appear @@ -1224,8 +1192,8 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, //! override this with an empty bounds list, e.g. "Box" or //! "Box". - match (ast_bounds, store) { - (&Some(ref bound_vec), _) => { + match ast_bounds { + &Some(ref bound_vec) => { let mut builtin_bounds = ty::empty_builtin_bounds(); for ast_bound in bound_vec.iter() { match *ast_bound { @@ -1265,12 +1233,10 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, builtin_bounds }, // &'static Trait is sugar for &'static Trait:'static. - (&None, ty::RegionTraitStore(ty::ReStatic, _)) => { + &None if static_region => { let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set } - // No bounds are automatically applied for &'r Trait or ~Trait - (&None, ty::RegionTraitStore(..)) | - (&None, ty::UniqTraitStore) => ty::empty_builtin_bounds(), + &None => ty::empty_builtin_bounds(), } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 18f4607a83cac..77e5fbae6ee1c 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -658,10 +658,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx, pat.span, expected) { - ty::ty_vec(mt, Some(fixed)) => - (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)), + ty::ty_vec(ty, Some(fixed)) => + (ty, default_region_var, ast::MutImmutable, Some(fixed)), ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_vec(mt, None) => { + ty::ty_vec(ty, None) => { fcx.type_error_message(pat.span, |_| { "unique vector patterns are no \ @@ -669,7 +669,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { }, expected, None); - (mt.ty, default_region_var, ast::MutImmutable, None) + (ty, default_region_var, ast::MutImmutable, None) } _ => { check_err("a vector pattern".to_string()); @@ -677,7 +677,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { } }, ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty { - ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None), + ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None), _ => { check_err("a vector pattern".to_string()); return; diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 2359f9d72d2b7..1b10b30b3358e 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -77,3 +77,17 @@ pub fn coerce(fcx: &FnCtxt, sp: Span, expected: ty::t, expr: &ast::Expr) { } } } + +pub fn coerce_with_fn(fcx: &FnCtxt, + sp: Span, + expected: ty::t, + expr: &ast::Expr, + handle_err: |Span, ty::t, ty::t, &ty::type_err|) { + let expr_ty = fcx.expr_ty(expr); + match fcx.mk_assignty(expr, expr_ty, expected) { + result::Ok(()) => { /* ok */ } + result::Err(ref err) => { + handle_err(sp, expected, expr_ty, err); + } + } +} diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 245bbe396fd0d..f3b829e60ca60 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -356,23 +356,14 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); let self_expr_id = self.self_expr.map(|e| e.id); - let (self_ty, autoderefs, result) = + let (_, _, result) = check::autoderef( self.fcx, span, self_ty, self_expr_id, PreferMutLvalue, |self_ty, autoderefs| self.search_step(self_ty, autoderefs)); match result { Some(Some(result)) => Some(result), - _ => { - if self.is_overloaded_deref() { - // If we are searching for an overloaded deref, no - // need to try coercing a `~[T]` to an `&[T]` and - // searching for an overloaded deref on *that*. - None - } else { - self.search_for_autosliced_method(self_ty, autoderefs) - } - } + _ => None } } @@ -408,6 +399,16 @@ impl<'a> LookupContext<'a> { } } + // If we are searching for an overloaded deref, no + // need to try coercing a `~[T]` to an `&[T]` and + // searching for an overloaded deref on *that*. + if !self.is_overloaded_deref() { + match self.search_for_autofatptrd_method(self_ty, autoderefs) { + Some(result) => return Some(Some(result)), + None => {} + } + } + // Don't autoderef if we aren't supposed to. if self.autoderef_receiver == DontAutoderefReceiver { Some(None) @@ -441,13 +442,10 @@ impl<'a> LookupContext<'a> { let span = self.self_expr.map_or(self.span, |e| e.span); check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| { match get(self_ty).sty { - ty_uniq(ty) | ty_rptr(_, mt {ty, ..}) => match get(ty).sty{ - ty_trait(box TyTrait { def_id, ref substs, .. }) => { - self.push_inherent_candidates_from_object(def_id, substs); - self.push_inherent_impl_candidates_for_type(def_id); - } - _ => {} - }, + ty_trait(box TyTrait { def_id, ref substs, .. }) => { + self.push_inherent_candidates_from_object(def_id, substs); + self.push_inherent_impl_candidates_for_type(def_id); + } ty_enum(did, _) | ty_struct(did, _) | ty_unboxed_closure(did, _) => { @@ -830,23 +828,22 @@ impl<'a> LookupContext<'a> { self_ty: ty::t, autoderefs: uint) -> Option { - let (self_ty, auto_deref_ref) = - self.consider_reborrow(self_ty, autoderefs); - // Hacky. For overloaded derefs, there may be an adjustment // added to the expression from the outside context, so we do not store // an explicit adjustment, but rather we hardwire the single deref // that occurs in trans and mem_categorization. - let adjustment = match self.self_expr { - Some(expr) => Some((expr.id, ty::AutoDerefRef(auto_deref_ref))), - None => return None - }; + if self.self_expr.is_none() { + return None; + } + + let (self_ty, auto_deref_ref) = self.consider_reborrow(self_ty, autoderefs); + let adjustment = Some((self.self_expr.unwrap().id, ty::AutoDerefRef(auto_deref_ref))); match self.search_for_method(self_ty) { None => None, Some(method) => { debug!("(searching for autoderef'd method) writing \ - adjustment {:?} for {}", adjustment, self.ty_to_string( self_ty)); + adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty)); match adjustment { Some((self_expr_id, adj)) => { self.fcx.write_adjustment(self_expr_id, adj); @@ -890,16 +887,10 @@ impl<'a> LookupContext<'a> { ty::ty_rptr(_, self_mt) => { let region = self.infcx().next_region_var(infer::Autoref(self.span)); - let (extra_derefs, auto) = match ty::get(self_mt.ty).sty { - ty::ty_vec(_, None) => (0, ty::AutoBorrowVec(region, self_mt.mutbl)), - ty::ty_str => (0, ty::AutoBorrowVec(region, self_mt.mutbl)), - ty::ty_trait(..) => (0, ty::AutoBorrowObj(region, self_mt.mutbl)), - _ => (1, ty::AutoPtr(region, self_mt.mutbl)), - }; (ty::mk_rptr(tcx, region, self_mt), ty::AutoDerefRef { - autoderefs: autoderefs + extra_derefs, - autoref: Some(auto)}) + autoderefs: autoderefs + 1, + autoref: Some(ty::AutoPtr(region, self_mt.mutbl, None))}) } _ => { (self_ty, @@ -920,15 +911,18 @@ impl<'a> LookupContext<'a> { } } - fn auto_slice_vec(&self, mt: ty::mt, autoderefs: uint) -> Option { + // Takes an [T] - an unwrapped DST pointer (either ~ or &) + // [T] to &[T] or &&[T] (note that we started with a &[T] or ~[T] which has + // been implicitly derefed). + fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) -> Option { let tcx = self.tcx(); - debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, mt.ty)); + debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, ty)); // First try to borrow to a slice let entry = self.search_for_some_kind_of_autorefd_method( - AutoBorrowVec, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m,r| ty::mk_slice(tcx, r, - ty::mt {ty:mt.ty, mutbl:m})); + ty::mt {ty:ty, mutbl:m})); if entry.is_some() { return entry; @@ -936,10 +930,11 @@ impl<'a> LookupContext<'a> { // Then try to borrow to a slice *and* borrow a pointer. self.search_for_some_kind_of_autorefd_method( - AutoBorrowVecRef, autoderefs, [MutImmutable, MutMutable], - |m,r| { + |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), + autoderefs, [MutImmutable, MutMutable], + |m, r| { let slice_ty = ty::mk_slice(tcx, r, - ty::mt {ty:mt.ty, mutbl:m}); + ty::mt {ty:ty, mutbl:m}); // NB: we do not try to autoref to a mutable // pointer. That would be creating a pointer // to a temporary pointer (the borrowed @@ -949,22 +944,59 @@ impl<'a> LookupContext<'a> { }) } + // [T, ..len] -> [T] or &[T] or &&[T] + fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option { + let tcx = self.tcx(); + debug!("auto_unsize_vec {}", ppaux::ty_to_str(tcx, ty)); + + // First try to borrow to an unsized vec. + let entry = self.search_for_some_kind_of_autorefd_method( + |_r, _m| AutoUnsize(ty::UnsizeLength(len)), + autoderefs, [MutImmutable, MutMutable], + |_m, _r| ty::mk_vec(tcx, ty, None)); + + if entry.is_some() { + return entry; + } + + // Then try to borrow to a slice. + let entry = self.search_for_some_kind_of_autorefd_method( + |r, m| AutoPtr(r, m, Some(box AutoUnsize(ty::UnsizeLength(len)))), + autoderefs, [MutImmutable, MutMutable], + |m, r| ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m})); + + if entry.is_some() { + return entry; + } + + // Then try to borrow to a slice *and* borrow a pointer. + self.search_for_some_kind_of_autorefd_method( + |r, m| AutoPtr(r, m, + Some(box AutoPtr(r, m, + Some(box AutoUnsize(ty::UnsizeLength(len)))))), + autoderefs, [MutImmutable, MutMutable], + |m, r| { + let slice_ty = ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m}); + ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:MutImmutable}) + }) + } fn auto_slice_str(&self, autoderefs: uint) -> Option { let tcx = self.tcx(); debug!("auto_slice_str"); let entry = self.search_for_some_kind_of_autorefd_method( - AutoBorrowVec, autoderefs, [MutImmutable], - |_m,r| ty::mk_str_slice(tcx, r, MutImmutable)); + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable], + |_m, r| ty::mk_str_slice(tcx, r, MutImmutable)); if entry.is_some() { return entry; } self.search_for_some_kind_of_autorefd_method( - AutoBorrowVecRef, autoderefs, [MutImmutable], - |m,r| { + |r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))), + autoderefs, [MutImmutable], + |m, r| { let slice_ty = ty::mk_str_slice(tcx, r, m); ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:m}) }) @@ -972,6 +1004,7 @@ impl<'a> LookupContext<'a> { // Coerce Box/&Trait instances to &Trait. fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option { + debug!("auto_slice_trait"); match ty::get(ty).sty { ty_trait(box ty::TyTrait { def_id: trt_did, @@ -980,7 +1013,8 @@ impl<'a> LookupContext<'a> { .. }) => { let tcx = self.tcx(); self.search_for_some_kind_of_autorefd_method( - AutoBorrowObj, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), + autoderefs, [MutImmutable, MutMutable], |m, r| { let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b); ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m }) @@ -990,31 +1024,24 @@ impl<'a> LookupContext<'a> { } } - fn search_for_autosliced_method(&self, - self_ty: ty::t, - autoderefs: uint) - -> Option { + fn search_for_autofatptrd_method(&self, + self_ty: ty::t, + autoderefs: uint) + -> Option { /*! * Searches for a candidate by converting things like * `~[]` to `&[]`. */ - debug!("search_for_autosliced_method {}", ppaux::ty_to_string(self.tcx(), self_ty)); + let tcx = self.tcx(); + debug!("search_for_autofatptrd_method {}", ppaux::ty_to_string(tcx, self_ty)); let sty = ty::get(self_ty).sty.clone(); match sty { - ty_rptr(_, mt) => match ty::get(mt.ty).sty { - ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs), - ty_trait(..) => self.auto_slice_trait(mt.ty, autoderefs), - _ => None - }, - ty_uniq(t) => match ty::get(t).sty { - ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs), - ty_str => self.auto_slice_str(autoderefs), - ty_trait(..) => self.auto_slice_trait(t, autoderefs), - _ => None - }, - ty_vec(mt, Some(_)) => self.auto_slice_vec(mt, autoderefs), + ty_vec(ty, Some(len)) => self.auto_unsize_vec(ty, autoderefs, len), + ty_vec(ty, None) => self.auto_slice_vec(ty, autoderefs), + ty_str => self.auto_slice_str(autoderefs), + ty_trait(..) => self.auto_slice_trait(self_ty, autoderefs), ty_closure(..) => { // This case should probably be handled similarly to @@ -1042,10 +1069,10 @@ impl<'a> LookupContext<'a> { ty_param(..) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | - ty_unboxed_closure(..) | ty_tup(..) | + ty_unboxed_closure(..) | ty_tup(..) | ty_open(..) | ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { self.search_for_some_kind_of_autorefd_method( - AutoPtr, autoderefs, [MutImmutable, MutMutable], + |r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable], |m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m})) } @@ -1073,8 +1100,8 @@ impl<'a> LookupContext<'a> { Some(expr) => Some(expr.id), None => { assert_eq!(autoderefs, 0); - assert_eq!(kind(ty::ReEmpty, ast::MutImmutable), - ty::AutoPtr(ty::ReEmpty, ast::MutImmutable)); + assert!(kind(ty::ReEmpty, ast::MutImmutable) == + ty::AutoPtr(ty::ReEmpty, ast::MutImmutable, None)); None } }; @@ -1303,7 +1330,7 @@ impl<'a> LookupContext<'a> { match self.fcx.mk_subty(false, infer::Misc(span), rcvr_ty, transformed_self_ty) { Ok(_) => {} - Err(_) => { + Err(e) => { self.bug(format!( "{} was a subtype of {} but now is not?", self.ty_to_string(rcvr_ty), @@ -1442,17 +1469,15 @@ impl<'a> LookupContext<'a> { match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { match ty::get(mt.ty).sty { - ty::ty_vec(_, None) | ty::ty_str => false, ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { mutability_matches(mt.mutbl, m) && rcvr_matches_object(self_did, candidate) } _ => mutability_matches(mt.mutbl, m) && - rcvr_matches_ty(self.fcx, mt.ty, candidate), + rcvr_matches_ty(self.fcx, mt.ty, candidate) } } - _ => false } } @@ -1462,7 +1487,6 @@ impl<'a> LookupContext<'a> { match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { match ty::get(typ).sty { - ty::ty_vec(_, None) | ty::ty_str => false, ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => { rcvr_matches_object(self_did, candidate) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 02115590c7e10..6d3e001a00b0f 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -560,21 +560,6 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>, check_block_with_expected(&fcx, body, ExpectHasType(ret_ty)); - // We unify the tail expr's type with the - // function result type, if there is a tail expr. - match body.expr { - Some(ref tail_expr) => { - // Special case: we print a special error if there appears - // to be do-block/for-loop confusion - demand::suptype_with_fn(&fcx, tail_expr.span, false, - fcx.ret_ty, fcx.expr_ty(&**tail_expr), - |sp, e, a, s| { - fcx.report_mismatched_return_types(sp, e, a, s); - }); - } - None => {} - } - for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) { fcx.write_ty(input.id, *arg); } @@ -2436,8 +2421,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // The tightest thing we can say is "must unify with // else branch". Note that in the case of a "has type" // constraint, this limitation does not hold. - let expected = expected.only_has_type(); + // If the expected type is just a type variable, then don't use + // an expected type. Otherwise, we might write parts of the type + // when checking the 'then' block which are incompatible with the + // 'else' branch. + let expected = match expected.only_has_type() { + ExpectHasType(ety) => { + match infer::resolve_type(fcx.infcx(), ety, force_tvar) { + Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty), + _ => NoExpectation + } + } + None => None + }; check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); check_expr_with_expectation(fcx, &**else_expr, expected); @@ -3090,76 +3087,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { - ast::ExprVstore(ev, vst) => { - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - let typ = match ev.node { - ast::ExprVec(ref args) => { - let mutability = match vst { - ast::ExprVstoreMutSlice => ast::MutMutable, - _ => ast::MutImmutable, - }; - let mut any_error = false; - let mut any_bot = false; - for e in args.iter() { - check(fcx, &**e, t); - let arg_t = fcx.expr_ty(&**e); - if ty::type_is_error(arg_t) { - any_error = true; - } - else if ty::type_is_bot(arg_t) { - any_bot = true; - } - } - if any_error { - ty::mk_err() - } else if any_bot { - ty::mk_bot() - } else { - ast_expr_vstore_to_ty(fcx, &*ev, vst, || - ty::mt{ ty: ty::mk_vec(tcx, - ty::mt {ty: t, mutbl: mutability}, - None), - mutbl: mutability }) - } - } - ast::ExprRepeat(ref element, ref count_expr) => { - check_expr_with_hint(fcx, &**count_expr, ty::mk_uint()); - let _ = ty::eval_repeat_count(fcx, &**count_expr); - let mutability = match vst { - ast::ExprVstoreMutSlice => ast::MutMutable, - _ => ast::MutImmutable, - }; - check(fcx, &**element, t); - let arg_t = fcx.expr_ty(&**element); - if ty::type_is_error(arg_t) { - ty::mk_err() - } else if ty::type_is_bot(arg_t) { - ty::mk_bot() - } else { - ast_expr_vstore_to_ty(fcx, &*ev, vst, || - ty::mt{ ty: ty::mk_vec(tcx, - ty::mt {ty: t, mutbl: mutability}, - None), - mutbl: mutability}) - } - } - ast::ExprLit(_) => { - if vst == ast::ExprVstoreSlice { - span_err!(tcx.sess, expr.span, E0064, - "`&\"string\"` has been removed; use `\"string\"` instead"); - } else { - span_err!(tcx.sess, expr.span, E0065, - "`box \"string\"` has been removed; use \ - `\"string\".to_string()` instead"); - } - ty::mk_err() - } - _ => tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence"), - }; - fcx.write_ty(ev.id, typ); - fcx.write_ty(id, typ); - } - ast::ExprBox(ref place, ref subexpr) => { check_expr(fcx, &**place); check_expr(fcx, &**subexpr); @@ -3337,22 +3264,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, hint, lvalue_pref); - // Note: at this point, we cannot say what the best lifetime - // is to use for resulting pointer. We want to use the - // shortest lifetime possible so as to avoid spurious borrowck - // errors. Moreover, the longest lifetime will depend on the - // precise details of the value whose address is being taken - // (and how long it is valid), which we don't know yet until type - // inference is complete. - // - // Therefore, here we simply generate a region variable. The - // region inferencer will then select the ultimate value. - // Finally, borrowck is charged with guaranteeing that the - // value whose address was taken can actually be made to live - // as long as it needs to live. - let region = fcx.infcx().next_region_var( - infer::AddrOfRegion(expr.span)); - let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { ty::mk_err() @@ -3360,7 +3271,31 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ty::mk_bot() } else { - ty::mk_rptr(tcx, region, tm) + // Note: at this point, we cannot say what the best lifetime + // is to use for resulting pointer. We want to use the + // shortest lifetime possible so as to avoid spurious borrowck + // errors. Moreover, the longest lifetime will depend on the + // precise details of the value whose address is being taken + // (and how long it is valid), which we don't know yet until type + // inference is complete. + // + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + match oprnd.node { + // String literals are already, implicitly converted to slices. + //ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd), + // Empty slices live in static memory. + ast::ExprVec(ref elements) if elements.len() == 0 => { + ty::mk_rptr(tcx, ty::ReStatic, tm) + } + _ => { + let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span)); + ty::mk_rptr(tcx, region, tm) + } + } }; fcx.write_ty(id, oprnd_t); } @@ -3393,7 +3328,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } }, Some(ref e) => { - check_expr_has_type(fcx, &**e, ret_ty); + //check_expr_has_type(fcx, e, ret_ty); + check_expr_coercable_to_type(fcx, &**e, ret_ty); } } fcx.write_bot(id); @@ -3547,29 +3483,60 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_cast(fcx, &**e, &**t, id, expr.span); } ast::ExprVec(ref args) => { - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - for e in args.iter() { - check(fcx, &**e, t); - } - let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable}, - Some(args.len())); + let uty = unpack_expected( + fcx, expected, + |sty| match *sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + }); + + let typ = match uty { + Some(uty) => { + for e in args.iter() { + check_expr_coercable_to_type(fcx, &**e, uty); + } + uty + } + None => { + let t: ty::t = fcx.infcx().next_ty_var(); + for e in args.iter() { + check_expr_has_type(fcx, &**e, t); + } + t + } + }; + let typ = ty::mk_vec(tcx, typ, Some(args.len())); fcx.write_ty(id, typ); } ast::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &**count_expr, ty::mk_uint()); let count = ty::eval_repeat_count(fcx, &**count_expr); - let (check, t) = check_fn_for_vec_elements_expected(fcx, expected); - check(fcx, &**element, t); - let element_ty = fcx.expr_ty(&**element); + + let uty = unpack_expected( + fcx, expected, + |sty| match *sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + }); + + let (element_ty, t) = match uty { + Some(uty) => { + check_expr_coercable_to_type(fcx, &**element, uty); + (uty, uty) + } + None => { + let t: ty::t = fcx.infcx().next_ty_var(); + check_expr_has_type(fcx, &**element, t); + (fcx.expr_ty(&**element), t) + } + }; + if ty::type_is_error(element_ty) { fcx.write_error(id); - } - else if ty::type_is_bot(element_ty) { + } else if ty::type_is_bot(element_ty) { fcx.write_bot(id); - } - else { - let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable}, - Some(count)); + } else { + let t = ty::mk_vec(tcx, t, Some(count)); fcx.write_ty(id, t); } } @@ -3589,8 +3556,16 @@ fn check_expr_with_unifier(fcx: &FnCtxt, Some(ref fs) if i < fs.len() => ExpectHasType(*fs.get(i)), _ => NoExpectation }; - check_expr_with_expectation(fcx, &**e, opt_hint); - let t = fcx.expr_ty(&**e); + let t = match opt_hint { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &**e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &**e, opt_hint); + fcx.expr_ty(&**e) + } + }; err_field = err_field || ty::type_is_error(t); bot_field = bot_field || ty::type_is_bot(t); t @@ -3702,9 +3677,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt, autoderef(fcx, expr.span, raw_base_t, Some(base.id), lvalue_pref, |base_t, _| ty::index(base_t)); match field_ty { - Some(mt) => { + Some(ty) => { check_expr_has_type(fcx, &**idx, ty::mk_uint()); - fcx.write_ty(id, mt.ty); + fcx.write_ty(id, ty); fcx.write_autoderef_adjustment(base.id, autoderefs); } None => { @@ -3985,15 +3960,23 @@ fn check_block_with_expected(fcx: &FnCtxt, e.span, "unreachable expression".to_string()); } - check_expr_with_expectation(fcx, &*e, expected); - let ety = fcx.expr_ty(&*e); - fcx.write_ty(blk.id, ety); - if any_err { - fcx.write_error(blk.id); - } - else if any_bot { - fcx.write_bot(blk.id); - } + let ety = match expected { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &*e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &*e, expected); + fcx.expr_ty(e) + } + }; + + fcx.write_ty(blk.id, ety); + if any_err { + fcx.write_error(blk.id); + } else if any_bot { + fcx.write_bot(blk.id); + } } }; }); @@ -4040,9 +4023,8 @@ pub fn check_const_with_ty(fcx: &FnCtxt, // emit a error. GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ()); - check_expr(fcx, e); - let cty = fcx.expr_ty(e); - demand::suptype(fcx, e.span, declty, cty); + check_expr_with_hint(fcx, e, declty); + demand::coerce(fcx, e.span, declty, e); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); } @@ -4132,6 +4114,7 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) { } } + pub fn check_enum_variants_sized(ccx: &CrateCtxt, vs: &[ast::P]) { for &v in vs.iter() { @@ -4747,39 +4730,39 @@ pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { return ty::type_is_uint(typ_s); } -pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt, - e: &ast::Expr, - v: ast::ExprVstore, - mk_inner: || -> ty::mt) - -> ty::t { - match v { - ast::ExprVstoreUniq => ty::mk_uniq(fcx.ccx.tcx, mk_inner().ty), - ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => { - match e.node { - ast::ExprLit(..) => { - // string literals and *empty slices* live in static memory - ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()) - } - ast::ExprVec(ref elements) if elements.len() == 0 => { - // string literals and *empty slices* live in static memory - ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()) - } - ast::ExprRepeat(..) | - ast::ExprVec(..) => { - // vector literals are temporaries on the stack - match fcx.tcx().region_maps.temporary_scope(e.id) { - Some(scope) => ty::mk_rptr(fcx.ccx.tcx, ty::ReScope(scope), mk_inner()), - None => ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()), - } - } - _ => { - fcx.ccx.tcx.sess.span_bug(e.span, - "vstore with unexpected \ - contents") - } - } - } - } +pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_scalar(typ_s); +} + +pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_char(typ_s); +} + +pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_bare_fn(typ_s); +} + +pub fn type_is_floating_point(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_floating_point(typ_s); +} + +pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_unsafe_ptr(typ_s); +} + +pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_region_ptr(typ_s); +} + +pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s); } // Returns true if b contains a break that can exit from b diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 3813dd7964244..4f77c89e86c1d 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -413,40 +413,43 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { for &adjustment in rcx.fcx.inh.adjustments.borrow().find(&expr.id).iter() { debug!("adjustment={:?}", adjustment); match *adjustment { - ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => { + ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - for autoref in opt_autoref.iter() { - link_autoref(rcx, expr, autoderefs, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - constrain_regions_in_type_of_node( - rcx, expr.id, ty::ReScope(expr.id), - infer::AutoBorrow(expr.span)); + match ty::adjusted_object_region(adjustment) { + Some(trait_region) => { + // Determine if we are casting `expr` to a trait + // instance. If so, we have to be sure that the type of + // the source obeys the trait's region bound. + // + // Note: there is a subtle point here concerning type + // parameters. It is possible that the type of `source` + // contains type parameters, which in turn may contain + // regions that are not visible to us (only the caller + // knows about them). The kind checker is ultimately + // responsible for guaranteeing region safety in that + // particular case. There is an extensive comment on the + // function check_cast_for_escaping_regions() in kind.rs + // explaining how it goes about doing that. + + constrain_regions_in_type(rcx, trait_region, + infer::RelateObjectBound(expr.span), expr_ty); + } + None => { + for autoref in opt_autoref.iter() { + link_autoref(rcx, expr, autoderefs, autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#6268) remove to support nested method calls + constrain_regions_in_type_of_node( + rcx, expr.id, ty::ReScope(expr.id), + infer::AutoBorrow(expr.span)); + } + } } } - ty::AutoObject(ty::RegionTraitStore(trait_region, _), _, _, _) => { - // Determine if we are casting `expr` to a trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - // - // Note: there is a subtle point here concerning type - // parameters. It is possible that the type of `source` - // contains type parameters, which in turn may contain - // regions that are not visible to us (only the caller - // knows about them). The kind checker is ultimately - // responsible for guaranteeing region safety in that - // particular case. There is an extensive comment on the - // function check_cast_for_escaping_regions() in kind.rs - // explaining how it goes about doing that. - - let source_ty = rcx.resolve_node_type(expr.id); - constrain_regions_in_type(rcx, trait_region, - infer::RelateObjectBound(expr.span), source_ty); - } _ => {} } } @@ -1176,24 +1179,12 @@ fn link_autoref(rcx: &Rcx, debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m) => { - link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), expr_cmt); - } - - ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { - let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1); - link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt_index); - } - - ty::AutoBorrowObj(r, m) => { - let cmt_deref = mc.cat_deref_obj(expr, expr_cmt); + ty::AutoPtr(r, m, _) => { link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt_deref); + ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bc53ed58f6fd5..5b14ee62b0aec 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -10,7 +10,7 @@ use middle::ty; -use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, ParamTy}; +use middle::ty::{AutoDerefRef, ParamTy}; use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, impl_self_ty}; @@ -388,7 +388,6 @@ fn search_for_vtable(vcx: &VtableContext, trait_ref: Rc, is_early: bool) -> Option { - debug!("nrc - search_for_vtable"); let tcx = vcx.tcx(); // First, check to see whether this is a call to the `call` method of an @@ -630,14 +629,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { let _indent = indenter(); let cx = fcx.ccx; - let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t, key: MethodCall| { - // Look up vtables for the type we're casting to, - // passing in the source and target type. The source - // must be a pointer type suitable to the object sigil, - // e.g.: `&x as &Trait` or `box x as Box` - // Bounds of type's contents are not checked here, but in kind.rs. - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(src)); + let check_object_cast = |src_ty: ty::t, target_ty: ty::t| { + // Check that a cast is of correct types. match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) { (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) if !mutability_allowed(mt.mutbl, mutbl) => { @@ -648,74 +641,14 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } - - (&ty::ty_uniq(ty), &ty::ty_uniq(..) ) | - (&ty::ty_rptr(_, ty::mt{ty, ..}), &ty::ty_rptr(..)) => { - match ty::get(ty).sty { - ty::ty_trait(box ty::TyTrait { - def_id: target_def_id, substs: ref target_substs, .. - }) => { - debug!("nrc correct path"); - let typ = match &ty::get(src_ty).sty { - &ty::ty_uniq(typ) => typ, - &ty::ty_rptr(_, mt) => mt.ty, - _ => fail!("shouldn't get here"), - }; - - let vcx = fcx.vtable_context(); - - // Take the type parameters from the object - // type, but set the Self type (which is - // unknown, for the object type) to be the type - // we are casting from. - let mut target_types = target_substs.types.clone(); - assert!(target_types.get_self().is_none()); - target_types.push(subst::SelfSpace, typ); - - let target_trait_ref = Rc::new(ty::TraitRef { - def_id: target_def_id, - substs: subst::Substs { - regions: target_substs.regions.clone(), - types: target_types - } - }); - - let param_bounds = ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(target_trait_ref) - }; - let vtables = - lookup_vtables_for_param(&vcx, - ex.span, - None, - ¶m_bounds, - typ, - is_early); - - if !is_early { - let mut r = VecPerParamSpace::empty(); - r.push(subst::SelfSpace, vtables); - insert_vtables(fcx, key, r); - } - - // Now, if this is &trait, we need to link the - // regions. - match (&ty::get(src_ty).sty, &ty::get(target_ty).sty) { - (&ty::ty_rptr(ra, _), &ty::ty_rptr(rb, _)) => { - debug!("nrc - make subr"); - infer::mk_subr(fcx.infcx(), - false, - infer::RelateObjectBound(ex.span), - rb, - ra); - } - _ => {} - } - } - _ => {} - } + (&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {} + (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { + infer::mk_subr(fcx.infcx(), + false, + infer::RelateObjectBound(ex.span), + r_t, + r_s); } - (&ty::ty_uniq(ty), _) => { match ty::get(ty).sty { ty::ty_trait(..) => { @@ -737,7 +670,55 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } + _ => {} + } + }; + let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| { + // Look up vtables for the type we're casting to, + // passing in the source and target type. The source + // must be a pointer type suitable to the object sigil, + // e.g.: `&x as &Trait` or `box x as Box` + // Bounds of type's contents are not checked here, but in kind.rs. + match ty::get(target_ty).sty { + ty::ty_trait(box ty::TyTrait { + def_id: target_def_id, substs: ref target_substs, .. + }) => { + let vcx = fcx.vtable_context(); + + // Take the type parameters from the object + // type, but set the Self type (which is + // unknown, for the object type) to be the type + // we are casting from. + let mut target_types = target_substs.types.clone(); + assert!(target_types.get_self().is_none()); + target_types.push(subst::SelfSpace, src_ty); + + let target_trait_ref = Rc::new(ty::TraitRef { + def_id: target_def_id, + substs: subst::Substs { + regions: target_substs.regions.clone(), + types: target_types + } + }); + + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::empty_builtin_bounds(), + trait_bounds: vec!(target_trait_ref) + }; + let vtables = + lookup_vtables_for_param(&vcx, + ex.span, + None, + ¶m_bounds, + src_ty, + is_early); + if !is_early { + let mut r = VecPerParamSpace::empty(); + r.push(subst::SelfSpace, vtables); + insert_vtables(fcx, key, r); + } + } _ => {} } }; @@ -792,8 +773,16 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { ast::ExprCast(ref src, _) => { debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); let target_ty = fcx.expr_ty(ex); - let key = MethodCall::expr(ex.id); - resolve_object_cast(&**src, target_ty, key); + let src_ty = structurally_resolved_type(fcx, ex.span, + fcx.expr_ty(&**src)); + check_object_cast(src_ty, target_ty); + match (ty::deref(src_ty, false), ty::deref(target_ty, false)) { + (Some(s), Some(t)) => { + let key = MethodCall::expr(ex.id); + resolve_object_cast(s.ty, t.ty, key) + } + _ => {} + } } _ => () } @@ -802,7 +791,26 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { match fcx.inh.adjustments.borrow().find(&ex.id) { Some(adjustment) => { match *adjustment { - AutoDerefRef(adj) => { + _ if ty::adjust_is_object(adjustment) => { + let src_ty = structurally_resolved_type(fcx, ex.span, + fcx.expr_ty(ex)); + match ty::type_of_adjust(fcx.tcx(), adjustment) { + Some(target_ty) => { + check_object_cast(src_ty, target_ty) + } + None => {} + } + + match trait_cast_types(fcx, adjustment, src_ty, ex.span) { + Some((s, t)) => { + let key = MethodCall::autoobject(ex.id); + resolve_object_cast(s, t, key) + } + None => fail!("Couldn't extract types from adjustment") + } + } + AutoDerefRef(ref adj) => { + assert!(!ty::adjust_is_object(adjustment)); for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(ex.id, autoderef); match fcx.inh.method_map.borrow().find(&method_call) { @@ -823,37 +831,83 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { } } } - AutoObject(store, - bounds, - def_id, - ref substs) => { - debug!("doing trait adjustment for expr {} {} \ - (early? {})", - ex.id, - ex.repr(fcx.tcx()), - is_early); - - let trait_ty = ty::mk_trait(cx.tcx, - def_id, - substs.clone(), - bounds); - let object_ty = match store { - ty::UniqTraitStore => ty::mk_uniq(cx.tcx, trait_ty), - ty::RegionTraitStore(r, m) => { - ty::mk_rptr(cx.tcx, r, ty::mt {ty: trait_ty, mutbl: m}) - } - }; - - let key = MethodCall::autoobject(ex.id); - resolve_object_cast(ex, object_ty, key); + _ => { + assert!(!ty::adjust_is_object(adjustment)); } - AutoAddEnv(..) => {} } } None => {} } } +// When we coerce (possibly implicitly) from a concrete type to a trait type, this +// function returns the concrete type and trait. This might happen arbitrarily +// deep in the adjustment. This function will fail if the adjustment does not +// match the source type. +// This function will always return types if ty::adjust_is_object is true for the +// adjustment +fn trait_cast_types(fcx: &FnCtxt, + adj: &ty::AutoAdjustment, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + fn trait_cast_types_autoref(fcx: &FnCtxt, + autoref: &ty::AutoRef, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + fn trait_cast_types_unsize(fcx: &FnCtxt, + k: &ty::UnsizeKind, + src_ty: ty::t, + sp: Span) + -> Option<(ty::t, ty::t)> { + match k { + &ty::UnsizeVtable(bounds, def_id, ref substs) => { + Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) + } + &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { + ty::ty_struct(_, ref substs) => { + let ty_substs = substs.types.get_vec(subst::TypeSpace); + let field_ty = *ty_substs.get(tp_index); + let field_ty = structurally_resolved_type(fcx, sp, field_ty); + trait_cast_types_unsize(fcx, k, field_ty, sp) + } + _ => fail!("Failed to find a ty_struct to correspond with \ + UnsizeStruct whilst walking adjustment. Found {}", + ppaux::ty_to_str(fcx.tcx(), src_ty)) + }, + _ => None + } + } + + match autoref { + &ty::AutoUnsize(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), + &ty::AutoUnsizeUniq(ref k) => match k { + &ty::UnsizeVtable(bounds, def_id, ref substs) => { + Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) + } + _ => None + }, + &ty::AutoPtr(_, _, Some(box ref autoref)) => { + trait_cast_types_autoref(fcx, autoref, src_ty, sp) + } + _ => None + } + } + + match adj { + &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => { + let mut derefed_type = src_ty; + for _ in range(0, autoderefs) { + derefed_type = ty::deref(derefed_type, false).unwrap().ty; + derefed_type = structurally_resolved_type(fcx, sp, derefed_type) + } + trait_cast_types_autoref(fcx, autoref, derefed_type, sp) + } + _ => None + } +} + pub fn resolve_impl(tcx: &ty::ctxt, impl_item: &ast::Item, impl_generics: &ty::Generics, diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 892a62249ac3b..7951c8dfc1980 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -259,6 +259,7 @@ impl<'cx> WritebackCx<'cx> { } Some(adjustment) => { + let adj_object = ty::adjust_is_object(&adjustment); let resolved_adjustment = match adjustment { ty::AutoAddEnv(store) => { // FIXME(eddyb) #2190 Allow only statically resolved @@ -286,24 +287,17 @@ impl<'cx> WritebackCx<'cx> { self.visit_vtable_map_entry(reason, method_call); } + if adj_object { + let method_call = MethodCall::autoobject(id); + self.visit_method_map_entry(reason, method_call); + self.visit_vtable_map_entry(reason, method_call); + } + ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, autoref: self.resolve(&adj.autoref, reason), }) } - - ty::AutoObject(trait_store, bb, def_id, substs) => { - let method_call = MethodCall::autoobject(id); - self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); - - ty::AutoObject( - self.resolve(&trait_store, reason), - self.resolve(&bb, reason), - def_id, - self.resolve(&substs, reason) - ) - } }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().adjustments.borrow_mut().insert( diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 3dee787b6c906..a6fa9d84600bf 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -23,7 +23,7 @@ use middle::ty::get; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{lookup_item_type}; use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; -use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil}; +use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open}; use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; @@ -86,7 +86,7 @@ fn get_base_type(inference_context: &InferCtxt, ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | + ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { debug!("(getting base type) no base type; found {:?}", get(original_type).sty); @@ -166,6 +166,9 @@ fn get_base_type_def_id(inference_context: &InferCtxt, enum, struct, or trait"); } }, + ty_trait(box ty::TyTrait { def_id, .. }) => { + Some(def_id) + } _ => { fail!("get_base_type() returned a type that wasn't an \ enum, struct, or trait"); diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 03890250f7701..6d0b34e89d679 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur. */ use middle::subst; -use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowObj, AutoDerefRef}; +use middle::ty::{AutoPtr, AutoDerefRef, AutoUnsize}; use middle::ty::{mt}; use middle::ty; use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; @@ -73,6 +73,7 @@ use middle::typeck::infer::combine::{CombineFields, Combine}; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::resolve::try_resolve_tvar_shallow; use util::common::indenter; +use util::ppaux; use util::ppaux::Repr; use syntax::abi; @@ -94,38 +95,51 @@ impl<'f> Coerce<'f> { b.repr(self.get_ref().infcx.tcx)); let _indent = indenter(); + // Special case: if the subtype is a sized array literal (`[T, ..n]`), + // then it would get auto-borrowed to `&[T, ..n]` and then DST-ified + // to `&[T]`. Doing it all at once makes the target code a bit more + // efficient and spares us from having to handle multiple coercions. + match ty::get(b).sty { + ty::ty_rptr(_, mt_b) => { + match ty::get(mt_b.ty).sty { + ty::ty_vec(_, None) => { + let unsize_and_ref = self.unpack_actual_value(a, |sty_a| { + self.coerce_unsized_with_borrow(a, sty_a, b, mt_b.mutbl) + }); + if unsize_and_ref.is_ok() { + return unsize_and_ref; + } + } + _ => {} + } + } + _ => {} + } + + // Consider coercing the subtype to a DST + let unsize = self.unpack_actual_value(a, |sty_a| { + self.coerce_unsized(a, sty_a, b) + }); + if unsize.is_ok() { + return unsize; + } + // Examine the supertype and consider auto-borrowing. // // Note: does not attempt to resolve type variables we encounter. // See above for details. match ty::get(b).sty { - ty::ty_rptr(r_b, mt_b) => { + ty::ty_rptr(_, mt_b) => { match ty::get(mt_b.ty).sty { - ty::ty_vec(mt_b, None) => { - return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_vector(a, sty_a, b, mt_b.mutbl) - }); - } - ty::ty_vec(_, _) => {}, ty::ty_str => { return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_string(a, sty_a, b) + self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable) }); } - ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => { + ty::ty_trait(..) => { let result = self.unpack_actual_value(a, |sty_a| { - match *sty_a { - ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty { - ty::ty_trait(..) => { - self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) - } - _ => self.coerce_object(a, sty_a, b, def_id, substs, - ty::RegionTraitStore(r_b, mt_b.mutbl), - bounds) - }, - _ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) - } + self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl) }); match result { @@ -136,37 +150,12 @@ impl<'f> Coerce<'f> { _ => { return self.unpack_actual_value(a, |sty_a| { - self.coerce_borrowed_pointer(a, sty_a, b, mt_b) + self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl) }); } }; } - ty::ty_uniq(t_b) => { - match ty::get(t_b).sty { - ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => { - let result = self.unpack_actual_value(a, |sty_a| { - match *sty_a { - ty::ty_uniq(t_a) => match ty::get(t_a).sty { - ty::ty_trait(..) => { - Err(ty::terr_mismatch) - } - _ => self.coerce_object(a, sty_a, b, def_id, substs, - ty::UniqTraitStore, bounds) - }, - _ => Err(ty::terr_mismatch) - } - }); - - match result { - Ok(t) => return Ok(t), - Err(..) => {} - } - } - _ => {} - } - } - ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. @@ -221,20 +210,21 @@ impl<'f> Coerce<'f> { self.get_ref().infcx.tcx.sess.span_bug( self.get_ref().trace.origin.span(), format!("failed to resolve even without \ - any force options: {:?}", e).as_slice()); + any force options: {:?}", e).as_slice()); } } } + // ~T -> &T or &mut T -> &T (including where T = [U] or str) pub fn coerce_borrowed_pointer(&self, a: ty::t, sty_a: &ty::sty, b: ty::t, - mt_b: ty::mt) + mutbl_b: ast::Mutability) -> CoerceResult { - debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})", + debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, - b.repr(self.get_ref().infcx.tcx), mt_b); + b.repr(self.get_ref().infcx.tcx)); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -256,64 +246,182 @@ impl<'f> Coerce<'f> { let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, - mt {ty: inner_ty, mutbl: mt_b.mutbl}); + mt {ty: inner_ty, mutbl: mutbl_b}); if_ok!(sub.tys(a_borrowed, b)); + Ok(Some(AutoDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(AutoPtr(r_borrow, mt_b.mutbl)) + autoref: Some(AutoPtr(r_borrow, mutbl_b, None)) }))) } - pub fn coerce_borrowed_string(&self, + // [T, ..n] -> &[T] or &mut [T] + fn coerce_unsized_with_borrow(&self, a: ty::t, sty_a: &ty::sty, - b: ty::t) + b: ty::t, + mutbl_b: ast::Mutability) -> CoerceResult { - debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})", + debug!("coerce_unsized_with_borrow(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, b.repr(self.get_ref().infcx.tcx)); match *sty_a { - ty::ty_uniq(_) => return Err(ty::terr_mismatch), - _ => return self.subtype(a, b), + ty::ty_vec(t_a, Some(len)) => { + let sub = Sub(self.get_ref().clone()); + let coercion = Coercion(self.get_ref().trace.clone()); + let r_borrow = self.get_ref().infcx.next_region_var(coercion); + let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow, + mt {ty: t_a, mutbl: mutbl_b}); + if_ok!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b))); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 0, + autoref: Some(ty::AutoPtr(r_borrow, + mutbl_b, + Some(box AutoUnsize(ty::UnsizeLength(len))))) + }))) + } + _ => Err(ty::terr_mismatch) } } - pub fn coerce_borrowed_vector(&self, - a: ty::t, - sty_a: &ty::sty, - b: ty::t, - mutbl_b: ast::Mutability) - -> CoerceResult { - debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})", + // &[T, ..n] or &mut [T, ..n] -> &[T] + // or &mut [T, ..n] -> &mut [T] + // or &Concrete -> &Trait, etc. + fn coerce_unsized(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t) + -> CoerceResult { + debug!("coerce_unsized(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, b.repr(self.get_ref().infcx.tcx)); + // Note, we want to avoid unnecessary unsizing. We don't want to coerce to + // a DST unless we have to. This currently comes out in the wash since + // we can't unify [T] with U. But to properly support DST, we need to allow + // that, at which point we will need extra checks on b here. + let sub = Sub(self.get_ref().clone()); - let coercion = Coercion(self.get_ref().trace.clone()); - let r_borrow = self.get_ref().infcx.next_region_var(coercion); - let ty_inner = match *sty_a { - ty::ty_uniq(_) => return Err(ty::terr_mismatch), - ty::ty_ptr(ty::mt{ty: t, ..}) | - ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty { - ty::ty_vec(mt, None) => mt.ty, - _ => { - return self.subtype(a, b); - } - }, - ty::ty_vec(mt, _) => mt.ty, - _ => { - return self.subtype(a, b); + + let sty_b = &ty::get(b).sty; + match (sty_a, sty_b) { + (&ty::ty_uniq(t_a), &ty::ty_rptr(_, mt_b)) => Err(ty::terr_mismatch), + (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => { + self.unpack_actual_value(t_a, |sty_a| { + match self.unsize_ty(sty_a, mt_b.ty) { + Some((ty, kind)) => { + let coercion = Coercion(self.get_ref().trace.clone()); + let r_borrow = self.get_ref().infcx.next_region_var(coercion); + let ty = ty::mk_rptr(self.get_ref().infcx.tcx, + r_borrow, + ty::mt{ty: ty, mutbl: mt_b.mutbl}); + if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoPtr(AutoUnsize({:?})))", kind); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, + Some(box AutoUnsize(kind)))) + }))) + } + _ => Err(ty::terr_mismatch) + } + }) } - }; + (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { + self.unpack_actual_value(t_a, |sty_a| { + match self.unsize_ty(sty_a, t_b) { + Some((ty, kind)) => { + let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); + if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoUnsizeUniq({:?}))", kind); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsizeUniq(kind)) + }))) + } + _ => Err(ty::terr_mismatch) + } + }) + } + _ => Err(ty::terr_mismatch) + } + } - let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow, - mt {ty: ty_inner, mutbl: mutbl_b}); - if_ok!(sub.tys(a_borrowed, b)); - Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: Some(AutoBorrowVec(r_borrow, mutbl_b)) - }))) + // Takes a type and returns an unsized version along with the adjustment + // performed to unsize it. + // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` + fn unsize_ty(&self, + sty_a: &ty::sty, + ty_b: ty::t) + -> Option<(ty::t, ty::UnsizeKind)> { + debug!("unsize_ty(sty_a={:?}", sty_a); + + let tcx = self.get_ref().infcx.tcx; + + self.unpack_actual_value(ty_b, |sty_b| + match (sty_a, sty_b) { + (&ty::ty_vec(t_a, Some(len)), _) => { + let ty = ty::mk_vec(tcx, t_a, None); + Some((ty, ty::UnsizeLength(len))) + } + (&ty::ty_trait(..), &ty::ty_trait(..)) => None, + (_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => { + let ty = ty::mk_trait(tcx, + def_id, + substs.clone(), + bounds); + Some((ty, ty::UnsizeVtable(bounds, + def_id, + substs.clone()))) + } + (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b)) + if did_a == did_b => { + debug!("unsizing a struct"); + // Try unsizing each type param in turn to see if we end up with ty_b. + let ty_substs_a = substs_a.types.get_vec(subst::TypeSpace); + let ty_substs_b = substs_b.types.get_vec(subst::TypeSpace); + assert!(ty_substs_a.len() == ty_substs_b.len()); + + let sub = Sub(self.get_ref().clone()); + + let mut result = None; + let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); + for (i, (tp_a, tp_b)) in tps { + if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + continue; + } + match self.unpack_actual_value(*tp_a, |tp| self.unsize_ty(tp, *tp_b)) { + Some((new_tp, k)) => { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + *new_substs.types.get_mut_vec(subst::TypeSpace).get_mut(i) = new_tp; + let ty = ty::mk_struct(tcx, did_a, new_substs); + if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { + debug!("Unsized type parameter '{}', but still \ + could not match types {} and {}", + ppaux::ty_to_string(tcx, *tp_a), + ppaux::ty_to_string(tcx, ty), + ppaux::ty_to_string(tcx, ty_b)); + // We can only unsize a single type parameter, so + // if we unsize one and it doesn't give us the + // type we want, then we won't succeed later. + break; + } + + result = Some((ty, ty::UnsizeStruct(box k, i))); + break; + } + None => {} + } + } + result + } + _ => None + } + ) } fn coerce_borrowed_object(&self, @@ -331,7 +439,8 @@ impl<'f> Coerce<'f> { let r_a = self.get_ref().infcx.next_region_var(coercion); let a_borrowed = match *sty_a { - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_uniq(ty) => return Err(ty::terr_mismatch), + ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, ref substs, @@ -352,8 +461,8 @@ impl<'f> Coerce<'f> { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: Some(AutoBorrowObj(r_a, b_mutbl)) + autoderefs: 1, + autoref: Some(AutoPtr(r_a, b_mutbl, None)) }))) } @@ -438,21 +547,4 @@ impl<'f> Coerce<'f> { autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) }))) } - - pub fn coerce_object(&self, - a: ty::t, - sty_a: &ty::sty, - b: ty::t, - trait_def_id: ast::DefId, - trait_substs: &subst::Substs, - trait_store: ty::TraitStore, - bounds: ty::BuiltinBounds) -> CoerceResult { - - debug!("coerce_object(a={}, sty_a={:?}, b={})", - a.repr(self.get_ref().infcx.tcx), sty_a, - b.repr(self.get_ref().infcx.tcx)); - - Ok(Some(ty::AutoObject(trait_store, bounds, - trait_def_id, trait_substs.clone()))) - } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d99d55d4d873d..a57dec9045522 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -529,10 +529,10 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt)) } - (&ty::ty_vec(ref a_mt, sz_a), &ty::ty_vec(ref b_mt, sz_b)) => { - this.mts(a_mt, b_mt).and_then(|mt| { + (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => { + this.tys(a_t, b_t).and_then(|t| { if sz_a == sz_b { - Ok(ty::mk_vec(tcx, mt, sz_a)) + Ok(ty::mk_vec(tcx, t, sz_a)) } else { Err(ty::terr_sorts(expected_found(this, a, b))) } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 5b9b37ab8441b..920fa23f31df3 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -1411,8 +1411,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> { infer::AutoBorrow(span) => { self.tcx.sess.span_note( span, - "...so that automatically reference is valid \ - at the time of borrow"); + "...so that reference is valid \ + at the time of implicit borrow"); } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_note( diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 44c147bfe7f62..a54afb1102fb9 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -129,10 +129,23 @@ impl<'f> Combine for Sub<'f> { if_ok!(self.get_ref().var_sub_var(a_id, b_id)); Ok(a) } + // The vec/str check here and below is so that we don't unify + // T with [T], this is necessary so we reflect subtyping of references + // (&T does not unify with &[T]) where that in turn is to reflect + // the historical non-typedness of [T]. + (&ty::ty_infer(TyVar(_)), &ty::ty_str) | + (&ty::ty_infer(TyVar(_)), &ty::ty_vec(_, None)) => { + Err(ty::terr_sorts(expected_found(self, a, b))) + } (&ty::ty_infer(TyVar(a_id)), _) => { if_ok!(self.get_ref().var_sub_t(a_id, b)); Ok(a) } + + (&ty::ty_str, &ty::ty_infer(TyVar(_))) | + (&ty::ty_vec(_, None), &ty::ty_infer(TyVar(_))) => { + Err(ty::terr_sorts(expected_found(self, a, b))) + } (_, &ty::ty_infer(TyVar(b_id))) => { if_ok!(self.get_ref().t_sub_var(a, b_id)); Ok(a) diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 97c11b9205970..e6227b9c12829 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -741,11 +741,7 @@ impl<'a> ConstraintContext<'a> { self.add_constraints_from_mt(mt, variance); } - ty::ty_vec(ref mt, _) => { - self.add_constraints_from_mt(mt, variance); - } - - ty::ty_uniq(typ) | ty::ty_box(typ) => { + ty::ty_uniq(typ) | ty::ty_box(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => { self.add_constraints_from_ty(typ, variance); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e0e9f0e6910b2..4f68d42de966c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -19,7 +19,7 @@ use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; -use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup}; +use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; @@ -370,6 +370,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { buf.push_str(mt_to_string(cx, tm).as_slice()); buf } + ty_open(typ) => format!("opened<{}>", ty_to_str(cx, typ)), ty_tup(ref elems) => { let strs: Vec = elems.iter().map(|elem| ty_to_string(cx, *elem)).collect(); format!("({})", strs.connect(",")) @@ -407,7 +408,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { let trait_def = ty::lookup_trait_def(cx, did); let ty = parameterized(cx, base.as_slice(), substs, &trait_def.generics); - let bound_sep = if bounds.is_empty() { "" } else { ":" }; + let bound_sep = if bounds.is_empty() { "" } else { "+" }; let bound_str = bounds.repr(cx); format!("{}{}{}", ty, @@ -416,12 +417,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } ty_str => "str".to_string(), ty_unboxed_closure(..) => "closure".to_string(), - ty_vec(ref mt, sz) => { + ty_vec(t, sz) => { match sz { Some(n) => { - format!("[{}, .. {}]", mt_to_string(cx, mt), n) + format!("[{}, .. {}]", ty_to_string(cx, t), n) } - None => format!("[{}]", ty_to_string(cx, mt.ty)), + None => format!("[{}]", ty_to_string(cx, t)), } } } diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs index 015331b8be00e..e859a5d21d7e7 100644 --- a/src/librustc_back/abi.rs +++ b/src/librustc_back/abi.rs @@ -20,8 +20,8 @@ pub static fn_field_box: uint = 1u; // The two fields of a trait object/trait instance: vtable and box. // The vtable contains the type descriptor as first element. -pub static trt_field_vtable: uint = 0u; -pub static trt_field_box: uint = 1u; +pub static trt_field_box: uint = 0u; +pub static trt_field_vtable: uint = 1u; pub static slice_elt_base: uint = 0u; pub static slice_elt_len: uint = 1u; diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 29668795ed7ba..6af19d948e0e8 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -225,7 +225,6 @@ mod svh_visitor { SawExprBreak(Option), SawExprAgain(Option), - SawExprVstore, SawExprBox, SawExprVec, SawExprCall, @@ -257,7 +256,6 @@ mod svh_visitor { fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { match *node { - ExprVstore(..) => SawExprVstore, ExprBox(..) => SawExprBox, ExprVec(..) => SawExprVec, ExprCall(..) => SawExprCall, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 68e1529fb1770..dc2c0d1d0830d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1250,8 +1250,8 @@ impl Clean for ty::t { }); lang_struct(box_did, t, "Box", Unique) } - ty::ty_vec(mt, None) => Vector(box mt.ty.clean()), - ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), + ty::ty_vec(ty, None) => Vector(box ty.clean()), + ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(), format!("{}", i)), ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()), ty::ty_rptr(r, mt) => BorrowedRef { @@ -1315,6 +1315,7 @@ impl Clean for ty::t { ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton) ty::ty_infer(..) => fail!("ty_infer"), + ty::ty_open(..) => fail!("ty_open"), ty::ty_err => fail!("ty_err"), } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index be62b1cc36f40..6415ee85f5704 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -259,7 +259,8 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) -> // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) { + let default: &[_] = &[]; + match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { Some(attrs) => { for attr in attrs.iter() { match *attr { diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index 91614763ce52f..55d9811ccadc0 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -72,13 +72,15 @@ impl Clone for HomeHandle { } pub fn local_id() -> uint { + use std::raw::TraitObject; + let mut io = match LocalIo::borrow() { Some(io) => io, None => return 0, }; let io = io.get(); unsafe { - let (_vtable, ptr): (uint, uint) = mem::transmute(io); - return ptr; + let obj: TraitObject = mem::transmute(io); + return mem::transmute(obj.data); } } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index dd80ab3ee78a1..6e948992979d8 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -462,13 +462,14 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf { // This function is full of lies! #[cfg(test)] fn local_loop() -> &'static mut uvio::UvIoFactory { + use std::raw::TraitObject; unsafe { mem::transmute({ let mut task = Local::borrow(None::); let mut io = task.local_io().unwrap(); - let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) = + let obj: TraitObject = mem::transmute(io.get()); - uvio + obj.data }) } } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 0a7817c3e0047..06eab31d7bff5 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -464,6 +464,7 @@ static dot_dot_static: &'static [u8] = b".."; mod tests { use prelude::*; use super::*; + use mem; use str; use str::StrSlice; @@ -621,8 +622,10 @@ mod tests { macro_rules! t( (s: $path:expr, $op:ident, $exp:expr) => ( { - let path = Path::new($path); - assert!(path.$op() == ($exp).as_bytes()); + unsafe { + let path = Path::new($path); + assert!(path.$op() == mem::transmute(($exp).as_bytes())); + } } ); (s: $path:expr, $op:ident, $exp:expr, opt) => ( @@ -634,9 +637,11 @@ mod tests { ); (v: $path:expr, $op:ident, $exp:expr) => ( { - let arg = $path; - let path = Path::new(arg); - assert!(path.$op() == $exp); + unsafe { + let arg = $path; + let path = Path::new(arg); + assert!(path.$op() == mem::transmute($exp)); + } } ); ) @@ -684,8 +689,9 @@ mod tests { t!(v: b"hi/there.txt", extension, Some(b"txt")); t!(v: b"hi/there\x80.txt", extension, Some(b"txt")); t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt")); - t!(v: b"hi/there", extension, None); - t!(v: b"hi/there\x80", extension, None); + let no: Option<&'static [u8]> = None; + t!(v: b"hi/there", extension, no); + t!(v: b"hi/there\x80", extension, no); t!(s: "hi/there.txt", extension, Some("txt"), opt); t!(s: "hi/there", extension, None, opt); t!(s: "there.txt", extension, Some("txt"), opt); @@ -974,57 +980,62 @@ mod tests { macro_rules! t( (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - let filename = $filename; - assert!(path.filename_str() == filename, - "{}.filename_str(): Expected `{:?}`, found {:?}", - path.as_str().unwrap(), filename, path.filename_str()); - let dirname = $dirname; - assert!(path.dirname_str() == dirname, - "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), dirname, path.dirname_str()); - let filestem = $filestem; - assert!(path.filestem_str() == filestem, - "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filestem, path.filestem_str()); - let ext = $ext; - assert!(path.extension_str() == ext, - "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), ext, path.extension_str()); + unsafe { + let path = $path; + let filename = $filename; + assert!(path.filename_str() == filename, + "{}.filename_str(): Expected `{:?}`, found {:?}", + path.as_str().unwrap(), filename, path.filename_str()); + let dirname = $dirname; + assert!(path.dirname_str() == dirname, + "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), dirname, path.dirname_str()); + let filestem = $filestem; + assert!(path.filestem_str() == filestem, + "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filestem, path.filestem_str()); + let ext = $ext; + assert!(path.extension_str() == mem::transmute(ext), + "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), ext, path.extension_str()); + } } ); (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - assert!(path.filename() == $filename); - assert!(path.dirname() == $dirname); - assert!(path.filestem() == $filestem); - assert!(path.extension() == $ext); + unsafe { + let path = $path; + assert!(path.filename() == mem::transmute($filename)); + assert!(path.dirname() == mem::transmute($dirname)); + assert!(path.filestem() == mem::transmute($filestem)); + assert!(path.extension() == mem::transmute($ext)); + } } ) ) - t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None); - t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None); + let no: Option<&'static str> = None; + t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), no); + t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), no); t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi", Some(b"there"), Some(b"\xFF")); - t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("/"), None, Some("/"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("../.."), None, Some("../.."), None, None); + t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), no); + t!(s: Path::new("."), None, Some("."), None, no); + t!(s: Path::new("/"), None, Some("/"), None, no); + t!(s: Path::new(".."), None, Some(".."), None, no); + t!(s: Path::new("../.."), None, Some("../.."), None, no); t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"), Some("there"), Some("txt")); - t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None); + t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), no); t!(s: Path::new("hi/there."), Some("there."), Some("hi"), Some("there"), Some("")); - t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None); + t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), no); t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"), Some("."), Some("there")); - t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None); + t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, no); t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt")); - t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None); - t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None); + t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), no); + t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), no); } #[test] diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index dd87e214c2c96..d9864cfaa6130 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -1141,6 +1141,7 @@ fn prefix_len(p: Option) -> uint { #[cfg(test)] mod tests { + use mem; use prelude::*; use super::*; use super::parse_prefix; @@ -1383,9 +1384,11 @@ mod tests { macro_rules! t( (s: $path:expr, $op:ident, $exp:expr) => ( { - let path = $path; - let path = Path::new(path); - assert!(path.$op() == Some($exp)); + unsafe { + let path = $path; + let path = Path::new(path); + assert!(path.$op() == Some(mem::transmute($exp))); + } } ); (s: $path:expr, $op:ident, $exp:expr, opt) => ( @@ -1398,9 +1401,11 @@ mod tests { ); (v: $path:expr, $op:ident, $exp:expr) => ( { - let path = $path; - let path = Path::new(path); - assert!(path.$op() == $exp); + unsafe { + let path = $path; + let path = Path::new(path); + assert!(path.$op() == mem::transmute($exp)); + } } ) ) @@ -1485,7 +1490,8 @@ mod tests { // filestem is based on filename, so we don't need the full set of prefix tests t!(v: b"hi\\there.txt", extension, Some(b"txt")); - t!(v: b"hi\\there", extension, None); + let no: Option<&'static [u8]> = None; + t!(v: b"hi\\there", extension, no); t!(s: "hi\\there.txt", extension_str, Some("txt"), opt); t!(s: "hi\\there", extension_str, None, opt); t!(s: "there.txt", extension_str, Some("txt"), opt); @@ -1892,48 +1898,53 @@ mod tests { macro_rules! t( (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - let filename = $filename; - assert!(path.filename_str() == filename, - "`{}`.filename_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filename, path.filename_str()); - let dirname = $dirname; - assert!(path.dirname_str() == dirname, - "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), dirname, path.dirname_str()); - let filestem = $filestem; - assert!(path.filestem_str() == filestem, - "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), filestem, path.filestem_str()); - let ext = $ext; - assert!(path.extension_str() == ext, - "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", - path.as_str().unwrap(), ext, path.extension_str()); + unsafe { + let path = $path; + let filename = $filename; + assert!(path.filename_str() == filename, + "`{}`.filename_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filename, path.filename_str()); + let dirname = $dirname; + assert!(path.dirname_str() == dirname, + "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), dirname, path.dirname_str()); + let filestem = $filestem; + assert!(path.filestem_str() == filestem, + "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), filestem, path.filestem_str()); + let ext = $ext; + assert!(path.extension_str() == mem::transmute(ext), + "`{}`.extension_str(): Expected `{:?}`, found `{:?}`", + path.as_str().unwrap(), ext, path.extension_str()); + } } ); (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( { - let path = $path; - assert!(path.filename() == $filename); - assert!(path.dirname() == $dirname); - assert!(path.filestem() == $filestem); - assert!(path.extension() == $ext); + unsafe { + let path = $path; + assert!(path.filename() == mem::transmute($filename)); + assert!(path.dirname() == mem::transmute($dirname)); + assert!(path.filestem() == mem::transmute($filestem)); + assert!(path.extension() == mem::transmute($ext)); + } } ) ) - t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None); - t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("\\"), None, Some("\\"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None); + let no: Option<&'static str> = None; + t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), no); + t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), no); + t!(s: Path::new("."), None, Some("."), None, no); + t!(s: Path::new("\\"), None, Some("\\"), None, no); + t!(s: Path::new(".."), None, Some(".."), None, no); + t!(s: Path::new("..\\.."), None, Some("..\\.."), None, no); t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"), Some("there"), Some("txt")); - t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None); + t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), no); t!(s: Path::new("hi\\there."), Some("there."), Some("hi"), Some("there"), Some("")); - t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None); + t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), no); t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"), Some("."), Some("there")); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 42d9430d7320e..7d5787092a5c5 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -394,16 +394,6 @@ pub enum Mutability { MutImmutable, } -#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] -pub enum ExprVstore { - /// ~[1, 2, 3, 4] - ExprVstoreUniq, - /// &[1, 2, 3, 4] - ExprVstoreSlice, - /// &mut [1, 2, 3, 4] - ExprVstoreMutSlice, -} - #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum BinOp { BiAdd, @@ -522,7 +512,6 @@ pub struct Expr { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Expr_ { - ExprVstore(Gc, ExprVstore), /// First expr is the place; second expr is the value. ExprBox(Gc, Gc), ExprVec(Vec>), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f7eddca4b7aed..909f8f1e78ce4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -143,12 +143,10 @@ pub trait AstBuilder { fn expr_u8(&self, sp: Span, u: u8) -> Gc; fn expr_bool(&self, sp: Span, value: bool) -> Gc; - fn expr_vstore(&self, sp: Span, expr: Gc, vst: ast::ExprVstore) -> Gc; fn expr_vec(&self, sp: Span, exprs: Vec> ) -> Gc; fn expr_vec_ng(&self, sp: Span) -> Gc; fn expr_vec_slice(&self, sp: Span, exprs: Vec> ) -> Gc; fn expr_str(&self, sp: Span, s: InternedString) -> Gc; - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc; fn expr_some(&self, sp: Span, expr: Gc) -> Gc; fn expr_none(&self, sp: Span) -> Gc; @@ -654,9 +652,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_lit(sp, ast::LitBool(value)) } - fn expr_vstore(&self, sp: Span, expr: Gc, vst: ast::ExprVstore) -> Gc { - self.expr(sp, ast::ExprVstore(expr, vst)) - } fn expr_vec(&self, sp: Span, exprs: Vec> ) -> Gc { self.expr(sp, ast::ExprVec(exprs)) } @@ -669,15 +664,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new()) } fn expr_vec_slice(&self, sp: Span, exprs: Vec> ) -> Gc { - self.expr_vstore(sp, self.expr_vec(sp, exprs), ast::ExprVstoreSlice) + self.expr_addr_of(sp, self.expr_vec(sp, exprs)) } fn expr_str(&self, sp: Span, s: InternedString) -> Gc { self.expr_lit(sp, ast::LitStr(s, ast::CookedStr)) } - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc { - self.expr_vstore(sp, self.expr_str(sp, s), ast::ExprVstoreUniq) - } - fn expr_cast(&self, sp: Span, expr: Gc, ty: P) -> Gc { self.expr(sp, ast::ExprCast(expr, ty)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb96b4b83d7f3..4a0787aeb9efa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1088,9 +1088,6 @@ pub fn noop_fold_pat(p: Gc, folder: &mut T) -> Gc { pub fn noop_fold_expr(e: Gc, folder: &mut T) -> Gc { let id = folder.new_id(e.id); let node = match e.node { - ExprVstore(e, v) => { - ExprVstore(folder.fold_expr(e), v) - } ExprBox(p, e) => { ExprBox(folder.fold_expr(p), folder.fold_expr(e)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 17a27a5a39e6d..585b98925cc58 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1137,7 +1137,8 @@ mod test { let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap(); let docs = item.attrs.iter().filter(|a| a.name().get() == "doc") .map(|a| a.value_str().unwrap().get().to_string()).collect::>(); - assert_eq!(docs.as_slice(), &["/// doc comment".to_string(), "/// line 2".to_string()]); + let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; + assert_eq!(docs.as_slice(), b); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2409912abe461..00513f7f67c31 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,9 +27,8 @@ use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn}; -use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; -use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl}; -use ast::{ExprVstoreUniq, Once, Many}; +use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl}; +use ast::{Once, Many}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod}; @@ -1428,13 +1427,16 @@ impl<'a> Parser<'a> { } else if self.token == token::TILDE { // OWNED POINTER self.bump(); - let last_span = self.last_span; + let span = self.last_span; match self.token { - token::LBRACKET => - self.obsolete(last_span, ObsoleteOwnedVector), - _ => self.obsolete(last_span, ObsoleteOwnedType), - }; - TyUniq(self.parse_ty(true)) + token::IDENT(ref ident, _) + if "str" == token::get_ident(*ident).get() => { + // This is OK (for now). + } + token::LBRACKET => {} // Also OK. + _ => self.obsolete(span, ObsoleteOwnedType) + } + TyUniq(self.parse_ty(false)) } else if self.token == token::BINOP(token::STAR) { // STAR POINTER (bare pointer?) self.bump(); @@ -2549,16 +2551,7 @@ impl<'a> Parser<'a> { let m = self.parse_mutability(); let e = self.parse_prefix_expr(); hi = e.span.hi; - // HACK: turn &[...] into a &-vec - ex = match e.node { - ExprVec(..) if m == MutImmutable => { - ExprVstore(e, ExprVstoreSlice) - } - ExprVec(..) if m == MutMutable => { - ExprVstore(e, ExprVstoreMutSlice) - } - _ => ExprAddrOf(m, e) - }; + ex = ExprAddrOf(m, e); } token::AT => { self.bump(); @@ -2570,25 +2563,18 @@ impl<'a> Parser<'a> { } token::TILDE => { self.bump(); + let span = self.last_span; + match self.token { + token::LIT_STR(_) => { + // This is OK (for now). + } + token::LBRACKET => {} // Also OK. + _ => self.obsolete(span, ObsoleteOwnedExpr) + } let e = self.parse_prefix_expr(); hi = e.span.hi; - // HACK: turn ~[...] into a ~-vec - let last_span = self.last_span; - ex = match e.node { - ExprVec(..) | ExprRepeat(..) => { - self.obsolete(last_span, ObsoleteOwnedVector); - ExprVstore(e, ExprVstoreUniq) - } - ExprLit(lit) if lit_is_str(lit) => { - self.obsolete(last_span, ObsoleteOwnedExpr); - ExprVstore(e, ExprVstoreUniq) - } - _ => { - self.obsolete(last_span, ObsoleteOwnedExpr); - self.mk_unary(UnUniq, e) - } - }; + ex = self.mk_unary(UnUniq, e); } token::IDENT(_, _) => { if self.is_keyword(keywords::Box) { @@ -2607,24 +2593,10 @@ impl<'a> Parser<'a> { } } - // Otherwise, we use the unique pointer default. - let subexpression = self.parse_prefix_expr(); - hi = subexpression.span.hi; - // HACK: turn `box [...]` into a boxed-vec - ex = match subexpression.node { - ExprVec(..) | ExprRepeat(..) => { - let last_span = self.last_span; - self.obsolete(last_span, ObsoleteOwnedVector); - ExprVstore(subexpression, ExprVstoreUniq) - } - ExprLit(lit) if lit_is_str(lit) => { - ExprVstore(subexpression, ExprVstoreUniq) - } - _ => self.mk_unary(UnUniq, subexpression) - }; - } else { - return self.parse_dot_or_call_expr() - } + // Otherwise, we use the unique pointer default. + let subexpression = self.parse_prefix_expr(); + hi = subexpression.span.hi; + ex = self.mk_unary(UnUniq, subexpression); } _ => return self.parse_dot_or_call_expr() } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6fe44078447e5..d5b6c5652a0cc 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -159,6 +159,7 @@ impl<'a> State<'a> { } pub fn to_string(f: |&mut State| -> IoResult<()>) -> String { + use std::raw::TraitObject; let mut s = rust_printer(box MemWriter::new()); f(&mut s).unwrap(); eof(&mut s.s).unwrap(); @@ -166,7 +167,8 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String { // FIXME(pcwalton): A nasty function to extract the string from an `io::Writer` // that we "know" to be a `MemWriter` that works around the lack of checked // downcasts. - let (_, wr): (uint, Box) = mem::transmute_copy(&s.s.out); + let obj: TraitObject = mem::transmute_copy(&s.s.out); + let wr: Box = mem::transmute(obj.data); let result = String::from_utf8(Vec::from_slice(wr.get_ref().as_slice())).unwrap(); mem::forget(wr); @@ -1321,16 +1323,6 @@ impl<'a> State<'a> { } } - pub fn print_expr_vstore(&mut self, t: ast::ExprVstore) -> IoResult<()> { - match t { - ast::ExprVstoreUniq => word(&mut self.s, "box "), - ast::ExprVstoreSlice => word(&mut self.s, "&"), - ast::ExprVstoreMutSlice => { - try!(word(&mut self.s, "&")); - word(&mut self.s, "mut") - } - } - } fn print_call_post(&mut self, args: &[Gc]) -> IoResult<()> { try!(self.popen()); @@ -1355,10 +1347,6 @@ impl<'a> State<'a> { try!(self.ibox(indent_unit)); try!(self.ann.pre(self, NodeExpr(expr))); match expr.node { - ast::ExprVstore(ref e, v) => { - try!(self.print_expr_vstore(v)); - try!(self.print_expr(&**e)); - }, ast::ExprBox(ref p, ref e) => { try!(word(&mut self.s, "box")); try!(word(&mut self.s, "(")); diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 43367611ab2b9..517c5e5bf47da 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -64,7 +64,10 @@ impl SmallVector { pub fn as_slice<'a>(&'a self) -> &'a [T] { match self.repr { - Zero => &[], + Zero => { + let result: &[T] = &[]; + result + } One(ref v) => slice::ref_slice(v), Many(ref vs) => vs.as_slice() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9e371143311c2..6c6f59f0df639 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -729,9 +729,6 @@ pub fn walk_mac>(_: &mut V, _: &Mac, _: E) { pub fn walk_expr>(visitor: &mut V, expression: &Expr, env: E) { match expression.node { - ExprVstore(ref subexpression, _) => { - visitor.visit_expr(&**subexpression, env.clone()) - } ExprBox(ref place, ref subexpression) => { visitor.visit_expr(&**place, env.clone()); visitor.visit_expr(&**subexpression, env.clone()) diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs index f7d5ddb314557..4f53694ebd622 100644 --- a/src/test/compile-fail/const-cast-different-types.rs +++ b/src/test/compile-fail/const-cast-different-types.rs @@ -9,8 +9,8 @@ // except according to those terms. static a: &'static str = "foo"; -static b: *const u8 = a as *const u8; //~ ERROR non-scalar cast -static c: *const u8 = &a as *const u8; //~ ERROR mismatched types +static b: *const u8 = a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&'static str` +static c: *const u8 = &a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&&'static str` fn main() { } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs new file mode 100644 index 0000000000000..282cf57df26c0 --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -0,0 +1,46 @@ +// 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. + +// Forbid assignment into a dynamically sized type. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = box Bar1 {f: 36}; + f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment +} diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs new file mode 100644 index 0000000000000..e069eb01ae184 --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -0,0 +1,46 @@ +// 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. + +// Forbid assignment into a dynamically sized type. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = box Bar1 {f: 36}; + f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar` but found `Bar1` +} diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs new file mode 100644 index 0000000000000..a7dc4e123aff8 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -0,0 +1,32 @@ +// 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. + +// Attempt to change the type as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &Fat<[uint]> = f2; + //~^ ERROR mismatched types: expected `&Fat<[uint]>` but found `&Fat<[int, .. 3]>` + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; + let f3: &Fat = f2; + //~^ ERROR failed to find an implementation of trait Bar for Foo +} diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs new file mode 100644 index 0000000000000..d4ce59b726162 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -0,0 +1,31 @@ +// 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. + +// Attempt to change the mutability as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &mut Fat<[int]> = f2; //~ ERROR cannot borrow immutable dereference + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; + let f3: &mut Fat = f2; //~ ERROR cannot borrow immutable dereference +} diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs new file mode 100644 index 0000000000000..bd7c46060a512 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -0,0 +1,35 @@ +// 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. + +// Attempt to extend the lifetime as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +fn baz<'a>() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat<[int]> = f2; + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat = f2; +} + +pub fn main() { + baz(); +} diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs new file mode 100644 index 0000000000000..0916fa08a3924 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -0,0 +1,22 @@ +// 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. + +// Attempt to coerce from unsized to sized. + +struct Fat { + ptr: T +} + +pub fn main() { + // With a vec of ints. + let f1: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = f1; + //~^ ERROR mismatched types: expected `&Fat<[int, .. 3]>` but found `&Fat<[int]>` +} diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs new file mode 100644 index 0000000000000..b18e7dad4ac55 --- /dev/null +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -0,0 +1,25 @@ +// 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. + +// Try to initialise a DST struct where the lost information is deeply nested. +// This is an error because it requires an unsized rvalue. This is a problem +// because it would require stack allocation of an unsized temporary (*g in the +// test). + +struct Fat { + ptr: T +} + +pub fn main() { + let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] }; + let g: &Fat<[int]> = &f; + let h: &Fat> = &Fat { ptr: *g }; + //~^ ERROR trying to initialise a dynamically sized struct +} diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 71b98bb5f5a48..8ae20dfde9123 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test<'x>(x: &'x int) { //~ NOTE the lifetime 'x as defined +fn test<'x>(x: &'x int) { drop::< <'z>|&'z int| -> &'z int>(|z| { - //~^ ERROR mismatched types - //~^^ ERROR cannot infer an appropriate lifetime x + //~^ ERROR cannot infer an appropriate lifetime }); } diff --git a/src/test/compile-fail/issue-13446.rs b/src/test/compile-fail/issue-13446.rs index 0bb6ded00121d..162324b7c59b2 100644 --- a/src/test/compile-fail/issue-13446.rs +++ b/src/test/compile-fail/issue-13446.rs @@ -11,7 +11,9 @@ // Used to cause ICE -static VEC: [u32, ..256] = vec!(); //~ ERROR mismatched types +// error-pattern: mismatched types + +static VEC: [u32, ..256] = vec!(); fn main() {} diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs index 026327a358a46..5063a78e38348 100644 --- a/src/test/compile-fail/issue-4523.rs +++ b/src/test/compile-fail/issue-4523.rs @@ -10,8 +10,8 @@ fn foopy() {} -static f: ||: 'static = foopy; //~ ERROR found extern fn +static f: ||: 'static = foopy; fn main () { - f(); + f(); //~ ERROR closure invocation in a static location } diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index d684d1b376b8f..f7199a92d27cc 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -17,7 +17,7 @@ pub enum TraitWrapper { fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { - A(box ref map) => map, //~ ERROR cannot be dereferenced + A(box ref map) => map, //~ ERROR mismatched types: expected `Box` but found a box } } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 831e165ad0ef5..3703d4f39acef 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -11,15 +11,14 @@ trait A {} struct Struct { - r: A //~ ERROR reference to trait `A` where a type is expected; try `Box` or `&A` + r: A } fn new_struct(r: A) -> Struct { - //~^ ERROR reference to trait `A` where a type is expected; try `Box` or `&A` + //~^ ERROR variable `r` has dynamically sized type `A` Struct { r: r } } trait Curve {} enum E {X(Curve)} -//~^ ERROR reference to trait `Curve` where a type is expected; try `Box` or `&Curve` fn main() {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index ea332c1e25233..efd8e75d3d6d3 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,7 +32,7 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR cannot pack type `Box`, which does not fulfill `Send` + //~^ ERROR cannot pack type `Box` as a trait bounded by Send because the type does not fulfil let v = Rc::new(RefCell::new(a)); let w = v.clone(); let b = &*v; diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index ef5a45fcf70ae..481fb3dee73a8 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -36,14 +36,14 @@ fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) { struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } @@ -53,21 +53,19 @@ struct Dog<'y> { dog: &'y int } fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x int { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x int - x.t.dog //~ ERROR: mismatched types + x.t.dog //~ ERROR: cannot infer } struct Baz<'x> { bar: &'x int } - impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &int) -> (&'b int, &'b int) { // The lifetime that gets assigned to `x` seems somewhat random. // I have disabled this test for the time being. --pcwalton (self.bar, x) //~ ERROR: cannot infer - //~^ ERROR: mismatched types - //~^^ ERROR: mismatched types + //~^ ERROR: cannot infer } } diff --git a/src/test/compile-fail/lub-if.rs b/src/test/compile-fail/lub-if.rs index 82938d63ce54c..5440219e55eb9 100644 --- a/src/test/compile-fail/lub-if.rs +++ b/src/test/compile-fail/lub-if.rs @@ -31,18 +31,18 @@ pub fn opt_str1<'a>(maybestr: &'a Option) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { - if maybestr.is_none() { //~ ERROR mismatched types + if maybestr.is_none() { "(none)" } else { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } } pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { - if maybestr.is_some() { //~ ERROR mismatched types + if maybestr.is_some() { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } else { "(none)" } diff --git a/src/test/compile-fail/lub-match.rs b/src/test/compile-fail/lub-match.rs index 98bea422fb5b9..febe5f45d96b0 100644 --- a/src/test/compile-fail/lub-match.rs +++ b/src/test/compile-fail/lub-match.rs @@ -33,7 +33,7 @@ pub fn opt_str1<'a>(maybestr: &'a Option) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to None => "(none)", Some(ref s) => { let s: &'a str = s.as_slice(); @@ -43,7 +43,7 @@ pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { } pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to Some(ref s) => { let s: &'a str = s.as_slice(); s diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 9c8f8f8c30cc5..0cb88b924f85c 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -27,7 +27,7 @@ impl<'a> GetRef<'a> for Box<'a> { impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a int { - g2.get() //~ ERROR lifetime mismatch + g2.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } } diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs index 9cff4849cbeb2..25016c104adc8 100644 --- a/src/test/compile-fail/regions-early-bound-error.rs +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -26,7 +26,7 @@ impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { } fn get<'a,'b,G:GetRef<'a, int>>(g1: G, b: &'b int) -> &'b int { - g1.get() //~ ERROR lifetime mismatch + g1.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } fn main() { diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index 1d8c4cec65544..0eb47da16b600 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -22,9 +22,9 @@ mod argparse { impl<'a> Flag<'a> { pub fn set_desc(self, s: &str) -> Flag<'a> { - Flag { //~ ERROR cannot infer + Flag { name: self.name, - desc: s, + desc: s, //~ ERROR cannot infer an appropriate lifetime for automatic coercion due t max_count: self.max_count, value: self.value } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index c66e5616b849a..7dc57d37e2496 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -21,8 +21,7 @@ fn nested<'x>(x: &'x int) { }); ignore::< <'z>|&'z int| -> &'z int>(|z| { - if false { return x; } //~ ERROR mismatched types - //~^ ERROR cannot infer + if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return ay; } return z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 068ecb7118fc2..df46b2aaac013 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -17,7 +17,7 @@ fn with(f: <'a>|x: &'a int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index f9983bcf80172..507a48fb74170 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -20,7 +20,7 @@ fn with(f: |x: &int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-return-stack-allocated-vec.rs b/src/test/compile-fail/regions-return-stack-allocated-vec.rs index b5f4fcadf89fe..3c5423c44d089 100644 --- a/src/test/compile-fail/regions-return-stack-allocated-vec.rs +++ b/src/test/compile-fail/regions-return-stack-allocated-vec.rs @@ -11,7 +11,7 @@ // Test that we cannot return a stack allocated slice fn function(x: int) -> &'static [int] { - &[x] //~ ERROR mismatched types + &[x] //~ ERROR borrowed value does not live long enough } fn main() { diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index f0f388a5a078e..78b4ab817bfac 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -14,7 +14,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ERROR reference to trait `Foo` where a type is expected; try `Box` or `&Foo` + //~^ERROR variable `_x` has dynamically sized type `Foo+Send` } fn main() { } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index bc47d9aff8121..978cca56b5604 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -6,37 +6,37 @@ digraph block { N4[label="expr 151i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr break \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { break \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { break \'outer ; \"unreachable\" }"]; + N16[label="block { break \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 2i"]; N20[label="expr y >= 2i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 2i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 2i { break ; \"unreachable\"; }"]; N26[label="expr 3i"]; N27[label="expr y"]; N28[label="expr y -= 3i"]; - N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N30[label="expr 4i"]; N31[label="expr y"]; N32[label="expr y -= 4i"]; N33[label="expr 5i"]; N34[label="expr x"]; N35[label="expr x -= 5i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; - N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -47,7 +47,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -56,7 +56,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs index e5ca1de3f2d2c..62233dcb7d8a1 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ b/src/test/run-make/graphviz-flowgraph/f15.rs @@ -16,11 +16,11 @@ pub fn expr_break_label_15() { 'inner: loop { if x == 1i { break 'outer; - "unreachable" + "unreachable"; } if y >= 2i { break; - "unreachable" + "unreachable"; } y -= 3i; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index 9c60e19f8b073..963c4b4353195 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -6,38 +6,38 @@ digraph block { N4[label="expr 16i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr continue \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { continue \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { continue \'outer ; \"unreachable\" }"]; + N16[label="block { continue \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 1i"]; N20[label="expr y >= 1i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 1i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 1i { break ; \"unreachable\"; }"]; N26[label="expr 1i"]; N27[label="expr y"]; N28[label="expr y -= 1i"]; - N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; - N30[label="expr 1i"]; + N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; + N30[label="expr 1"]; N31[label="expr y"]; N32[label="expr y -= 1i"]; N33[label="expr 1i"]; N34[label="expr x"]; N35[label="expr x -= 1i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N37[label="expr \"unreachable\""]; - N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; + N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,7 +48,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -57,7 +57,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs index 78de99d28fcce..2683d8bd06b97 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ b/src/test/run-make/graphviz-flowgraph/f16.rs @@ -16,11 +16,11 @@ pub fn expr_continue_label_16() { 'inner: loop { if x == 1i { continue 'outer; - "unreachable" + "unreachable"; } if y >= 1i { break; - "unreachable" + "unreachable"; } y -= 1i; } diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs new file mode 100644 index 0000000000000..17957dbcc1389 --- /dev/null +++ b/src/test/run-pass/check-static-slice.rs @@ -0,0 +1,40 @@ +// 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. + +// Check that the various ways of getting to a reference to a vec (both sized +// and unsized) work properly. + +static aa: [int, ..3] = [1, 2, 3]; +static ab: &'static [int, ..3] = &aa; +static ac: &'static [int] = ab; +static ad: &'static [int] = &aa; +static ae: &'static [int, ..3] = &[1, 2, 3]; +static af: &'static [int] = &[1, 2, 3]; + +static ca: int = aa[0]; +static cb: int = ab[1]; +static cc: int = ac[2]; +static cd: int = ad[0]; +static ce: int = ae[1]; +static cf: int = af[2]; + +fn main () { + let b: &[int] = &[1, 2, 3]; + assert!(ac == b); + assert!(ad == b); + assert!(af == b); + + assert!(ca == 1); + assert!(cb == 2); + assert!(cc == 3); + assert!(cd == 1); + assert!(ce == 2); + assert!(cf == 3); +} diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 4c81eaae1d802..5be21696bd1ed 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -12,6 +12,9 @@ enum E { V1(int), V0 } static C: &'static [E] = &[V0, V1(0xDEADBEE)]; static C0: E = C[0]; static C1: E = C[1]; +static D: &'static [E, ..2] = &[V0, V1(0xDEADBEE)]; +static D0: E = C[0]; +static D1: E = C[1]; pub fn main() { match C0 { @@ -22,4 +25,13 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } + + match D0 { + V0 => (), + _ => fail!() + } + match D1 { + V1(n) => assert!(n == 0xDEADBEE), + _ => fail!() + } } diff --git a/src/test/run-pass/dst-struct-reflect.rs b/src/test/run-pass/dst-struct-reflect.rs new file mode 100644 index 0000000000000..297880a8b53de --- /dev/null +++ b/src/test/run-pass/dst-struct-reflect.rs @@ -0,0 +1,59 @@ +// 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. + +// Test that structs with unsized fields work with {:?} reflection. + +extern crate debug; + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn reflect(x: &Fat<[int]>, cmp: &str) { + // Don't test this result because reflecting unsized fields is undefined for now. + let _s = format!("{:?}", x); + let s = format!("{:?}", &x.ptr); + assert!(s == cmp.to_string()) + + println!("{:?}", x); + println!("{:?}", &x.ptr); +} + +fn reflect_0(x: &Fat<[int]>) { + let _s = format!("{:?}", x.ptr[0]); + println!("{:?}", x.ptr[0]); +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(&f1, "&[1, 2, 3]"); + reflect_0(&f1); + let f2 = &f1; + reflect(f2, "&[1, 2, 3]"); + reflect_0(f2); + let f3: &Fat<[int]> = f2; + reflect(f3, "&[1, 2, 3]"); + reflect_0(f3); + let f4: &Fat<[int]> = &f1; + reflect(f4, "&[1, 2, 3]"); + reflect_0(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(f5, "&[1, 2, 3]"); + reflect_0(f5); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + reflect(f5, "&[]"); +} + diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs new file mode 100644 index 0000000000000..3f01d013cee32 --- /dev/null +++ b/src/test/run-pass/dst-struct-sole.rs @@ -0,0 +1,84 @@ +// 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. + +// As dst-struct.rs, but the unsized field is the only field in the struct. + +struct Fat { + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); +} + +fn foo2(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); +} diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs new file mode 100644 index 0000000000000..ae1f854ccab34 --- /dev/null +++ b/src/test/run-pass/dst-struct.rs @@ -0,0 +1,127 @@ +// 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. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo2(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo3(x: &Fat>) { + let y = &x.ptr.ptr; + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr.ptr[1] == 2); +} + + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + + // Deeply nested. + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(&f1); + let f2 = &f1; + foo3(f2); + let f3: &Fat> = f2; + foo3(f3); + let f4: &Fat> = &f1; + foo3(f4); + let f5: &Fat> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(f5); + + // Box. + let f1 = box [1i, 2, 3]; + assert!((*f1)[1] == 2); + let f2: Box<[int]> = f1; + assert!((*f2)[1] == 2); + + // Nested Box. + let f1 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f1); + let f2 : Box> = f1; + foo(&*f2); + let f3 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f3); +} diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs new file mode 100644 index 0000000000000..7429136716c96 --- /dev/null +++ b/src/test/run-pass/dst-trait.rs @@ -0,0 +1,111 @@ +// 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. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } + fn to_val(&self) -> int { + 0 + } +} +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +// x is a fat pointer +fn foo(x: &Fat) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.to_bar() == Bar); + assert!(x.ptr.to_val() == 42); + + let y = &x.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); +} + +fn bar(x: &ToBar) { + assert!(x.to_bar() == Bar); + assert!(x.to_val() == 42); +} + +fn baz(x: &Fat>) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.to_bar() == Bar); + assert!(x.ptr.ptr.to_val() == 42); + + let y = &x.ptr.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); + +} + +pub fn main() { + let f1 = Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat = f2; + foo(f3); + let f4: &Fat = &f1; + foo(f4); + let f5: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(f5); + + // Zero size object. + let f6: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar }; + assert!(f6.ptr.to_bar() == Bar); + + // &* + let f7: Box = box Bar1 {f :42}; + bar(&*f7); + + // Deep nesting + let f1 = + Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(&f1); + let f2 = &f1; + baz(f2); + let f3: &Fat> = f2; + baz(f3); + let f4: &Fat> = &f1; + baz(f4); + let f5: &Fat> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(f5); +} diff --git a/src/test/run-pass/evec-slice.rs b/src/test/run-pass/evec-slice.rs index 9c5995b7ba010..4a112f145c3ed 100644 --- a/src/test/run-pass/evec-slice.rs +++ b/src/test/run-pass/evec-slice.rs @@ -14,7 +14,7 @@ extern crate debug; pub fn main() { let x : &[int] = &[1,2,3,4,5]; - let mut z = &[1,2,3,4,5]; + let mut z : &[int] = &[1,2,3,4,5]; z = x; assert_eq!(z[0], 1); assert_eq!(z[4], 5); diff --git a/src/test/run-pass/gc-vec.rs b/src/test/run-pass/gc-vec.rs new file mode 100644 index 0000000000000..d2f43aacd66ab --- /dev/null +++ b/src/test/run-pass/gc-vec.rs @@ -0,0 +1,22 @@ +// 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. + +use std::gc::{GC}; + +fn main() { + // A fixed-size array allocated in a garbage-collected box + let x = box(GC) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(x[0], 1); + assert_eq!(x[6], 7); + assert_eq!(x[9], 10); + + let y = x; + assert!(*y == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +} diff --git a/src/test/run-pass/issue-7012.rs b/src/test/run-pass/issue-7012.rs index 4e74a7a1ecfe0..96db28f4a101f 100644 --- a/src/test/run-pass/issue-7012.rs +++ b/src/test/run-pass/issue-7012.rs @@ -22,6 +22,7 @@ static test1: signature<'static> = signature { }; pub fn main() { - let test = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32,0x03707344u32,0xa4093822u32,0x299f31d0u32]; + let test: &[u32] = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32, + 0x03707344u32,0xa4093822u32,0x299f31d0u32]; println!("{}",test==test1.pattern); } diff --git a/src/test/run-pass/issue-9259.rs b/src/test/run-pass/issue-9259.rs index 35f51efe135ca..2818b8249692a 100644 --- a/src/test/run-pass/issue-9259.rs +++ b/src/test/run-pass/issue-9259.rs @@ -14,7 +14,7 @@ struct A<'a> { } pub fn main() { - let b = &["foo".to_string()]; + let b: &[String] = &["foo".to_string()]; let a = A { a: &["test".to_string()], b: Some(b), diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 0b5406b8f67d5..2d54663993925 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -81,5 +81,6 @@ pub fn main() { // Check the final states. assert_eq!(*n, 2); - assert_eq!((*v).as_slice(), &[1, 2]); + let expected: &[_] = &[1, 2]; + assert_eq!((*v).as_slice(), expected); } diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 596e56b424a30..f599a2b7ad55c 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -61,6 +61,8 @@ impl TyVisitor for MyVisitor { fn visit_char(&mut self) -> bool { true } fn visit_estr_slice(&mut self) -> bool { true } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, _sz: uint, _sz2: uint, _align: uint) -> bool { true } @@ -72,7 +74,7 @@ impl TyVisitor for MyVisitor { fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool { true } fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint, - _mtbl: uint, _inner: *const TyDesc) -> bool { true } + _inner: *const TyDesc) -> bool { true } fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index 4f1a3817fabd7..52e7118653766 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -22,6 +22,7 @@ extern "rust-intrinsic" { fn transmute(t: T) -> U; } #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] pub trait Sized {} #[start] #[no_split_stack] diff --git a/src/test/run-pass/vec-dst.rs b/src/test/run-pass/vec-dst.rs new file mode 100644 index 0000000000000..809dde38eb498 --- /dev/null +++ b/src/test/run-pass/vec-dst.rs @@ -0,0 +1,115 @@ +// 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. + +extern crate debug; + +fn reflect() { + // Tests for reflective printing. + // Also tests drop glue. + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + assert!(format!("{:?}", x) == "[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", x2) == "[(), (), ()]".to_string()); + assert!(format!("{:?}", e1) == "[]".to_string()); + assert!(format!("{:?}", e2) == "[]".to_string()); + assert!(format!("{:?}", e3) == "[]".to_string()); + + let rx: &[uint, ..4] = &x; + let rx2: &[(), ..3] = &x2; + let re1: &[uint, ..0] = &e1; + let re2: &[&'static str, ..0] = &e2; + let re3: &[(), ..0] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + let rx: &[uint] = &x; + let rx2: &[()] = &x2; + let re1: &[uint] = &e1; + let re2: &[&'static str] = &e2; + let re3: &[()] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + // FIXME(15049) These should all work some day. + /*let rx: Box<[uint, ..4]> = box x; + let rx2: Box<[(), ..3]> = box x2; + let re1: Box<[uint, ..0]> = box e1; + let re2: Box<[&'static str, ..0]> = box e2; + let re3: Box<[(), ..0]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string()); + + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + let rx: Box<[uint]> = box x; + let rx2: Box<[()]> = box x2; + let re1: Box<[uint]> = box e1; + let re2: Box<[&'static str]> = box e2; + let re3: Box<[()]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string());*/ +} + +fn sub_expr() { + // Test for a &[T] => &&[T] coercion in sub-expression position + // (surpisingly, this can cause errors which are not caused by either of: + // `let x = vec.mut_slice(0, 2);` + // `foo(vec.mut_slice(0, 2));` ). + let mut vec: Vec = vec!(1, 2, 3, 4); + let b: &mut [int] = [1, 2]; + assert!(vec.mut_slice(0, 2) == b); +} + +fn index() { + // Tests for indexing into box/& [T, ..n] + let x: [int, ..3] = [1, 2, 3]; + let mut x: Box<[int, ..3]> = box x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); + + let mut x: [int, ..3] = [1, 2, 3]; + let x: &mut [int, ..3] = &mut x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); +} + +pub fn main() { + reflect(); + sub_expr(); + index(); +} From 52ef46251ede1ff51e5d5621d5fe2614e950f963 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 6 Aug 2014 11:59:40 +0200 Subject: [PATCH 4/5] Rebasing changes --- src/libcollections/ringbuf.rs | 6 +- src/libcollections/str.rs | 13 +- src/libcollections/string.rs | 6 +- src/libcore/cmp.rs | 5 +- src/libcore/option.rs | 5 +- src/libcore/raw.rs | 4 +- src/libcore/slice.rs | 21 ++ src/libcoretest/iter.rs | 4 +- src/libdebug/reflect.rs | 2 +- src/libdebug/repr.rs | 2 +- src/liblibc/lib.rs | 2 +- src/librbml/io.rs | 18 +- src/librlibc/lib.rs | 2 +- src/librustc/diagnostics.rs | 6 - src/librustc/front/test.rs | 4 +- src/librustc/lint/builtin.rs | 3 + src/librustc/middle/astencode.rs | 12 +- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/intrinsicck.rs | 5 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/subst.rs | 2 +- src/librustc/middle/trans/_match.rs | 2 +- src/librustc/middle/trans/adt.rs | 76 ++++--- src/librustc/middle/trans/base.rs | 61 +++-- src/librustc/middle/trans/callee.rs | 1 + src/librustc/middle/trans/common.rs | 3 + src/librustc/middle/trans/consts.rs | 10 +- src/librustc/middle/trans/controlflow.rs | 4 +- src/librustc/middle/trans/datum.rs | 7 +- src/librustc/middle/trans/debuginfo.rs | 36 +-- src/librustc/middle/trans/expr.rs | 114 +++++----- src/librustc/middle/trans/glue.rs | 208 ++++++++++++++++-- src/librustc/middle/trans/intrinsic.rs | 18 +- src/librustc/middle/trans/meth.rs | 19 +- src/librustc/middle/trans/reflect.rs | 32 ++- src/librustc/middle/trans/tvec.rs | 51 ++++- src/librustc/middle/trans/type_of.rs | 24 +- src/librustc/middle/ty.rs | 61 ++--- src/librustc/middle/ty_fold.rs | 18 +- src/librustc/middle/typeck/check/method.rs | 4 +- src/librustc/middle/typeck/check/mod.rs | 131 +++++------ src/librustc/middle/typeck/check/vtable.rs | 21 +- src/librustc/middle/typeck/infer/coercion.rs | 15 +- src/librustc/util/ppaux.rs | 2 +- src/libserialize/serialize.rs | 1 - src/libsyntax/parse/parser.rs | 31 +-- src/libtime/lib.rs | 37 +--- src/libunicode/u_str.rs | 9 +- src/liburl/lib.rs | 6 +- src/rt/rust_builtin.c | 42 +--- .../const-cast-different-types.rs | 6 +- src/test/compile-fail/dst-bad-assign-2.rs | 2 +- src/test/compile-fail/dst-bad-assign.rs | 4 +- src/test/compile-fail/dst-bad-coerce1.rs | 4 +- src/test/compile-fail/dst-bad-coerce2.rs | 2 +- src/test/compile-fail/dst-bad-coerce3.rs | 2 +- src/test/compile-fail/dst-bad-coerce4.rs | 4 +- src/test/compile-fail/dst-bad-deep.rs | 2 +- src/test/compile-fail/issue-3907-2.rs | 4 +- src/test/compile-fail/issue-4972.rs | 2 +- src/test/compile-fail/issue-5035-2.rs | 4 +- src/test/compile-fail/issue-5883.rs | 2 +- src/test/compile-fail/issue-7013.rs | 2 +- src/test/compile-fail/tuple-arity-mismatch.rs | 2 +- src/test/pretty/issue-4264.pp | 6 +- .../graphviz-flowgraph/f15.dot-expected.dot | 2 +- .../graphviz-flowgraph/f16.dot-expected.dot | 2 +- src/test/run-pass/dst-dtor-1.rs | 34 +++ src/test/run-pass/dst-dtor-2.rs | 31 +++ src/test/run-pass/dst-struct-reflect.rs | 4 +- src/test/run-pass/dst-struct-sole.rs | 2 +- src/test/run-pass/dst-struct.rs | 2 +- src/test/run-pass/dst-trait.rs | 2 +- src/test/run-pass/gc-vec.rs | 4 +- src/test/run-pass/issue-14936.rs | 3 +- src/test/run-pass/issue-15080.rs | 2 +- src/test/run-pass/match-vec-alternatives.rs | 22 +- src/test/run-pass/order-drop-with-match.rs | 3 +- src/test/run-pass/vec-matching.rs | 3 +- src/test/run-pass/vec-to_str.rs | 4 +- 80 files changed, 851 insertions(+), 487 deletions(-) create mode 100644 src/test/run-pass/dst-dtor-1.rs create mode 100644 src/test/run-pass/dst-dtor-2.rs diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index d2cfb510bc058..2f0fbfadb17f3 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -243,7 +243,8 @@ impl RingBuf { /// buf.push(5i); /// buf.push(3); /// buf.push(4); - /// assert_eq!(buf.iter().collect::>().as_slice(), &[&5, &3, &4]); + /// let b: &[_] = &[&5, &3, &4]; + /// assert_eq!(buf.iter().collect::>().as_slice(), b); /// ``` pub fn iter<'a>(&'a self) -> Items<'a, T> { Items{index: 0, rindex: self.nelts, lo: self.lo, elts: self.elts.as_slice()} @@ -263,7 +264,8 @@ impl RingBuf { /// for num in buf.mut_iter() { /// *num = *num - 2; /// } - /// assert_eq!(buf.mut_iter().collect::>().as_slice(), &[&mut 3, &mut 1, &mut 2]); + /// let b: &[_] = &[&mut 3, &mut 1, &mut 2]; + /// assert_eq!(buf.mut_iter().collect::>().as_slice(), b); /// ``` pub fn mut_iter<'a>(&'a mut self) -> MutItems<'a, T> { let start_index = raw_index(self.lo, self.elts.len(), 0); diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 1145e1f357319..3f9a179872e14 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1971,7 +1971,7 @@ mod tests { use std::iter::order; // official Unicode test data // from http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt - let test_same = [ + let test_same: [(_, &[_]), .. 325] = [ ("\u0020\u0020", &["\u0020", "\u0020"]), ("\u0020\u0308\u0020", &["\u0020\u0308", "\u0020"]), ("\u0020\u000D", &["\u0020", "\u000D"]), ("\u0020\u0308\u000D", &["\u0020\u0308", "\u000D"]), ("\u0020\u000A", &["\u0020", "\u000A"]), @@ -2180,7 +2180,7 @@ mod tests { ("\u0646\u200D\u0020", &["\u0646\u200D", "\u0020"]), ]; - let test_diff = [ + let test_diff: [(_, &[_], &[_]), .. 23] = [ ("\u0020\u0903", &["\u0020\u0903"], &["\u0020", "\u0903"]), ("\u0020\u0308\u0903", &["\u0020\u0308\u0903"], &["\u0020\u0308", "\u0903"]), ("\u000D\u0308\u0903", &["\u000D", "\u0308\u0903"], &["\u000D", "\u0308", "\u0903"]), ("\u000A\u0308\u0903", @@ -2229,9 +2229,11 @@ mod tests { // test the indices iterators let s = "a̐éö̲\r\n"; let gr_inds = s.grapheme_indices(true).collect::>(); - assert_eq!(gr_inds.as_slice(), &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]); + let b: &[_] = &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]; + assert_eq!(gr_inds.as_slice(), b); let gr_inds = s.grapheme_indices(true).rev().collect::>(); - assert_eq!(gr_inds.as_slice(), &[(11, "\r\n"), (6, "ö̲"), (3, "é"), (0u, "a̐")]); + let b: &[_] = &[(11, "\r\n"), (6, "ö̲"), (3, "é"), (0u, "a̐")]; + assert_eq!(gr_inds.as_slice(), b); let mut gr_inds = s.grapheme_indices(true); let e1 = gr_inds.size_hint(); assert_eq!(e1, (1, Some(13))); @@ -2243,7 +2245,8 @@ mod tests { // make sure the reverse iterator does the right thing with "\n" at beginning of string let s = "\n\r\n\r"; let gr = s.graphemes(true).rev().collect::>(); - assert_eq!(gr.as_slice(), &["\r", "\r\n", "\n"]); + let b: &[_] = &["\r", "\r\n", "\n"]; + assert_eq!(gr.as_slice(), b); } #[test] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 89fdc4d42fb88..05d91a7504150 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -531,7 +531,8 @@ impl String { /// /// ``` /// let s = String::from_str("hello"); - /// assert_eq!(s.as_bytes(), &[104, 101, 108, 108, 111]); + /// let b: &[_] = &[104, 101, 108, 108, 111]; + /// assert_eq!(s.as_bytes(), b); /// ``` #[inline] pub fn as_bytes<'a>(&'a self) -> &'a [u8] { @@ -552,7 +553,8 @@ impl String { /// bytes[1] = 51; /// bytes[4] = 48; /// } - /// assert_eq!(s.as_bytes(), &[104, 51, 108, 108, 48]); + /// let b: &[_] = &[104, 51, 108, 108, 48]; + /// assert_eq!(s.as_bytes(), b); /// assert_eq!(s.as_slice(), "h3ll0") /// ``` #[inline] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index bfd10c835e206..b90c6daf9ebae 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -112,12 +112,13 @@ impl Ordering { /// assert_eq!(Greater.reverse(), Less); /// /// - /// let mut data = &mut [2u, 10, 5, 8]; + /// let mut data: &mut [_] = &mut [2u, 10, 5, 8]; /// /// // sort the array from largest to smallest. /// data.sort_by(|a, b| a.cmp(b).reverse()); /// - /// assert_eq!(data, &mut [10u, 8, 5, 2]); + /// let b: &mut [_] = &mut [10u, 8, 5, 2]; + /// assert!(data == b); /// ``` #[inline] #[experimental] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 47df8ae68cdd2..7773e03416e9e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -530,7 +530,10 @@ impl Slice for Option { fn as_slice<'a>(&'a self) -> &'a [T] { match *self { Some(ref x) => slice::ref_slice(x), - None => &[] + None => { + let result: &[_] = &[]; + result + } } } } diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index aa8a4976867a6..5daa693c77400 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -58,8 +58,8 @@ pub struct TraitObject { } #[cfg(not(stage0))] pub struct TraitObject { - pub data: *(), - pub vtable: *(), + pub data: *mut (), + pub vtable: *mut (), } /// This trait is meant to map equivalences between raw structs and their diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 8c55662f16395..475c2e94ec778 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1648,6 +1648,27 @@ impl<'a,T:PartialEq, V: Slice> Equiv for &'a [T] { fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() } } +#[unstable = "waiting for DST"] +impl<'a,T:PartialEq> PartialEq for &'a mut [T] { + fn eq(&self, other: & &'a mut [T]) -> bool { + self.len() == other.len() && + order::eq(self.iter(), other.iter()) + } + fn ne(&self, other: & &'a mut [T]) -> bool { + self.len() != other.len() || + order::ne(self.iter(), other.iter()) + } +} + +#[unstable = "waiting for DST"] +impl<'a,T:Eq> Eq for &'a mut [T] {} + +#[unstable = "waiting for DST"] +impl<'a,T:PartialEq, V: Slice> Equiv for &'a mut [T] { + #[inline] + fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() } +} + #[unstable = "waiting for DST"] impl<'a,T:Ord> Ord for &'a [T] { fn cmp(&self, other: & &'a [T]) -> Ordering { diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index d25ffb5b84c8a..99ac7cfed027f 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -368,7 +368,7 @@ fn test_collect() { #[test] fn test_all() { - let v: Box<&[int]> = box &[1i, 2, 3, 4, 5]; + let v: Box<[int]> = box [1i, 2, 3, 4, 5]; assert!(v.iter().all(|&x| x < 10)); assert!(!v.iter().all(|&x| x % 2 == 0)); assert!(!v.iter().all(|&x| x > 100)); @@ -377,7 +377,7 @@ fn test_all() { #[test] fn test_any() { - let v: Box<&[int]> = box &[1i, 2, 3, 4, 5]; + let v: Box<[int]> = box [1i, 2, 3, 4, 5]; assert!(v.iter().any(|&x| x < 10)); assert!(v.iter().any(|&x| x % 2 == 0)); assert!(!v.iter().any(|&x| x > 100)); diff --git a/src/libdebug/reflect.rs b/src/libdebug/reflect.rs index 0d7209b599970..b89ea4d373ddc 100644 --- a/src/libdebug/reflect.rs +++ b/src/libdebug/reflect.rs @@ -251,7 +251,7 @@ impl TyVisitor for MovePtrAdaptor { } #[cfg(not(stage0))] fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint, - inner: *TyDesc) -> bool { + inner: *const TyDesc) -> bool { self.align(align); if ! self.inner.visit_evec_fixed(n, sz, align, inner) { return false; diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index c810e1f64737f..20f96d24a5f5f 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -342,7 +342,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { #[cfg(not(stage0))] fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, - inner: *TyDesc) -> bool { + inner: *const TyDesc) -> bool { let assumed_size = if sz == 0 { n } else { sz }; self.get::<()>(|this, b| { this.write_vec_range(b, assumed_size, inner) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 265d1e37ec389..949dd08eaa343 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -302,7 +302,7 @@ extern {} /// A wrapper for a nullable pointer. Don't use this except for interacting /// with libc. Basically Option, but without the dependence on libstd. // If/when libprim happens, this can be removed in favor of that -pub enum Nullable { +pub enum Nullable { Null, NotNull(T) } diff --git a/src/librbml/io.rs b/src/librbml/io.rs index 9ab163c5f4740..443bf4d34ffa1 100644 --- a/src/librbml/io.rs +++ b/src/librbml/io.rs @@ -96,7 +96,8 @@ impl Writer for SeekableMemWriter { let (left, right) = if cap <= buf.len() { (buf.slice_to(cap), buf.slice_from(cap)) } else { - (buf, &[]) + let result: (_, &[_]) = (buf, &[]); + result }; // Do the necessary writes @@ -142,24 +143,29 @@ mod tests { writer.write([1, 2, 3]).unwrap(); writer.write([4, 5, 6, 7]).unwrap(); assert_eq!(writer.tell(), Ok(8)); - assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.get_ref(), b); writer.seek(0, io::SeekSet).unwrap(); assert_eq!(writer.tell(), Ok(0)); writer.write([3, 4]).unwrap(); - assert_eq!(writer.get_ref(), &[3, 4, 2, 3, 4, 5, 6, 7]); + let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer.get_ref(), b); writer.seek(1, io::SeekCur).unwrap(); writer.write([0, 1]).unwrap(); - assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 7]); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; + assert_eq!(writer.get_ref(), b); writer.seek(-1, io::SeekEnd).unwrap(); writer.write([1, 2]).unwrap(); - assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2]); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; + assert_eq!(writer.get_ref(), b); writer.seek(1, io::SeekEnd).unwrap(); writer.write([1]).unwrap(); - assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; + assert_eq!(writer.get_ref(), b); } #[test] diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index b43ad1eabf90c..739ec2cf43ffe 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -49,7 +49,7 @@ // implementations below. If pointer arithmetic is done through integers the // optimizations start to break down. extern "rust-intrinsic" { - fn offset(dst: *const T, offset: int) -> *const T; + fn offset(dst: *const T, offset: int) -> *const T; } #[no_mangle] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index a789049d4de8c..77e73c46c402c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -34,7 +34,6 @@ register_diagnostics!( E0015, E0016, E0017, - E0018, E0019, E0020, E0021, @@ -53,7 +52,6 @@ register_diagnostics!( E0034, E0035, E0036, - E0037, E0038, E0039, E0040, @@ -80,8 +78,6 @@ register_diagnostics!( E0061, E0062, E0063, - E0064, - E0065, E0066, E0067, E0068, @@ -127,8 +123,6 @@ register_diagnostics!( E0108, E0109, E0110, - E0111, - E0112, E0113, E0114, E0115, diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 9984aba8d08ab..5f26a966f97e7 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -477,10 +477,10 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc { box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprAddrOf(box(GC) ast::MutImmutable, + node: ast::ExprAddrOf(ast::MutImmutable, box(GC) ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprVec(cx.testfns.borrow().iter().map(|test| { + node: ast::ExprVec(cx.testfns.iter().map(|test| { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 6cc1c6a7b37df..214401b17a1bb 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1556,6 +1556,9 @@ declare_lint!(pub UNKNOWN_CRATE_TYPE, Deny, declare_lint!(pub VARIANT_SIZE_DIFFERENCE, Allow, "detects enums with widely varying variant sizes") +declare_lint!(pub TRANSMUTE_FAT_PTR, Allow, + "detects transmutes of fat pointers") + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. pub struct HardwiredLints; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 260e38f20708f..6a8ee2675425f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1029,6 +1029,8 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { } fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef) { + use serialize::Encoder; + self.emit_enum("AutoRef", |this| { match autoref { &ty::AutoPtr(r, m, None) => { @@ -1067,6 +1069,8 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { } fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef) { + use serialize::Encoder; + self.emit_struct("AutoDerefRef", 2, |this| { this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); this.emit_struct_field("autoref", 1, |this| { @@ -1081,6 +1085,8 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { } fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind) { + use serialize::Encoder; + self.emit_enum("UnsizeKind", |this| { match *uk { ty::UnsizeLength(len) => { @@ -1286,7 +1292,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, _ if ty::adjust_is_object(adjustment) => { let method_call = MethodCall::autoobject(id); for &method in tcx.method_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_method_map, |ebml_w| { + rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { encode_method_callee(ecx, rbml_w, method_call.adjustment, method) @@ -1297,7 +1303,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |ebml_w| { + rbml_w.tag(c::tag_table_val, |rbml_w| { encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); }) }) @@ -1336,7 +1342,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_adjustments, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_auto_adjustment(ecx, adj); + rbml_w.emit_auto_adjustment(ecx, adjustment); }) }) } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index b0b2fe89c3f0f..629aba8092c27 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -182,7 +182,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) { // Mutable slices are allowed. ExprVec(_) => {} _ => span_err!(v.tcx.sess, e.span, E0017, - "references in constants may only refer to immutable values"); + "references in constants may only refer to immutable values") } }, diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 6669147b0dcac..639f89dc3cced 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -92,7 +92,7 @@ impl<'a> IntrinsicCheckingVisitor<'a> { } } - fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) { + fn check_transmute(&self, span: Span, from: ty::t, to: ty::t, id: ast::NodeId) { if type_size_is_affected_by_type_parameters(self.tcx, from) { span_err!(self.tcx.sess, span, E0139, "cannot transmute from a type that contains type parameters"); @@ -106,6 +106,7 @@ impl<'a> IntrinsicCheckingVisitor<'a> { span: span, from: from, to: to, + id: id, }; self.tcx.transmute_restrictions.borrow_mut().push(restriction); } @@ -123,7 +124,7 @@ impl<'a> Visitor<()> for IntrinsicCheckingVisitor<'a> { if bare_fn_ty.abi == RustIntrinsic => { let from = *bare_fn_ty.sig.inputs.get(0); let to = bare_fn_ty.sig.output; - self.check_transmute(expr.span, from, to); + self.check_transmute(expr.span, from, to, expr.id); } _ => { self.tcx diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 155b69d0a84c2..2d052feb6720f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -214,7 +214,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option { } pub fn deref_kind(tcx: &ty::ctxt, t: ty::t) -> deref_kind { - debug!("deref_kind {}", ty_to_str(tcx, t)); + debug!("deref_kind {}", ty_to_string(tcx, t)); match opt_deref_kind(t) { Some(k) => k, None => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 673872103af60..ccc4dbb21e019 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -403,7 +403,7 @@ impl VecPerParamSpace { self.content.slice(start, limit) } - fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] { + pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] { let (start, limit) = self.limits(space); self.content.mut_slice(start, limit) } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 4a26d4f800210..28f396c8bf795 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -280,7 +280,7 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> { match *o { lit(lit_expr) => { let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id); - let (llval, _) = consts::const_expr(ccx, &*lit_expr, true); + let (llval, _, _) = consts::const_expr(ccx, &*lit_expr, true); let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); return single_result(Result::new(bcx, lit_datum.val)); diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 3bcefe7ec9dbb..f3f4a88fdee4f 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -127,11 +127,11 @@ pub enum Repr { /// For structs, and struct-like parts of anything fancier. pub struct Struct { - // If the struct is DST, then we will not know its size. We must be careful - // never to use such a struct when a fixed size is required (e.g., stack - // allocation). - pub size: Option, - pub align: Option, + // If the struct is DST, then the size and alignment do not take into + // account the unsized fields of the struct. + pub size: u64, + pub align: u64, + pub sized: bool, pub packed: bool, pub fields: Vec } @@ -269,7 +269,7 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { }).collect(), dtor); } _ => cx.sess().bug(format!("adt::represent_type called on non-ADT type: {}", - ty_to_str(cx.tcx(), t)).as_slice()) + ty_to_string(cx.tcx(), t)).as_slice()) } } @@ -288,7 +288,7 @@ pub enum PointerField { impl Case { fn is_zerolen(&self, cx: &CrateContext) -> bool { - mk_struct(cx, self.tys.as_slice(), false).size.unwrap() == 0 + mk_struct(cx, self.tys.as_slice(), false).size == 0 } fn find_ptr(&self) -> Option { @@ -310,7 +310,7 @@ impl Case { // Box could either be a thin or fat pointer depending on T ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_vec(_, None) | return Some(FatPointer(i, slice_elt_base)), + ty::ty_vec(_, None) => return Some(FatPointer(i, slice_elt_base)), // Box is a pair of pointers: the actual object and a vtable ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)), @@ -351,18 +351,24 @@ fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct { let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::>(); let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); Struct { - size: Some(machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64), - align: Some(machine::llalign_of_min(cx, llty_rec) /*bad*/as u64), + size: machine::llsize_of_alloc(cx, llty_rec), + align: machine::llalign_of_min(cx, llty_rec), + sized: true, packed: packed, fields: Vec::from_slice(tys), } } else { + // Ignore any dynamically sized fields. + let lltys = tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty)) + .map(|&ty| type_of::sizing_type_of(cx, ty)).collect::>(); + let llty_rec = Type::struct_(cx, lltys.as_slice(), packed); Struct { - size: None, - align: None, + size: machine::llsize_of_alloc(cx, llty_rec), + align: machine::llalign_of_min(cx, llty_rec), + sized: false, packed: packed, fields: Vec::from_slice(tys), - } + } } } @@ -467,31 +473,38 @@ pub fn ty_of_inttype(ity: IntType) -> ty::t { * unbounded recursion; see also the comments in `trans::type_of`. */ pub fn type_of(cx: &CrateContext, r: &Repr) -> Type { - generic_type_of(cx, r, None, false) + generic_type_of(cx, r, None, false, false) } -pub fn sizing_type_of(cx: &CrateContext, r: &Repr) -> Type { - generic_type_of(cx, r, None, true) +// Pass dst=true if the type you are passing is a DST. Yes, we could figure +// this out, but if you call this on an unsized type without realising it, you +// are going to get the wrong type (it will not include the unsized parts of it). +pub fn sizing_type_of(cx: &CrateContext, r: &Repr, dst: bool) -> Type { + generic_type_of(cx, r, None, true, dst) } pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type { - generic_type_of(cx, r, Some(name), false) + generic_type_of(cx, r, Some(name), false, false) } pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) { match *r { CEnum(..) | General(..) | RawNullablePointer { .. } => { } Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => - llty.set_struct_body(struct_llfields(cx, st, false).as_slice(), + llty.set_struct_body(struct_llfields(cx, st, false, false).as_slice(), st.packed) } } -fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type { +fn generic_type_of(cx: &CrateContext, + r: &Repr, + name: Option<&str>, + sizing: bool, + dst: bool) -> Type { match *r { CEnum(ity, _, _) => ll_inttype(cx, ity), RawNullablePointer { nnty, .. } => type_of::sizing_type_of(cx, nnty), Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => { match name { None => { - Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(), + Type::struct_(cx, struct_llfields(cx, st, sizing, dst).as_slice(), st.packed) } Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) } @@ -510,9 +523,9 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool // of the size. // // FIXME #10604: this breaks when vector types are present. - let size = sts.iter().map(|st| st.size.unwrap()).max().unwrap(); - let most_aligned = sts.iter().max_by(|st| st.align.unwrap()).unwrap(); - let align = most_aligned.align.unwrap(); + let size = sts.iter().map(|st| st.size).max().unwrap(); + let most_aligned = sts.iter().max_by(|st| st.align).unwrap(); + let align = most_aligned.align; let discr_ty = ll_inttype(cx, ity); let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64; let align_units = (size + align - 1) / align - 1; @@ -543,9 +556,10 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool } } -fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec { +fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool, dst: bool) -> Vec { if sizing { - st.fields.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect() + st.fields.iter().filter(|&ty| !dst || ty::type_is_sized(cx.tcx(), *ty)) + .map(|&ty| type_of::sizing_type_of(cx, ty)).collect() } else { st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect() } @@ -906,12 +920,12 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr, } General(ity, ref cases, _) => { let case = cases.get(discr as uint); - let max_sz = cases.iter().map(|x| x.size.unwrap()).max().unwrap(); + let max_sz = cases.iter().map(|x| x.size).max().unwrap(); let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true); let contents = build_const_struct(ccx, case, (vec!(lldiscr)).append(vals).as_slice()); - C_struct(ccx, contents.append([padding(ccx, max_sz - case.size.unwrap())]).as_slice(), + C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(), false) } Univariant(ref st, _dro) => { @@ -958,7 +972,7 @@ fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec { for &ty in st.fields.iter() { let llty = type_of::sizing_type_of(ccx, ty); if !st.packed { - let type_align = machine::llalign_of_min(ccx, llty) as u64; + let type_align = type_of::align_of(ccx, ty) as u64; offset = roundup(offset, type_align); } offsets.push(offset); @@ -1002,9 +1016,9 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef]) offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64; } - assert!(offset <= st.size.unwrap()); - if offset != st.size.unwrap() { - cfields.push(padding(ccx, st.size.unwrap() - offset)); + assert!(st.sized && offset <= st.size); + if offset != st.size { + cfields.push(padding(ccx, st.size - offset)); } cfields diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index b27afdb864b97..8968c8cc2599f 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -65,7 +65,7 @@ use middle::trans::glue; use middle::trans::inline; use middle::trans::intrinsic; use middle::trans::machine; -use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; +use middle::trans::machine::{llsize_of, llsize_of_real}; use middle::trans::meth; use middle::trans::monomorphize; use middle::trans::tvec; @@ -394,7 +394,7 @@ pub fn malloc_raw_dyn_managed<'a>( // Grab the TypeRef type of box_ptr_ty. let box_ptr_ty = ty::mk_box(bcx.tcx(), t); let llty = type_of(ccx, box_ptr_ty); - let llalign = C_uint(ccx, llalign_of_min(ccx, llty) as uint); + let llalign = C_uint(ccx, type_of::align_of(ccx, box_ptr_ty) as uint); // Allocate space: let drop_glue = glue::get_drop_glue(ccx, t); @@ -710,14 +710,33 @@ pub fn iter_structural_ty<'r, return cx; } + let (data_ptr, info) = if ty::type_is_sized(cx.tcx(), t) { + (av, None) + } else { + let data = GEPi(cx, av, [0, abi::slice_elt_base]); + let info = GEPi(cx, av, [0, abi::slice_elt_len]); + (Load(cx, data), Some(Load(cx, info))) + }; + let mut cx = cx; match ty::get(t).sty { ty::ty_struct(..) => { let repr = adt::represent_type(cx.ccx(), t); expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| { for (i, field_ty) in field_tys.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &*repr, av, discr, i); - cx = f(cx, llfld_a, field_ty.mt.ty); + let field_ty = field_ty.mt.ty; + let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i); + + let val = if ty::type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let boxed_ty = ty::mk_open(cx.tcx(), field_ty); + let scratch = datum::rvalue_scratch_datum(cx, boxed_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, GEPi(cx, scratch.val, [0, abi::slice_elt_base])); + Store(cx, info.unwrap(), GEPi(cx, scratch.val, [0, abi::slice_elt_len])); + scratch.val + }; + cx = f(cx, val, field_ty); } }) } @@ -725,19 +744,19 @@ pub fn iter_structural_ty<'r, let repr = adt::represent_type(cx.ccx(), t); let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id); for (i, upvar) in upvars.iter().enumerate() { - let llupvar = adt::trans_field_ptr(cx, &*repr, av, 0, i); + let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i); cx = f(cx, llupvar, upvar.ty); } } ty::ty_vec(_, Some(n)) => { - let (base, len) = tvec::get_fixed_base_and_len(cx, av, n); + let (base, len) = tvec::get_fixed_base_and_len(cx, data_ptr, n); let unit_ty = ty::sequence_element_type(cx.tcx(), t); cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f); } ty::ty_tup(ref args) => { let repr = adt::represent_type(cx.ccx(), t); for (i, arg) in args.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &*repr, av, 0, i); + let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i); cx = f(cx, llfld_a, *arg); } } @@ -781,7 +800,7 @@ pub fn iter_structural_ty<'r, let variant_cx = iter_variant(variant_cx, &*repr, - av, + data_ptr, &**variant, substs, |x,y,z| f(x,y,z)); @@ -968,7 +987,7 @@ pub fn invoke<'a>( // FIXME(15064) Lang item methods may (in the reflect case) not have proper // types, so doing an attribute lookup will fail. let attributes = if is_lang_item { - Vec::new() + llvm::AttrBuilder::new() } else { get_fn_llvm_attributes(bcx.ccx(), fn_ty) }; @@ -1158,7 +1177,7 @@ pub fn memcpy_ty(bcx: &Block, dst: ValueRef, src: ValueRef, t: ty::t) { if ty::type_is_structural(t) { let llty = type_of::type_of(ccx, t); let llsz = llsize_of(ccx, llty); - let llalign = llalign_of_min(ccx, llty); + let llalign = type_of::align_of(ccx, t); call_memcpy(bcx, dst, src, llsz, llalign as u32); } else { store_ty(bcx, Load(bcx, src), dst, t); @@ -1169,9 +1188,7 @@ pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) { if cx.unreachable.get() { return; } let _icx = push_ctxt("zero_mem"); let bcx = cx; - let ccx = cx.ccx(); - let llty = type_of::type_of(ccx, t); - memzero(&B(bcx), llptr, llty); + memzero(&B(bcx), llptr, t); } // Always use this function instead of storing a zero constant to the memory @@ -1179,10 +1196,12 @@ pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) { // allocation for large data structures, and the generated code will be // awful. (A telltale sign of this is large quantities of // `mov [byte ptr foo],0` in the generated code.) -fn memzero(b: &Builder, llptr: ValueRef, ty: Type) { +fn memzero(b: &Builder, llptr: ValueRef, ty: ty::t) { let _icx = push_ctxt("memzero"); let ccx = b.ccx; + let llty = type_of::type_of(ccx, ty); + let intrinsic_key = match ccx.sess().targ_cfg.arch { X86 | Arm | Mips | Mipsel => "llvm.memset.p0i8.i32", X86_64 => "llvm.memset.p0i8.i64" @@ -1191,8 +1210,8 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) { let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key); let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to()); let llzeroval = C_u8(ccx, 0); - let size = machine::llsize_of(ccx, ty); - let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32); + let size = machine::llsize_of(ccx, llty); + let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32); let volatile = C_bool(ccx, false); b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], None); } @@ -1223,13 +1242,14 @@ pub fn alloca_no_lifetime(cx: &Block, ty: Type, name: &str) -> ValueRef { Alloca(cx, ty, name) } -pub fn alloca_zeroed(cx: &Block, ty: Type, name: &str) -> ValueRef { +pub fn alloca_zeroed(cx: &Block, ty: ty::t, name: &str) -> ValueRef { + let llty = type_of::type_of(cx.ccx(), ty); if cx.unreachable.get() { unsafe { - return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); + return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); } } - let p = alloca_no_lifetime(cx, ty, name); + let p = alloca_no_lifetime(cx, llty, name); let b = cx.fcx.ccx.builder(); b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); memzero(&b, p, ty); @@ -1648,7 +1668,8 @@ fn copy_unboxed_closure_args_to_allocas<'a>( for j in range(0, args.len()) { let tuple_element_type = untupled_arg_types[j]; let tuple_element_datum = - tuple_datum.get_element(tuple_element_type, + tuple_datum.get_element(bcx, + tuple_element_type, |llval| GEPi(bcx, llval, [0, j])); let tuple_element_datum = tuple_element_datum.to_expr_datum(); let tuple_element_datum = diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 1283cc19528a6..7566cfbac56c4 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -970,6 +970,7 @@ fn trans_args_under_call_abi<'a>( let repr_ptr = &*repr; for i in range(0, field_types.len()) { let arg_datum = tuple_lvalue_datum.get_element( + bcx, *field_types.get(i), |srcval| { adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f0876442ff5ae..05528d2b3d88e 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -74,6 +74,9 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool { if simple && !ty::type_is_fat_ptr(tcx, ty) { return true; } + if !ty::type_is_sized(tcx, ty) { + return false; + } match ty::get(ty).sty { ty::ty_bot => true, ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index e65a10b3bb243..b3798c9f84dd4 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -116,7 +116,7 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr, (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b)) } -pub fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef { +pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { unsafe { let gv = "const".with_c_str(|name| { llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name) @@ -279,7 +279,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef } _ => cx.sess().span_bug(e.span, format!("unimplemented type in const unsize: {}", - ty_to_str(cx.tcx(), ty)).as_slice()) + ty_to_string(cx.tcx(), ty)).as_slice()) } } _ => { @@ -455,7 +455,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, _ => cx.sess().span_bug(base.span, format!("index-expr base must be a vector \ or string type, found {}", - ty_to_str(cx.tcx(), bt)).as_slice()) + ty_to_string(cx.tcx(), bt)).as_slice()) }, ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty { ty::ty_vec(_, Some(u)) => { @@ -464,12 +464,12 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, _ => cx.sess().span_bug(base.span, format!("index-expr base must be a vector \ or string type, found {}", - ty_to_str(cx.tcx(), bt)).as_slice()) + ty_to_string(cx.tcx(), bt)).as_slice()) }, _ => cx.sess().span_bug(base.span, format!("index-expr base must be a vector \ or string type, found {}", - ty_to_str(cx.tcx(), bt)).as_slice()) + ty_to_string(cx.tcx(), bt)).as_slice()) }; let len = llvm::LLVMConstIntGetZExtValue(len) as u64; diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 7a1864448e26b..9ec5234134817 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -497,7 +497,7 @@ pub fn trans_fail<'a>( let filename = C_str_slice(ccx, filename); let line = C_int(ccx, loc.line as int); let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); - let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const); + let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const, ast::MutImmutable); let args = vec!(expr_file_line); let did = langcall(bcx, Some(sp), "", FailFnLangItem); let bcx = callee::trans_lang_call(bcx, @@ -525,7 +525,7 @@ pub fn trans_fail_bounds_check<'a>( let filename = C_str_slice(ccx, filename); let line = C_int(ccx, loc.line as int); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::const_addr_of(ccx, file_line_const); + let file_line = consts::const_addr_of(ccx, file_line_const, ast::MutImmutable); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index b7803d404b5bc..2882eaf10be2f 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -15,6 +15,7 @@ use llvm::ValueRef; use middle::trans::base::*; +use middle::trans::build::Load; use middle::trans::common::*; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; @@ -119,10 +120,10 @@ pub fn lvalue_scratch_datum<'a, A>(bcx: &'a Block<'a>, * does not dominate the end of `scope`. */ - let llty = type_of::type_of(bcx.ccx(), ty); let scratch = if zero { - alloca_zeroed(bcx, llty, name) + alloca_zeroed(bcx, ty, name) } else { + let llty = type_of::type_of(bcx.ccx(), ty); alloca(bcx, llty, name) }; @@ -524,7 +525,7 @@ impl Datum { } _ => bcx.tcx().sess.bug( format!("Unexpected unsized type in get_element: {}", - bcx.ty_to_str(self.ty)).as_slice()) + bcx.ty_to_string(self.ty)).as_slice()) }; Datum { val: val, diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 31b3122446493..566f71220b05f 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -56,10 +56,11 @@ This file consists of three conceptual sections: ## Recursive Types Some kinds of types, such as structs and enums can be recursive. That means that -the type definition of some type X refers to some other type which in turn (transitively) -refers to X. This introduces cycles into the type referral graph. A naive algorithm doing -an on-demand, depth-first traversal of this graph when describing types, can get trapped -in an endless loop when it reaches such a cycle. +the type definition of some type X refers to some other type which in turn +(transitively) refers to X. This introduces cycles into the type referral graph. +A naive algorithm doing an on-demand, depth-first traversal of this graph when +describing types, can get trapped in an endless loop when it reaches such a +cycle. For example, the following simple type for a singly-linked list... @@ -2798,25 +2799,33 @@ fn subroutine_type_metadata(cx: &CrateContext, false); } +// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill- +// defined concept. For the case of an actual trait pointer (i.e., Box, +// &Trait), trait_object_type should be the whole thing (e.g, Box) and +// trait_type should be the actual trait (e.g., Trait). Where the trait is part +// of a DST struct, there is no trait_object_type and the results of this +// function will be a little bit weird. fn trait_pointer_metadata(cx: &CrateContext, - trait_object_type: ty::t, + trait_type: ty::t, + trait_object_type: Option, unique_type_id: UniqueTypeId) -> DIType { // The implementation provided here is a stub. It makes sure that the trait // type is assigned the correct name, size, namespace, and source location. // But it does not describe the trait's methods. - let def_id = match ty::get(trait_object_type).sty { + let def_id = match ty::get(trait_type).sty { ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id, _ => { - let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_object_type); + let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ trait_pointer_metadata(): {}", pp_type_name.as_slice()).as_slice()); } }; - let trait_pointer_type_name = + let trait_object_type = trait_object_type.unwrap_or(trait_type); + let trait_type_name = compute_debuginfo_type_name(cx, trait_object_type, false); let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); @@ -2824,8 +2833,8 @@ fn trait_pointer_metadata(cx: &CrateContext, let trait_llvm_type = type_of::type_of(cx, trait_object_type); composite_type_metadata(cx, - trait_pointer_llvm_type, - trait_pointer_type_name.as_slice(), + trait_llvm_type, + trait_type_name.as_slice(), unique_type_id, [], containing_scope, @@ -2897,7 +2906,7 @@ fn type_metadata(cx: &CrateContext, ty::ty_str => fixed_vec_metadata(cx, unique_type_id, ty::mk_i8(), 0, usage_site_span), ty::ty_trait(..) => { MetadataCreationResult::new( - trait_pointer_metadata(cx, t, unique_type_id), + trait_pointer_metadata(cx, t, None, unique_type_id), false) } ty::ty_uniq(ty) | ty::ty_ptr(ty::mt{ty, ..}) | ty::ty_rptr(_, ty::mt{ty, ..}) => { @@ -2910,7 +2919,7 @@ fn type_metadata(cx: &CrateContext, } ty::ty_trait(..) => { MetadataCreationResult::new( - trait_pointer_metadata(cx, ty, unique_type_id), + trait_pointer_metadata(cx, ty, Some(t), unique_type_id), false) } _ => { @@ -3698,7 +3707,7 @@ fn push_debuginfo_type_name(cx: &CrateContext, push_debuginfo_type_name(cx, inner_type, true, output); }, - ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => { + ty::ty_vec(inner_type, optional_length) => { output.push_char('['); push_debuginfo_type_name(cx, inner_type, true, output); @@ -3811,6 +3820,7 @@ fn push_debuginfo_type_name(cx: &CrateContext, } ty::ty_err | ty::ty_infer(_) | + ty::ty_open(_) | ty::ty_param(_) => { cx.sess().bug(format!("debuginfo: Trying to create type name for \ unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t)).as_slice()); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 657cd72c25543..5f9788d707ac5 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -71,7 +71,7 @@ use middle::typeck::MethodCall; use util::common::indenter; use util::ppaux::Repr; use util::nodemap::NodeMap; -use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc}; +use middle::trans::machine::{llsize_of, llsize_of_alloc}; use middle::trans::type_::Type; use syntax::ast; @@ -202,8 +202,11 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, }; if autoderefs > 0 { + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); + datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, datum, autoderefs)); + bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs)); } match adj.autoref { @@ -266,35 +269,42 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, -> DatumBlock<'a, Expr> { if !ty::type_is_sized(bcx.tcx(), datum.ty) { debug!("Taking address of unsized type {}", - bcx.ty_to_str(datum.ty)); + bcx.ty_to_string(datum.ty)); ref_fat_ptr(bcx, expr, datum) } else { debug!("Taking address of sized type {}", - bcx.ty_to_str(datum.ty)); + bcx.ty_to_string(datum.ty)); auto_ref(bcx, datum, expr) } } // Retrieve the information we are losing (making dynamic) in an unsizing // adjustment. + // When making a dtor, we need to do different things depending on the + // ownership of the object.. mk_ty is a function for turning unsized_type + // into a type to be destructed. If we want to end up with a Box pointer, + // then mk_ty should make a Box pointer (T -> Box), if we want a + // borrowed reference then it should be T -> &T. fn unsized_info<'a>(bcx: &'a Block<'a>, kind: &ty::UnsizeKind, id: ast::NodeId, - sized_ty: ty::t) -> ValueRef { + unsized_ty: ty::t, + mk_ty: |ty::t| -> ty::t) -> ValueRef { match kind { &ty::UnsizeLength(len) => C_uint(bcx.ccx(), len), - &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(sized_ty).sty { + &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(unsized_ty).sty { ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_vec(subst::TypeSpace); - let sized_ty = ty_substs.get(tp_index); - unsized_info(bcx, k, id, *sized_ty) + let ty_substs = substs.types.get_slice(subst::TypeSpace); + // The dtor for a field treats it like a value, so mk_ty + // should just be the identity function. + unsized_info(bcx, k, id, ty_substs[tp_index], |t| t) } _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", - bcx.ty_to_str(sized_ty)).as_slice()) + bcx.ty_to_string(unsized_ty)).as_slice()) }, &ty::UnsizeVtable(..) => PointerCast(bcx, - meth::vtable_ptr(bcx, id, sized_ty), + meth::vtable_ptr(bcx, id, mk_ty(unsized_ty)), Type::vtable_ptr(bcx.ccx())) } } @@ -320,7 +330,16 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, &ty::UnsizeVtable(..) => |_bcx, val| PointerCast(bcx, val, Type::i8p(bcx.ccx())) }; - let info = |bcx, _val| unsized_info(bcx, k, expr.id, datum_ty); + let info = |bcx, _val| unsized_info(bcx, + k, + expr.id, + ty::deref_or_dont(datum_ty), + |t| ty::mk_rptr(tcx, + ty::ReStatic, + ty::mt{ + ty: t, + mutbl: ast::MutImmutable + })); into_fat_ptr(bcx, expr, datum, dest_ty, base, info) } @@ -415,21 +434,26 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, let unboxed_ty = match ty::get(datum_ty).sty { ty::ty_uniq(t) => t, _ => bcx.sess().bug(format!("Expected ty_uniq, found {}", - bcx.ty_to_str(datum_ty)).as_slice()) + bcx.ty_to_string(datum_ty)).as_slice()) }; let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span)); let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id)); - let scratch = rvalue_scratch_datum(bcx, result_ty, "__fat_ptr"); + let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr"); let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty); let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to()); bcx = lval.store_to(bcx, base); - let info = unsized_info(bcx, k, expr.id, unboxed_ty); + let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t)); Store(bcx, info, get_len(bcx, scratch.val)); + let scratch = unpack_datum!(bcx, + scratch.to_expr_datum().to_lvalue_datum(bcx, + "fresh_uniq_fat_ptr", + expr.id)); + DatumBlock::new(bcx, scratch.to_expr_datum()) } @@ -550,8 +574,8 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, ast::ExprField(ref base, ident, _) => { trans_rec_field(bcx, &**base, ident.node) } - ast::ExprIndex(base, idx) => { - trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id)) + ast::ExprIndex(ref base, ref idx) => { + trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) } ast::ExprBox(_, ref contents) => { // Special case for `Box` and `Gc` @@ -559,18 +583,24 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>, let contents_ty = expr_ty(bcx, &**contents); match ty::get(box_ty).sty { ty::ty_uniq(..) => { - match contents.node { - ast::ExprRepeat(..) | ast::ExprVec(..) => { - // Special case for owned vectors. - fcx.push_ast_cleanup_scope(contents.id); - let datum = unpack_datum!( - bcx, tvec::trans_uniq_vec(bcx, expr, &**contents)); - bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); - DatumBlock::new(bcx, datum) - } - _ => { - trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) - } + let is_vec = match contents.node { + ast::ExprRepeat(..) | ast::ExprVec(..) => true, + ast::ExprLit(lit) => match lit.node { + ast::LitStr(..) => true, + _ => false + }, + _ => false + }; + + if is_vec { + // Special case for owned vectors. + fcx.push_ast_cleanup_scope(contents.id); + let datum = unpack_datum!( + bcx, tvec::trans_uniq_vec(bcx, expr, &**contents)); + bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id); + DatumBlock::new(bcx, datum) + } else { + trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) } } ty::ty_box(..) => { @@ -639,7 +669,6 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, if ty::type_is_sized(bcx.tcx(), d.ty) { DatumBlock { datum: d.to_expr_datum(), bcx: bcx } } else { - debug!("nrc: {}", bcx.ty_to_str(d.ty)) let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), ""); Store(bcx, d.val, get_dataptr(bcx, scratch.val)); let info = Load(bcx, get_len(bcx, base_datum.val)); @@ -652,7 +681,7 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>, } fn trans_index<'a>(bcx: &'a Block<'a>, - sp: codemap::Span, + index_expr: &ast::Expr, base: &ast::Expr, idx: &ast::Expr, method_call: MethodCall) @@ -1326,7 +1355,8 @@ pub fn trans_adt<'a>(mut bcx: &'a Block<'a>, let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base")); for &(i, t) in base.fields.iter() { let datum = base_datum.get_element( - t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i)); + bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i)); + assert!(ty::type_is_sized(bcx.tcx(), datum.ty)); let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i); bcx = datum.store_to(bcx, dest); } @@ -1348,21 +1378,6 @@ pub fn trans_adt<'a>(mut bcx: &'a Block<'a>, fcx.schedule_drop_mem(scope, dest, e_ty); } - for base in optbase.iter() { - // FIXME #6573: is it sound to use the destination's repr on the base? - // And, would it ever be reasonable to be here with discr != 0? - let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base")); - for &(i, t) in base.fields.iter() { - let datum = base_datum.get_element( - bcx, - t, - |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i)); - assert!(ty::type_is_sized(bcx.tcx(), datum.ty)); - let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); - bcx = datum.store_to(bcx, dest); - } - } - adt::trans_set_discr(bcx, &*repr, addr, discr); fcx.pop_custom_cleanup_scope(custom_cleanup_scope); @@ -1448,9 +1463,10 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>, -> DatumBlock<'a, Expr> { let _icx = push_ctxt("trans_uniq_expr"); let fcx = bcx.fcx; + assert!(ty::type_is_sized(bcx.tcx(), contents_ty)); let llty = type_of::type_of(bcx.ccx(), contents_ty); let size = llsize_of(bcx.ccx(), llty); - let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint); + let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty) as uint); let llty_ptr = llty.ptr_to(); let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align); // Unique boxes do not allocate for zero-size types. The standard library @@ -1499,7 +1515,7 @@ fn trans_addr_of<'a>(bcx: &'a Block<'a>, match ty::get(sub_datum.ty).sty { ty::ty_open(_) => { // Opened DST value, close to a fat pointer - debug!("Closing fat pointer {}", bcx.ty_to_str(sub_datum.ty)); + debug!("Closing fat pointer {}", bcx.ty_to_string(sub_datum.ty)); let scratch = rvalue_scratch_datum(bcx, ty::close_type(bcx.tcx(), sub_datum.ty), diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 2994378f91caf..56841cd4044b6 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -19,6 +19,7 @@ use llvm::{ValueRef, True, get_param}; use llvm; use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem}; use middle::subst; +use middle::subst::Subst; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; @@ -26,12 +27,13 @@ use middle::trans::callee; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; use middle::trans::common::*; +use middle::trans::datum; use middle::trans::expr; use middle::trans::machine::*; use middle::trans::reflect; use middle::trans::tvec; use middle::trans::type_::Type; -use middle::trans::type_of::{type_of, sizing_type_of}; +use middle::trans::type_of::{type_of, sizing_type_of, align_of}; use middle::ty; use util::ppaux::ty_to_short_str; use util::ppaux; @@ -51,24 +53,33 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> { Some(expr::Ignore)).bcx } -pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, - align: u64) -> &'a Block<'a> { +fn trans_exchange_free_internal<'a>(cx: &'a Block<'a>, v: ValueRef, size: ValueRef, + align: ValueRef) -> &'a Block<'a> { let _icx = push_ctxt("trans_exchange_free"); let ccx = cx.ccx(); callee::trans_lang_call(cx, langcall(cx, None, "", ExchangeFreeFnLangItem), - [PointerCast(cx, v, Type::i8p(ccx)), C_uint(ccx, size as uint), C_uint(ccx, align as uint)], + [PointerCast(cx, v, Type::i8p(ccx)), size, align], Some(expr::Ignore)).bcx } +pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64, + align: u64) -> &'a Block<'a> { + trans_exchange_free_internal(cx, + v, + C_uint(cx.ccx(), size as uint), + C_uint(cx.ccx(), align as uint)) +} + pub fn trans_exchange_free_ty<'a>(bcx: &'a Block<'a>, ptr: ValueRef, content_ty: ty::t) -> &'a Block<'a> { + assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty)); let sizing_type = sizing_type_of(bcx.ccx(), content_ty); let content_size = llsize_of_alloc(bcx.ccx(), sizing_type); // `Box` does not allocate. if content_size != 0 { - let content_align = llalign_of_min(bcx.ccx(), sizing_type); + let content_align = align_of(bcx.ccx(), content_ty); trans_exchange_free(bcx, ptr, content_size, content_align) } else { bcx @@ -91,6 +102,11 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { let tcx = ccx.tcx(); + // Even if there is no dtor for t, there might be one deeper down and we + // might need to pass in the vtable ptr. + if !ty::type_is_sized(tcx, t) { + return t + } if !ty::type_needs_drop(tcx, t) { return ty::mk_i8(); } @@ -139,13 +155,21 @@ pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t) } pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef { + debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t)); let t = get_drop_glue_type(ccx, t); + debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t)); match ccx.drop_glues.borrow().find(&t) { Some(&glue) => return glue, _ => { } } - let llfnty = Type::glue_fn(ccx, type_of(ccx, t).ptr_to()); + let llty = if ty::type_is_sized(ccx.tcx(), t) { + type_of(ccx, t).ptr_to() + } else { + type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to() + }; + + let llfnty = Type::glue_fn(ccx, llty); let glue = declare_generic_glue(ccx, t, llfnty, "drop"); ccx.drop_glues.borrow_mut().insert(t, glue); @@ -208,7 +232,13 @@ fn trans_struct_drop_flag<'a>(mut bcx: &'a Block<'a>, substs: &subst::Substs) -> &'a Block<'a> { let repr = adt::represent_type(bcx.ccx(), t); - let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, v0)); + let struct_data = if ty::type_is_sized(bcx.tcx(), t) { + v0 + } else { + let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]); + Load(bcx, llval) + }; + let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data)); with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| { trans_struct_drop(cx, t, v0, dtor_did, class_did, substs) }) @@ -227,13 +257,31 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs); - // The second argument is the "self" argument for drop + // The first argument is the "self" argument for drop let params = unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr)); ty.element_type().func_params() }; - adt::fold_variants(bcx, &*repr, v0, |variant_cx, st, value| { + let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs); + let self_ty = match ty::get(fty).sty { + ty::ty_bare_fn(ref f) => { + assert!(f.sig.inputs.len() == 1); + f.sig.inputs[0] + } + _ => bcx.sess().bug(format!("Expected function type, found {}", + bcx.ty_to_string(fty)).as_slice()) + }; + + let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) { + (v0, None) + } else { + let data = GEPi(bcx, v0, [0, abi::slice_elt_base]); + let info = GEPi(bcx, v0, [0, abi::slice_elt_len]); + (Load(bcx, data), Some(Load(bcx, info))) + }; + + adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| { // Be sure to put all of the fields into a scope so we can use an invoke // instruction to call the user destructor but still call the field // destructors if the user destructor fails. @@ -242,7 +290,22 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, // Class dtors have no explicit args, so the params should // just consist of the environment (self). assert_eq!(params.len(), 1); - let self_arg = PointerCast(variant_cx, value, *params.get(0)); + let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) { + // The dtor expects a fat pointer, so make one, even if we have to fake it. + let boxed_ty = ty::mk_open(bcx.tcx(), t); + let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self"); + Store(bcx, value, GEPi(bcx, scratch.val, [0, abi::slice_elt_base])); + Store(bcx, + // If we just had a thin pointer, make a fat pointer by sticking + // null where we put the unsizing info. This works because t + // is a sized type, so we will only unpack the fat pointer, never + // use the fake info. + info.unwrap_or(C_null(Type::i8p(bcx.ccx()))), + GEPi(bcx, scratch.val, [0, abi::slice_elt_len])); + PointerCast(variant_cx, scratch.val, *params.get(0)) + } else { + PointerCast(variant_cx, value, *params.get(0)) + }; let args = vec!(self_arg); // Add all the fields as a value which needs to be cleaned at the end of @@ -250,19 +313,84 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, // the order in which fields get dropped. for (i, ty) in st.fields.iter().enumerate().rev() { let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false); + + let val = if ty::type_is_sized(bcx.tcx(), *ty) { + llfld_a + } else { + let boxed_ty = ty::mk_open(bcx.tcx(), *ty); + let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_field"); + Store(bcx, llfld_a, GEPi(bcx, scratch.val, [0, abi::slice_elt_base])); + Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, [0, abi::slice_elt_len])); + scratch.val + }; variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope), - llfld_a, *ty); + val, *ty); } let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID, [get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil()); - let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None); + let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false); variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); variant_cx }) } +fn size_and_align_of_dst<'a>(bcx: &'a Block<'a>, t :ty::t, info: ValueRef) -> (ValueRef, ValueRef) { + debug!("calculate size of DST: {}; with lost info: {}", + bcx.ty_to_string(t), bcx.val_to_string(info)); + if ty::type_is_sized(bcx.tcx(), t) { + let sizing_type = sizing_type_of(bcx.ccx(), t); + let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type) as uint); + let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t) as uint); + return (size, align); + } + match ty::get(t).sty { + ty::ty_struct(id, ref substs) => { + let ccx = bcx.ccx(); + // First get the size of all statically known fields. + // Don't use type_of::sizing_type_of because that expects t to be sized. + assert!(!ty::type_is_simd(bcx.tcx(), t)); + let repr = adt::represent_type(ccx, t); + let sizing_type = adt::sizing_type_of(ccx, &*repr, true); + let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type) as uint); + let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type) as uint); + + // Recurse to get the size of the dynamically sized field (must be + // the last field). + let fields = ty::struct_fields(bcx.tcx(), id, substs); + let last_field = fields[fields.len()-1]; + let field_ty = last_field.mt.ty; + let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); + + // Return the sum of sizes and max of aligns. + let size = Add(bcx, sized_size, unsized_size); + let align = Select(bcx, + ICmp(bcx, llvm::IntULT, sized_align, unsized_align), + sized_align, + unsized_align); + (size, align) + } + ty::ty_trait(..) => { + // info points to the vtable and the second entry in the vtable is the + // dynamic size of the object. + let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to()); + let size_ptr = GEPi(bcx, info, [1u]); + let align_ptr = GEPi(bcx, info, [2u]); + (Load(bcx, size_ptr), Load(bcx, align_ptr)) + } + ty::ty_vec(unit_ty, None) => { + // The info in this case is the length of the vec, so the size is that + // times the unit size. + let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty); + let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty); + (Mul(bcx, info, C_uint(bcx.ccx(), unit_size as uint)), C_uint(bcx.ccx(), 8)) + } + _ => bcx.sess().bug(format!("Unexpected unsized type, found {}", + bcx.ty_to_string(t)).as_slice()) + } +} + fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> { // NB: v0 is an *alias* of type t here, not a direct value. let _icx = push_ctxt("make_drop_glue"); @@ -282,7 +410,8 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' ty::ty_trait(..) => { let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); // Only drop the value when it is non-null - with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| { + let concrete_ptr = Load(bcx, lluniquevalue); + with_cond(bcx, IsNotNull(bcx, concrete_ptr), |bcx| { let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable])); let dtor = Load(bcx, dtor_ptr); Call(bcx, @@ -292,13 +421,21 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' bcx }) } + ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => { + let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]); + let llbox = Load(bcx, llval); + let not_null = IsNotNull(bcx, llbox); + with_cond(bcx, not_null, |bcx| { + let bcx = drop_ty(bcx, v0, content_ty); + let info = GEPi(bcx, v0, [0, abi::slice_elt_len]); + let info = Load(bcx, info); + let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info); + trans_exchange_free_internal(bcx, llbox, llsize, llalign) + }) + } _ => { - let llval = if ty::type_is_sized(bcx.tcx(), content_ty) { - v0 - } else { - // The Box is a fat pointer - GEPi(bcx, v0, [0, abi::trt_field_box]) - }; + assert!(ty::type_is_sized(bcx.tcx(), content_ty)); + let llval = v0; let llbox = Load(bcx, llval); let not_null = IsNotNull(bcx, llbox); with_cond(bcx, not_null, |bcx| { @@ -312,7 +449,21 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { ty::TraitDtor(dtor, true) => { - trans_struct_drop_flag(bcx, t, v0, dtor, did, substs) + // FIXME(16758) Since the struct is unsized, it is hard to + // find the drop flag (which is at the end of the struct). + // Lets just ignore the flag and pretend everything will be + // OK. + if ty::type_is_sized(bcx.tcx(), t) { + trans_struct_drop_flag(bcx, t, v0, dtor, did, substs) + } else { + // Give the user a heads up that we are doing something + // stupid and dangerous. + bcx.sess().warn(format!("Ignoring drop flag in destructor for {}\ + because the struct is unsized. See issue\ + #16758", + bcx.ty_to_string(t)).as_slice()); + trans_struct_drop(bcx, t, v0, dtor, did, substs) + } } ty::TraitDtor(dtor, false) => { trans_struct_drop(bcx, t, v0, dtor, did, substs) @@ -340,7 +491,23 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' trans_exchange_free(bcx, env, 0, 8) }) } + ty::ty_trait(..) => { + // No need to do a null check here (as opposed to the Box tvec::make_drop_glue_unboxed(bcx, v0, ty), _ => { + assert!(ty::type_is_sized(bcx.tcx(), t)); if ty::type_needs_drop(bcx.tcx(), t) && ty::type_is_structural(t) { iter_structural_ty(bcx, v0, t, drop_ty) @@ -439,7 +606,6 @@ fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type, ccx, t, format!("glue_{}", name).as_slice()); - debug!("{} is for type {}", fn_nm, ppaux::ty_to_string(ccx.tcx(), t)); let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil()); note_unique_llvm_symbol(ccx, fn_nm); return llfn; diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index 359c8d24f7270..7d8e4679ae302 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -119,6 +119,17 @@ pub fn check_intrinsics(ccx: &CrateContext) { "s" }).as_slice()); } + if ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) || + ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) { + ccx.sess() + .add_lint(::lint::builtin::TRANSMUTE_FAT_PTR, + transmute_restriction.id, + transmute_restriction.span, + format!("Transmuting fat pointer types; {} to {}.\ + Beware of relying on the compiler's representation", + ty_to_string(ccx.tcx(), transmute_restriction.from), + ty_to_string(ccx.tcx(), transmute_restriction.to))); + } } ccx.sess().abort_if_errors(); } @@ -227,8 +238,7 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId, } (_, "min_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); - let lltp_ty = type_of::type_of(ccx, tp_ty); - C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint) + C_uint(ccx, type_of::align_of(ccx, tp_ty) as uint) } (_, "pref_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); @@ -542,7 +552,7 @@ fn copy_intrinsic(bcx: &Block, allow_overlap: bool, volatile: bool, tp_ty: ty::t, dst: ValueRef, src: ValueRef, count: ValueRef) -> ValueRef { let ccx = bcx.ccx(); let lltp_ty = type_of::type_of(ccx, tp_ty); - let align = C_i32(ccx, machine::llalign_of_min(ccx, lltp_ty) as i32); + let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32); let size = machine::llsize_of(ccx, lltp_ty); let int_size = machine::llbitsize_of_real(ccx, ccx.int_type); let name = if allow_overlap { @@ -571,7 +581,7 @@ fn memset_intrinsic(bcx: &Block, volatile: bool, tp_ty: ty::t, dst: ValueRef, val: ValueRef, count: ValueRef) -> ValueRef { let ccx = bcx.ccx(); let lltp_ty = type_of::type_of(ccx, tp_ty); - let align = C_i32(ccx, machine::llalign_of_min(ccx, lltp_ty) as i32); + let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32); let size = machine::llsize_of(ccx, lltp_ty); let name = if machine::llbitsize_of_real(ccx, ccx.int_type) == 32 { "llvm.memset.p0i8.i32" diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 3dc0904041911..83bdcc9dead64 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -25,6 +25,7 @@ use middle::trans::datum::*; use middle::trans::expr::{SaveIn, Ignore}; use middle::trans::expr; use middle::trans::glue; +use middle::trans::machine; use middle::trans::monomorphize; use middle::trans::type_::Type; use middle::trans::type_of::*; @@ -40,6 +41,9 @@ use syntax::parse::token; use syntax::{ast, ast_map, visit}; use syntax::ast_util::PostExpansionMethod; +// drop_glue pointer, size, align. +static VTABLE_OFFSET: uint = 3; + /** The main "translation" pass for methods. Generates code for non-monomorphized methods only. Other methods will @@ -450,7 +454,7 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>, GEPi(bcx, llpair, [0u, abi::trt_field_vtable]), Type::vtable(ccx).ptr_to().ptr_to())); - let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1])); + let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + VTABLE_OFFSET])); let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to()); return Callee { @@ -580,9 +584,15 @@ fn get_vtable(bcx: &Block, } }); + let size_ty = sizing_type_of(ccx, self_ty); + let size = machine::llsize_of_alloc(ccx, size_ty); + let ll_size = C_uint(ccx, size as uint); + let align = align_of(ccx, self_ty); + let ll_align = C_uint(ccx, align as uint); + // Generate a destructor for the vtable. let drop_glue = glue::get_drop_glue(ccx, self_ty); - let vtable = make_vtable(ccx, drop_glue, methods); + let vtable = make_vtable(ccx, drop_glue, ll_size, ll_align, methods); ccx.vtables.borrow_mut().insert(hash_id, vtable); vtable @@ -591,11 +601,14 @@ fn get_vtable(bcx: &Block, /// Helper function to declare and initialize the vtable. pub fn make_vtable>(ccx: &CrateContext, drop_glue: ValueRef, + size: ValueRef, + align: ValueRef, ptrs: I) -> ValueRef { let _icx = push_ctxt("meth::make_vtable"); - let components: Vec<_> = Some(drop_glue).move_iter().chain(ptrs).collect(); + let head = vec![drop_glue, size, align]; + let components: Vec<_> = head.move_iter().chain(ptrs).collect(); unsafe { let tbl = C_struct(ccx, components.as_slice(), false); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 7b6d3430ae0dc..11c641f2d75a2 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -66,7 +66,7 @@ impl<'a, 'b> Reflector<'a, 'b> { pub fn c_size_and_align(&mut self, t: ty::t) -> Vec { let tr = type_of(self.bcx.ccx(), t); let s = machine::llsize_of_real(self.bcx.ccx(), tr); - let a = machine::llalign_of_min(self.bcx.ccx(), tr); + let a = align_of(self.bcx.ccx(), t); return vec!(self.c_uint(s as uint), self.c_uint(a as uint)); } @@ -94,7 +94,7 @@ impl<'a, 'b> Reflector<'a, 'b> { ty::MethodTraitItem(ref method) => (*method).clone(), }; let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone()); - debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_str(tcx, mth_ty)); + debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_string(tcx, mth_ty)); let v = self.visitor_val; debug!("passing {} args:", args.len()); let mut bcx = self.bcx; @@ -154,8 +154,11 @@ impl<'a, 'b> Reflector<'a, 'b> { // Unfortunately we can't do anything here because at runtime we // pass around the value by pointer (*u8). But unsized pointers are // fat and so we can't just cast them to *u8 and back. So we have - // to work with the pointer directly (see ty_rptr/ty_uniq). See - // ty_struct for where this causes issues. + // to work with the pointer directly (see ty_rptr/ty_uniq). + fail!("Can't reflect unsized type") + } + // FIXME(15049) Reflection for unsized structs. + ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), t) => { fail!("Can't reflect unsized type") } @@ -278,12 +281,7 @@ impl<'a, 'b> Reflector<'a, 'b> { // because we cannot reflect unsized types (see note above). We // just pretend the unsized field does not exist and print nothing. // This is sub-optimal. - let len = if ty::type_is_sized(tcx, t) { - fields.len() - } else { - assert!(fields.len() > 0); - fields.len() - 1 - }; + let len = fields.len(); let extra = (vec!( self.c_slice( @@ -294,14 +292,12 @@ impl<'a, 'b> Reflector<'a, 'b> { )).append(self.c_size_and_align(t).as_slice()); self.bracketed("class", extra.as_slice(), |this| { for (i, field) in fields.iter().enumerate() { - if ty::type_is_sized(tcx, field.mt.ty) { - let extra = (vec!( - this.c_uint(i), - this.c_slice(token::get_ident(field.ident)), - this.c_bool(named_fields) - )).append(this.c_mt(&field.mt).as_slice()); - this.visit("class_field", extra.as_slice()); - } + let extra = (vec!( + this.c_uint(i), + this.c_slice(token::get_ident(field.ident)), + this.c_bool(named_fields) + )).append(this.c_mt(&field.mt).as_slice()); + this.visit("class_field", extra.as_slice()); } }) } diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 0ec18977139ed..94ca520c533f9 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -17,6 +17,7 @@ use middle::lang_items::StrDupUniqFnLangItem; use middle::trans::base::*; use middle::trans::base; use middle::trans::build::*; +use middle::trans::callee; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; use middle::trans::common::*; @@ -162,7 +163,7 @@ pub fn trans_slice_vec<'a>(bcx: &'a Block<'a>, // Handle the &[...] case: let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); - debug!(" vt={}, count={:?}", vt.to_str(ccx), count); + debug!(" vt={}, count={:?}", vt.to_string(ccx), count); let llcount = C_uint(ccx, count); let fixed_ty = ty::mk_vec(bcx.tcx(), @@ -173,7 +174,8 @@ pub fn trans_slice_vec<'a>(bcx: &'a Block<'a>, let llfixed = if count == 0 { // Just create a zero-sized alloca to preserve // the non-null invariant of the inner slice ptr - base::arrayalloca(bcx, vt.llunit_ty, llcount) + let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); + BitCast(bcx, llfixed, llfixed_ty) } else { // Make a fixed-length backing array and allocate it on the stack. let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount); @@ -231,26 +233,55 @@ pub fn trans_uniq_vec<'a>(bcx: &'a Block<'a>, content_expr: &ast::Expr) -> DatumBlock<'a, Expr> { /*! - * ~[...] and "...".to_string() allocate boxes in the exchange heap and write + * Box<[...]> and "...".to_string() allocate boxes in the exchange heap and write * the array elements into them. */ - debug!("trans_uniq_vec(vstore_expr={})", bcx.expr_to_string(uniq_expr)); + debug!("trans_uniq_vec(uniq_expr={})", bcx.expr_to_string(uniq_expr)); let fcx = bcx.fcx; let ccx = fcx.ccx; + // Handle "".to_string(). + match content_expr.node { + ast::ExprLit(lit) => { + match lit.node { + ast::LitStr(ref s, _) => { + let llptrval = C_cstr(ccx, (*s).clone(), false); + let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx)); + let llsizeval = C_uint(ccx, s.get().len()); + let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx())); + let lldestval = rvalue_scratch_datum(bcx, + typ, + ""); + let alloc_fn = langcall(bcx, + Some(lit.span), + "", + StrDupUniqFnLangItem); + let bcx = callee::trans_lang_call( + bcx, + alloc_fn, + [ llptrval, llsizeval ], + Some(expr::SaveIn(lldestval.val))).bcx; + return DatumBlock::new(bcx, lldestval).to_expr_datumblock(); + } + _ => {} + } + } + _ => {} + } + let vt = vec_types_from_expr(bcx, content_expr); let count = elements_required(bcx, content_expr); - debug!(" vt={}, count={:?}", vt.to_str(ccx), count); + debug!(" vt={}, count={:?}", vt.to_string(ccx), count); let vec_ty = node_id_type(bcx, uniq_expr.id); let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty)); - let fill = Mul(bcx, C_uint(ccx, count), unit_sz); - let alloc = if count < 4u { - Mul(bcx, C_int(ccx, 4), unit_sz) + let llcount = if count < 4u { + C_int(ccx, 4) } else { - fill + C_uint(ccx, count) }; + let alloc = Mul(bcx, llcount, unit_sz); let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to(); let align = C_uint(ccx, 8); let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx, @@ -268,7 +299,7 @@ pub fn trans_uniq_vec<'a>(bcx: &'a Block<'a>, dataptr, cleanup::HeapExchange, vt.unit_ty); debug!(" alloc_uniq_vec() returned dataptr={}, len={}", - bcx.val_to_str(dataptr), count); + bcx.val_to_string(dataptr), count); let bcx = write_content(bcx, &vt, uniq_expr, content_expr, SaveIn(dataptr)); diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 9608672928d61..83c792ecf8782 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -14,6 +14,7 @@ use middle::subst; use middle::trans::adt; use middle::trans::common::*; use middle::trans::foreign; +use middle::trans::machine; use middle::ty; use util::ppaux; use util::ppaux::Repr; @@ -163,7 +164,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { let llsizingty = match ty::get(t).sty { _ if !ty::lltype_is_sized(cx.tcx(), t) => { cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type", - ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + ppaux::ty_to_string(cx.tcx(), t)).as_slice()) } ty::ty_nil | ty::ty_bot => Type::nil(cx), @@ -192,7 +193,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => { let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &*repr) + adt::sizing_type_of(cx, &*repr, false) } ty::ty_struct(..) => { @@ -202,7 +203,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { Type::vector(&type_of(cx, et), n as u64) } else { let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &*repr) + adt::sizing_type_of(cx, &*repr, false) } } @@ -212,7 +213,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => { cx.sess().bug(format!("fictitious type {} in sizing_type_of()", - ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + ppaux::ty_to_string(cx.tcx(), t)).as_slice()) } ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => fail!("unreachable") }; @@ -232,6 +233,14 @@ pub fn arg_type_of(cx: &CrateContext, t: ty::t) -> Type { // NB: If you update this, be sure to update `sizing_type_of()` as well. pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { fn type_of_unsize_info(cx: &CrateContext, t: ty::t) -> Type { + // It is possible to end up here with a sized type. This happens with a + // struct which might be unsized, but is monomorphised to a sized type. + // In this case we'll fake a fat pointer with no unsize info (we use 0). + // However, its still a fat pointer, so we need some type use. + if ty::type_is_sized(cx.tcx(), t) { + return Type::i8p(cx); + } + match ty::get(ty::unsized_part_of_type(cx.tcx(), t)).sty { ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU), ty::ty_trait(_) => Type::vtable_ptr(cx), @@ -367,7 +376,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { } ty::ty_trait(..) => Type::opaque_trait(cx), _ => cx.sess().bug(format!("ty_open with sized type: {}", - ppaux::ty_to_str(cx.tcx(), t)).as_slice()) + ppaux::ty_to_string(cx.tcx(), t)).as_slice()) }, ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), @@ -395,6 +404,11 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { return llty; } +pub fn align_of(cx: &CrateContext, t: ty::t) -> u64 { + let llty = sizing_type_of(cx, t); + machine::llalign_of_min(cx, llty) +} + // Want refinements! (Or case classes, I guess pub enum named_ty { a_struct, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 486ed71457471..2d3096d13eae0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -302,26 +302,23 @@ pub enum AutoRef { AutoUnsafe(ast::Mutability), } -// Ugly little helper function. The bool in the returned tuple is true if there -// is an 'unsize to trait object' adjustment at the bottom of the adjustment. If -// that is surrounded by an AutoPtr, then we also return the region of the -// AutoPtr (in the third argument). The second bool is true if the adjustment is -// unique. +// Ugly little helper function. The first bool in the returned tuple is true if +// there is an 'unsize to trait object' adjustment at the bottom of the +// adjustment. If that is surrounded by an AutoPtr, then we also return the +// region of the AutoPtr (in the third argument). The second bool is true if the +// adjustment is unique. fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { - fn unsize_kind_region(k: &UnsizeKind) -> (bool, bool, Option) { + fn unsize_kind_is_object(k: &UnsizeKind) -> bool { match k { - &UnsizeVtable(..) => (true, false, None), - &UnsizeStruct(box ref k, _) => unsize_kind_region(k), - _ => (false, false, None) + &UnsizeVtable(..) => true, + &UnsizeStruct(box ref k, _) => unsize_kind_is_object(k), + _ => false } } match autoref { - &AutoUnsize(ref k) => unsize_kind_region(k), - &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(..) => (true, true, None), - _ => (false, false, None) - }, + &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None), + &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None), &AutoPtr(adj_r, _, Some(box ref autoref)) => { let (b, u, r) = autoref_object_region(autoref); if r.is_some() || u { @@ -407,6 +404,8 @@ pub struct TransmuteRestriction { pub from: t, /// The type being transmuted to. pub to: t, + /// NodeIf of the transmute intrinsic. + pub id: ast::NodeId, } /// The data structure to keep track of all the information that typechecker @@ -1765,7 +1764,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => {} + ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {} ty_box(ty) | ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f), ty_ptr(ref tm) | ty_rptr(_, ref tm) => { maybe_walk_ty(tm.ty, f); @@ -2941,12 +2940,12 @@ pub fn unsized_part_of_type(cx: &ctxt, ty: t) -> t { ty_str | ty_trait(..) | ty_vec(..) => ty, ty_struct(_, ref substs) => { // Exactly one of the type parameters must be unsized. - for tp in substs.types.get_vec(subst::TypeSpace).iter() { + for tp in substs.types.get_slice(subst::TypeSpace).iter() { if !type_is_sized(cx, *tp) { return unsized_part_of_type(cx, *tp); } } - fail!("Unsized struct type with no unsized type params?"); + fail!("Unsized struct type with no unsized type params? {}", ty_to_string(cx, ty)); } _ => { assert!(type_is_sized(cx, ty), @@ -2990,11 +2989,21 @@ pub fn deref(t: t, explicit: bool) -> Option { } } +pub fn deref_or_dont(t: t) -> t { + match get(t).sty { + ty_box(ty) | ty_uniq(ty) => { + ty + }, + ty_rptr(_, mt) | ty_ptr(mt) => mt.ty, + _ => t + } +} + pub fn close_type(cx: &ctxt, t: t) -> t { match get(t).sty { ty_open(t) => mk_rptr(cx, ReStatic, mt {ty: t, mutbl:ast::MutImmutable}), _ => cx.sess.bug(format!("Trying to close a non-open type {}", - ty_to_str(cx, t)).as_slice()) + ty_to_string(cx, t)).as_slice()) } } @@ -3027,9 +3036,9 @@ pub fn index(ty: t) -> Option { // This is exactly the same as the above, except it supports strings, // which can't actually be indexed. pub fn array_element_ty(t: t) -> Option { - match get(ty).sty { + match get(t).sty { ty_vec(t, _) => Some(t), - ty_str => Some(ty: mk_u8()), + ty_str => Some(mk_u8()), _ => None } } @@ -3361,20 +3370,19 @@ pub fn unsize_ty(cx: &ctxt, } _ => cx.sess.span_bug(span, format!("UnsizeLength with bad sty: {}", - ty_to_str(cx, ty)).as_slice()) + ty_to_string(cx, ty)).as_slice()) }, &UnsizeStruct(box ref k, tp_index) => match get(ty).sty { ty_struct(did, ref substs) => { - let ty_substs = substs.types.get_vec(subst::TypeSpace); - let old_ty = ty_substs.get(tp_index); - let new_ty = unsize_ty(cx, *old_ty, k, span); + let ty_substs = substs.types.get_slice(subst::TypeSpace); + let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span); let mut unsized_substs = substs.clone(); - *unsized_substs.types.get_mut_vec(subst::TypeSpace).get_mut(tp_index) = new_ty; + unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty; mk_struct(cx, did, unsized_substs) } _ => cx.sess.span_bug(span, format!("UnsizeStruct with bad sty: {}", - ty_to_str(cx, ty)).as_slice()) + ty_to_string(cx, ty)).as_slice()) }, &UnsizeVtable(bounds, def_id, ref substs) => { mk_trait(cx, def_id, substs.clone(), bounds) @@ -5333,6 +5341,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_tup(_) | ty_param(_) | ty_infer(_) | + ty_open(_) | ty_err => {} } }) diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index b246b5ce7a952..2bfbc67bbeb0f 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -273,6 +273,18 @@ impl TypeFoldable for ty::Generics { } } +impl TypeFoldable for ty::UnsizeKind { + fn fold_with(&self, folder: &mut F) -> ty::UnsizeKind { + match *self { + ty::UnsizeLength(len) => ty::UnsizeLength(len), + ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), + ty::UnsizeVtable(bounds, def_id, ref substs) => { + ty::UnsizeVtable(bounds.fold_with(folder), def_id, substs.fold_with(folder)) + } + } + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // @@ -425,11 +437,11 @@ pub fn super_fold_autoref(this: &mut T, match *autoref { ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), ty::AutoPtr(r, m, Some(ref a)) => { - ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, a.clone()))) + ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) } ty::AutoUnsafe(m) => ty::AutoUnsafe(m), - ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), - ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), + ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), + ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index f3b829e60ca60..6bb17c90da269 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -947,7 +947,7 @@ impl<'a> LookupContext<'a> { // [T, ..len] -> [T] or &[T] or &&[T] fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option { let tcx = self.tcx(); - debug!("auto_unsize_vec {}", ppaux::ty_to_str(tcx, ty)); + debug!("auto_unsize_vec {}", ppaux::ty_to_string(tcx, ty)); // First try to borrow to an unsized vec. let entry = self.search_for_some_kind_of_autorefd_method( @@ -1330,7 +1330,7 @@ impl<'a> LookupContext<'a> { match self.fcx.mk_subty(false, infer::Misc(span), rcvr_ty, transformed_self_ty) { Ok(_) => {} - Err(e) => { + Err(_) => { self.bug(format!( "{} was a subtype of {} but now is not?", self.ty_to_string(rcvr_ty), diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 6d3e001a00b0f..02464e17bac84 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1149,7 +1149,7 @@ fn check_cast(fcx: &FnCtxt, if ty::type_is_scalar(t_1) { // Supply the type as a hint so as to influence integer // literals and other things that might care. - check_expr_with_hint(fcx, e, t_1) + check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)) } else { check_expr(fcx, e) } @@ -2033,7 +2033,6 @@ fn check_argument_types(fcx: &FnCtxt, } check_expr_coercable_to_type(fcx, &**arg, formal_ty); - } } } @@ -2428,12 +2427,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // 'else' branch. let expected = match expected.only_has_type() { ExpectHasType(ety) => { - match infer::resolve_type(fcx.infcx(), ety, force_tvar) { + match infer::resolve_type(fcx.infcx(), Some(sp), ety, force_tvar) { Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty), _ => NoExpectation } } - None => None + _ => NoExpectation }; check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); @@ -3067,23 +3066,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, ty::t); - fn check_fn_for_vec_elements_expected(fcx: &FnCtxt, - expected: Expectation) - -> (ExprCheckerWithTy, ty::t) { - let tcx = fcx.ccx.tcx; - let (coerce, t) = match expected { - // If we're given an expected type, we can try to coerce to it - ExpectHasType(t) if ty::type_is_vec(t) => (true, ty::sequence_element_type(tcx, t)), - // Otherwise we just leave the type to be resolved later - _ => (false, fcx.infcx().next_ty_var()) - }; - if coerce { - (check_expr_coercable_to_type, t) - } else { - (check_expr_has_type, t) - } - } - let tcx = fcx.ccx.tcx; let id = expr.id; match expr.node { @@ -3157,7 +3139,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } } ast::ExprUnary(unop, ref oprnd) => { - let expected = expected.only_has_type(); let expected_inner = expected.map(fcx, |sty| { match unop { ast::UnBox | ast::UnUniq => match *sty { @@ -3328,7 +3309,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } }, Some(ref e) => { - //check_expr_has_type(fcx, e, ret_ty); check_expr_coercable_to_type(fcx, &**e, ret_ty); } } @@ -3483,12 +3463,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_cast(fcx, &**e, &**t, id, expr.span); } ast::ExprVec(ref args) => { - let uty = unpack_expected( - fcx, expected, - |sty| match *sty { - ty::ty_vec(ty, _) => Some(ty), - _ => None - }); + let uty = match expected { + ExpectHasType(uty) => { + match ty::get(uty).sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + } + } + _ => None + }; let typ = match uty { Some(uty) => { @@ -3512,12 +3495,15 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_expr_has_type(fcx, &**count_expr, ty::mk_uint()); let count = ty::eval_repeat_count(fcx, &**count_expr); - let uty = unpack_expected( - fcx, expected, - |sty| match *sty { - ty::ty_vec(ty, _) => Some(ty), - _ => None - }); + let uty = match expected { + ExpectHasType(uty) => { + match ty::get(uty).sty { + ty::ty_vec(ty, _) => Some(ty), + _ => None + } + } + _ => None + }; let (element_ty, t) = match uty { Some(uty) => { @@ -3552,17 +3538,14 @@ fn check_expr_with_unifier(fcx: &FnCtxt, let mut err_field = false; let elt_ts = elts.iter().enumerate().map(|(i, e)| { - let opt_hint = match flds { - Some(ref fs) if i < fs.len() => ExpectHasType(*fs.get(i)), - _ => NoExpectation - }; - let t = match opt_hint { - ExpectHasType(ety) => { + let t = match flds { + Some(ref fs) if i < fs.len() => { + let ety = *fs.get(i); check_expr_coercable_to_type(fcx, &**e, ety); ety } _ => { - check_expr_with_expectation(fcx, &**e, opt_hint); + check_expr_with_expectation(fcx, &**e, NoExpectation); fcx.expr_ty(&**e) } }; @@ -3942,42 +3925,42 @@ fn check_block_with_expected(fcx: &FnCtxt, } match blk.expr { None => if any_err { - fcx.write_error(blk.id); - } - else if any_bot { - fcx.write_bot(blk.id); - } - else { - fcx.write_nil(blk.id); - }, - Some(e) => { - if any_bot && !warned { - fcx.ccx - .tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); - } - let ety = match expected { - ExpectHasType(ety) => { - check_expr_coercable_to_type(fcx, &*e, ety); - ety + fcx.write_error(blk.id); } - _ => { - check_expr_with_expectation(fcx, &*e, expected); - fcx.expr_ty(e) + else if any_bot { + fcx.write_bot(blk.id); } - }; + else { + fcx.write_nil(blk.id); + }, + Some(e) => { + if any_bot && !warned { + fcx.ccx + .tcx + .sess + .add_lint(lint::builtin::UNREACHABLE_CODE, + e.id, + e.span, + "unreachable expression".to_string()); + } + let ety = match expected { + ExpectHasType(ety) => { + check_expr_coercable_to_type(fcx, &*e, ety); + ety + } + _ => { + check_expr_with_expectation(fcx, &*e, expected); + fcx.expr_ty(&*e) + } + }; - fcx.write_ty(blk.id, ety); - if any_err { - fcx.write_error(blk.id); - } else if any_bot { - fcx.write_bot(blk.id); + fcx.write_ty(blk.id, ety); + if any_err { + fcx.write_error(blk.id); + } else if any_bot { + fcx.write_bot(blk.id); + } } - } }; }); diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 5b14ee62b0aec..530f8dd4b9ef6 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -810,7 +810,6 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { } } AutoDerefRef(ref adj) => { - assert!(!ty::adjust_is_object(adjustment)); for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(ex.id, autoderef); match fcx.inh.method_map.borrow().find(&method_call) { @@ -831,9 +830,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { } } } - _ => { - assert!(!ty::adjust_is_object(adjustment)); - } + _ => {} } } None => {} @@ -867,27 +864,21 @@ fn trait_cast_types(fcx: &FnCtxt, } &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_vec(subst::TypeSpace); - let field_ty = *ty_substs.get(tp_index); - let field_ty = structurally_resolved_type(fcx, sp, field_ty); + let ty_substs = substs.types.get_slice(subst::TypeSpace); + let field_ty = structurally_resolved_type(fcx, sp, ty_substs[tp_index]); trait_cast_types_unsize(fcx, k, field_ty, sp) } _ => fail!("Failed to find a ty_struct to correspond with \ UnsizeStruct whilst walking adjustment. Found {}", - ppaux::ty_to_str(fcx.tcx(), src_ty)) + ppaux::ty_to_string(fcx.tcx(), src_ty)) }, _ => None } } match autoref { - &ty::AutoUnsize(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), - &ty::AutoUnsizeUniq(ref k) => match k { - &ty::UnsizeVtable(bounds, def_id, ref substs) => { - Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) - } - _ => None - }, + &ty::AutoUnsize(ref k) | + &ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), &ty::AutoPtr(_, _, Some(box ref autoref)) => { trait_cast_types_autoref(fcx, autoref, src_ty, sp) } diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 6d0b34e89d679..abf366381139c 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -199,8 +199,8 @@ impl<'f> Coerce<'f> { } } - pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult) - -> CoerceResult { + pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> T) + -> T { match resolve_type(self.get_ref().infcx, None, a, try_resolve_tvar_shallow) { Ok(t) => { @@ -306,7 +306,7 @@ impl<'f> Coerce<'f> { let sty_b = &ty::get(b).sty; match (sty_a, sty_b) { - (&ty::ty_uniq(t_a), &ty::ty_rptr(_, mt_b)) => Err(ty::terr_mismatch), + (&ty::ty_uniq(_), &ty::ty_rptr(..)) => Err(ty::terr_mismatch), (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => { self.unpack_actual_value(t_a, |sty_a| { match self.unsize_ty(sty_a, mt_b.ty) { @@ -381,8 +381,8 @@ impl<'f> Coerce<'f> { if did_a == did_b => { debug!("unsizing a struct"); // Try unsizing each type param in turn to see if we end up with ty_b. - let ty_substs_a = substs_a.types.get_vec(subst::TypeSpace); - let ty_substs_b = substs_b.types.get_vec(subst::TypeSpace); + let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); + let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); assert!(ty_substs_a.len() == ty_substs_b.len()); let sub = Sub(self.get_ref().clone()); @@ -397,7 +397,7 @@ impl<'f> Coerce<'f> { Some((new_tp, k)) => { // Check that the whole types match. let mut new_substs = substs_a.clone(); - *new_substs.types.get_mut_vec(subst::TypeSpace).get_mut(i) = new_tp; + new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, new_substs); if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { debug!("Unsized type parameter '{}', but still \ @@ -439,8 +439,7 @@ impl<'f> Coerce<'f> { let r_a = self.get_ref().infcx.next_region_var(coercion); let a_borrowed = match *sty_a { - ty::ty_uniq(ty) => return Err(ty::terr_mismatch), - ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, ref substs, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4f68d42de966c..5dff183108ce8 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -370,7 +370,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { buf.push_str(mt_to_string(cx, tm).as_slice()); buf } - ty_open(typ) => format!("opened<{}>", ty_to_str(cx, typ)), + ty_open(typ) => format!("opened<{}>", ty_to_string(cx, typ)), ty_tup(ref elems) => { let strs: Vec = elems.iter().map(|elem| ty_to_string(cx, *elem)).collect(); format!("({})", strs.connect(",")) diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index a9cbacb07bee5..bbaac7a96e9ee 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -18,7 +18,6 @@ use std::path; use std::rc::Rc; use std::gc::{Gc, GC}; use std::cell::{Cell, RefCell}; -use std::strbuf::StrBuf; pub trait Encoder { // Primitive types: diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 00513f7f67c31..01de001c043c7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -61,7 +61,7 @@ use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause, WherePredicate}; use ast; -use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec}; +use ast_util::{as_prec, ident_to_path, operator_prec}; use ast_util; use attr; use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; @@ -2577,21 +2577,24 @@ impl<'a> Parser<'a> { ex = self.mk_unary(UnUniq, e); } token::IDENT(_, _) => { - if self.is_keyword(keywords::Box) { - self.bump(); + if !self.is_keyword(keywords::Box) { + return self.parse_dot_or_call_expr(); + } - // Check for a place: `box(PLACE) EXPR`. - if self.eat(&token::LPAREN) { - // Support `box() EXPR` as the default. - if !self.eat(&token::RPAREN) { - let place = self.parse_expr(); - self.expect(&token::RPAREN); - let subexpression = self.parse_prefix_expr(); - hi = subexpression.span.hi; - ex = ExprBox(place, subexpression); - return self.mk_expr(lo, hi, ex); - } + self.bump(); + + // Check for a place: `box(PLACE) EXPR`. + if self.eat(&token::LPAREN) { + // Support `box() EXPR` as the default. + if !self.eat(&token::RPAREN) { + let place = self.parse_expr(); + self.expect(&token::RPAREN); + let subexpression = self.parse_prefix_expr(); + hi = subexpression.span.hi; + ex = ExprBox(place, subexpression); + return self.mk_expr(lo, hi, ex); } + } // Otherwise, we use the unique pointer default. let subexpression = self.parse_prefix_expr(); diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 9a56dd5c0e47b..429a16ec5c89a 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -268,19 +268,7 @@ pub struct Tm { pub tm_nsec: i32, } -impl Tm { - pub fn tm_zone<'a>(&'a self) -> &'a str { - self.tm_zone.as_slice() - } -} - pub fn empty_tm() -> Tm { - // 64 is the max size of the timezone buffer allocated on windows - // in rust_localtime. In glibc the max timezone size is supposedly 3. - let mut zone = StrBuf::new(); - for _ in range(0, 64) { - zone.push_char(' ') - } Tm { tm_sec: 0_i32, tm_min: 0_i32, @@ -292,7 +280,6 @@ pub fn empty_tm() -> Tm { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, - tm_zone: zone, tm_nsec: 0_i32, } } @@ -773,7 +760,6 @@ pub fn strptime(s: &str, format: &str) -> Result { 'Z' => { if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") { tm.tm_gmtoff = 0_i32; - tm.tm_zone = "UTC".into_strbuf(); Ok(pos + 3u) } else { // It's odd, but to maintain compatibility with c's @@ -798,7 +784,6 @@ pub fn strptime(s: &str, format: &str) -> Result { let (v, pos) = item; if v == 0_i32 { tm.tm_gmtoff = 0_i32; - tm.tm_zone = "UTC".into_strbuf(); } Ok(pos) @@ -828,7 +813,6 @@ pub fn strptime(s: &str, format: &str) -> Result { tm_yday: 0_i32, tm_isdst: 0_i32, tm_gmtoff: 0_i32, - tm_zone: StrBuf::new(), tm_nsec: 0_i32, }; let mut pos = 0u; @@ -875,7 +859,6 @@ pub fn strptime(s: &str, format: &str) -> Result { tm_yday: tm.tm_yday, tm_isdst: tm.tm_isdst, tm_gmtoff: tm.tm_gmtoff, - tm_zone: tm.tm_zone.clone(), tm_nsec: tm.tm_nsec, }) } else { result } @@ -1077,7 +1060,6 @@ pub fn strftime(format: &str, tm: &Tm) -> String { 'w' => (tm.tm_wday as int).to_string(), 'Y' => (tm.tm_year as int + 1900).to_string(), 'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100), - 'Z' => tm.tm_zone.as_slice().to_owned(), 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = num::abs(tm.tm_gmtoff) / 60_i32; @@ -1203,7 +1185,6 @@ mod tests { assert_eq!(utc.tm_yday, 43_i32); assert_eq!(utc.tm_isdst, 0_i32); assert_eq!(utc.tm_gmtoff, 0_i32); - assert_eq!(utc.tm_zone(), "UTC"); assert_eq!(utc.tm_nsec, 54321_i32); } @@ -1225,12 +1206,6 @@ mod tests { assert_eq!(local.tm_yday, 43_i32); assert_eq!(local.tm_isdst, 0_i32); assert_eq!(local.tm_gmtoff, -28800_i32); - - // FIXME (#2350): We should probably standardize on the timezone - // abbreviation. - let zone = local.tm_zone(); - assert!(zone == "PST" || zone == "Pacific Standard Time"); - assert_eq!(local.tm_nsec, 54321_i32); } @@ -1273,7 +1248,6 @@ mod tests { assert!(tm.tm_wday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); - assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 0_i32); } Err(_) => () @@ -1297,7 +1271,6 @@ mod tests { assert!(tm.tm_yday == 0_i32); assert!(tm.tm_isdst == 0_i32); assert!(tm.tm_gmtoff == 0_i32); - assert!(tm.tm_zone() == ""); assert!(tm.tm_nsec == 12340000_i32); } } @@ -1409,10 +1382,10 @@ mod tests { assert!(test("6", "%w")); assert!(test("2009", "%Y")); assert!(test("09", "%y")); - assert!(strptime("UTC", "%Z").unwrap().tm_zone() == "UTC"); - assert!(strptime("PST", "%Z").unwrap().tm_zone() == ""); - assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == 0); - assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == 0); + assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == + 0); + assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == + 0); assert!(test("%", "%%")); // Test for #7256 diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 262721bd63676..c71cf5557e35f 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -46,9 +46,11 @@ pub trait UnicodeStrSlice<'a> { /// /// ```rust /// let gr1 = "a\u0310e\u0301o\u0308\u0332".graphemes(true).collect::>(); - /// assert_eq!(gr1.as_slice(), &["a\u0310", "e\u0301", "o\u0308\u0332"]); + /// let b: &[_] = &["a\u0310", "e\u0301", "o\u0308\u0332"]; + /// assert_eq!(gr1.as_slice(), b); /// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::>(); - /// assert_eq!(gr2.as_slice(), &["a", "\r\n", "b", "🇷🇺🇸🇹"]); + /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"]; + /// assert_eq!(gr2.as_slice(), b); /// ``` fn graphemes(&self, is_extended: bool) -> Graphemes<'a>; @@ -59,7 +61,8 @@ pub trait UnicodeStrSlice<'a> { /// /// ```rust /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::>(); - /// assert_eq!(gr_inds.as_slice(), &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]); + /// let b: &[_] = &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]; + /// assert_eq!(gr_inds.as_slice(), b); /// ``` fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices<'a>; diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs index 9ced6cb62af00..b5ffdef22e968 100644 --- a/src/liburl/lib.rs +++ b/src/liburl/lib.rs @@ -1095,7 +1095,8 @@ mod tests { t("\0", "%00"); t("\n", "%0A"); - t(&[0u8, 10, 37], "%00%0A%25"); + let a: &[_] = &[0u8, 10, 37]; + t(a, "%00%0A%25"); } #[test] @@ -1130,7 +1131,8 @@ mod tests { t("\0", "%00"); t("\n", "%0A"); - t(&[0u8, 10, 37], "%00%0A%25"); + let a: &[_] = &[0u8, 10, 37]; + t(a, "%00%0A%25"); } #[test] diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index 1a9b1c1c818b7..ba20f2c6f27f9 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -127,15 +127,6 @@ rust_list_dir_wfd_fp_buf(void* wfd) { } #endif -typedef struct -{ - size_t fill; // in bytes; if zero, heapified - size_t alloc; // in bytes - uint8_t *data; -} rust_vec; - -typedef rust_vec rust_str_buf; - typedef struct { int32_t tm_sec; int32_t tm_min; @@ -147,7 +138,6 @@ typedef struct { int32_t tm_yday; int32_t tm_isdst; int32_t tm_gmtoff; - rust_str_buf tm_zone; int32_t tm_nsec; } rust_tm; @@ -164,8 +154,10 @@ void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) { out_tm->tm_isdst = in_tm->tm_isdst; } -void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff, - const char *zone, int32_t nsec) { +void tm_to_rust_tm(struct tm* in_tm, + rust_tm* out_tm, + int32_t gmtoff, + int32_t nsec) { out_tm->tm_sec = in_tm->tm_sec; out_tm->tm_min = in_tm->tm_min; out_tm->tm_hour = in_tm->tm_hour; @@ -177,13 +169,6 @@ void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff, out_tm->tm_isdst = in_tm->tm_isdst; out_tm->tm_gmtoff = gmtoff; out_tm->tm_nsec = nsec; - - if (zone != NULL) { - size_t size = strlen(zone); - assert(out_tm->tm_zone.alloc >= size); - memcpy(out_tm->tm_zone.data, zone, size); - out_tm->tm_zone.fill = size; - } } #if defined(__WIN32__) @@ -225,7 +210,7 @@ rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; GMTIME(&s, &tm); - tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec); + tm_to_rust_tm(&tm, timeptr, 0, nsec); } void @@ -234,28 +219,13 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { time_t s = sec; LOCALTIME(&s, &tm); - const char* zone = NULL; #if defined(__WIN32__) int32_t gmtoff = -timezone; - wchar_t wbuffer[64] = {0}; - char buffer[256] = {0}; - // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418), - // so time zone should be converted from UTF-16 string. - // Since wcsftime depends on setlocale() result, - // instead we convert it using MultiByteToWideChar. - if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) { - // ANSI -> UTF-16 - MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t)); - // UTF-16 -> UTF-8 - WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); - zone = buffer; - } #else int32_t gmtoff = tm.tm_gmtoff; - zone = tm.tm_zone; #endif - tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec); + tm_to_rust_tm(&tm, timeptr, gmtoff, nsec); } int64_t diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs index 4f53694ebd622..6b8e126db7790 100644 --- a/src/test/compile-fail/const-cast-different-types.rs +++ b/src/test/compile-fail/const-cast-different-types.rs @@ -9,8 +9,10 @@ // except according to those terms. static a: &'static str = "foo"; -static b: *const u8 = a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&'static str` -static c: *const u8 = &a as *const u8; //~ ERROR mismatched types: expected `*u8` but found `&&'static str` +static b: *const u8 = a as *const u8; +//~^ ERROR mismatched types: expected `*const u8`, found `&'static str` +static c: *const u8 = &a as *const u8; +//~^ ERROR mismatched types: expected `*const u8`, found `&&'static str` fn main() { } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 282cf57df26c0..08e5103810436 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -10,7 +10,7 @@ // Forbid assignment into a dynamically sized type. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index e069eb01ae184..17149941a7e1a 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -10,7 +10,7 @@ // Forbid assignment into a dynamically sized type. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T @@ -42,5 +42,5 @@ pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; - f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar` but found `Bar1` + f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar`, found `Bar1` } diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index a7dc4e123aff8..a609740eaebf5 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -10,7 +10,7 @@ // Attempt to change the type as well as unsizing. -struct Fat { +struct Fat { ptr: T } @@ -22,7 +22,7 @@ pub fn main() { let f1 = Fat { ptr: [1, 2, 3] }; let f2: &Fat<[int, ..3]> = &f1; let f3: &Fat<[uint]> = f2; - //~^ ERROR mismatched types: expected `&Fat<[uint]>` but found `&Fat<[int, .. 3]>` + //~^ ERROR mismatched types: expected `&Fat<[uint]>`, found `&Fat<[int, .. 3]>` // With a trait. let f1 = Fat { ptr: Foo }; diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs index d4ce59b726162..118e4ce7e0834 100644 --- a/src/test/compile-fail/dst-bad-coerce2.rs +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -10,7 +10,7 @@ // Attempt to change the mutability as well as unsizing. -struct Fat { +struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs index bd7c46060a512..7cf647a26d7a7 100644 --- a/src/test/compile-fail/dst-bad-coerce3.rs +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -10,7 +10,7 @@ // Attempt to extend the lifetime as well as unsizing. -struct Fat { +struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs index 0916fa08a3924..9a192334997d2 100644 --- a/src/test/compile-fail/dst-bad-coerce4.rs +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -10,7 +10,7 @@ // Attempt to coerce from unsized to sized. -struct Fat { +struct Fat { ptr: T } @@ -18,5 +18,5 @@ pub fn main() { // With a vec of ints. let f1: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; let f2: &Fat<[int, ..3]> = f1; - //~^ ERROR mismatched types: expected `&Fat<[int, .. 3]>` but found `&Fat<[int]>` + //~^ ERROR mismatched types: expected `&Fat<[int, .. 3]>`, found `&Fat<[int]>` } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index b18e7dad4ac55..cf52639228330 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -13,7 +13,7 @@ // because it would require stack allocation of an unsized temporary (*g in the // test). -struct Fat { +struct Fat { ptr: T } diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index 795e48cb7b005..ab9f7a8453078 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -11,10 +11,12 @@ // aux-build:issue_3907.rs extern crate issue_3907; -type Foo = issue_3907::Foo; //~ ERROR: reference to trait +type Foo = issue_3907::Foo; struct S { name: int } +fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type `issue_3907::Foo` + fn main() {} diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index f7199a92d27cc..199bc3f5c29d9 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -17,7 +17,7 @@ pub enum TraitWrapper { fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { - A(box ref map) => map, //~ ERROR mismatched types: expected `Box` but found a box + A(box ref map) => map, //~ ERROR type `Box` cannot be dereferenced } } diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index 8d9116da81db2..689b8f7c61360 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -9,6 +9,8 @@ // except according to those terms. trait I {} -type K = I; //~ ERROR: reference to trait +type K = I; + +fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type `I` fn main() {} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 3703d4f39acef..14136d96c2dff 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -16,7 +16,7 @@ struct Struct { fn new_struct(r: A) -> Struct { //~^ ERROR variable `r` has dynamically sized type `A` - Struct { r: r } + Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct } trait Curve {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index efd8e75d3d6d3..ef585998aa5a5 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,7 +32,7 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR cannot pack type `Box` as a trait bounded by Send because the type does not fulfil + //~^ ERROR cannot pack type `Box`, which does not fulfill `Send`, as a trait bounded by Send let v = Rc::new(RefCell::new(a)); let w = v.clone(); let b = &*v; diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index 27d272c9f319b..1500a3cbe52db 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -13,6 +13,6 @@ fn first((value, _): (int, f64)) -> int { value } fn main() { - let y = first ((1,2,3)); + let y = first ((1,2.0,3)); //~^ ERROR expected a tuple with 2 elements, found one with 3 elements } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index e1ad27ec5c7a2..7f93c8595f2a2 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -48,8 +48,8 @@ as core::fmt::rt::Piece<'static>)] as [core::fmt::rt::Piece<'static>, .. 1]); let __args_vec = - (&([] as &'static [core::fmt::Argument<'static>]) as - &'static [core::fmt::Argument<'static>]); + (&([] as [core::fmt::Argument<'static>, .. 0]) as + &'static [core::fmt::Argument<'static>, .. 0]); let __args = (unsafe { ((::std::fmt::Arguments::new as @@ -58,7 +58,7 @@ [core::fmt::rt::Piece<'static>, .. 1]), (__args_vec as - &'static [core::fmt::Argument<'static>])) + &'static [core::fmt::Argument<'static>, .. 0])) as core::fmt::Arguments<'static>) } as core::fmt::Arguments<'static>); diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 978cca56b5604..77ee0df5512ef 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -47,7 +47,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index 963c4b4353195..b5a867e60297f 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -29,7 +29,7 @@ digraph block { N27[label="expr y"]; N28[label="expr y -= 1i"]; N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; - N30[label="expr 1"]; + N30[label="expr 1i"]; N31[label="expr y"]; N32[label="expr y -= 1i"]; N33[label="expr 1i"]; diff --git a/src/test/run-pass/dst-dtor-1.rs b/src/test/run-pass/dst-dtor-1.rs new file mode 100644 index 0000000000000..6e2ae117ce7ae --- /dev/null +++ b/src/test/run-pass/dst-dtor-1.rs @@ -0,0 +1,34 @@ +// 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. + +static mut DROP_RAN: bool = false; + +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + unsafe { DROP_RAN = true; } + } +} + +trait Trait {} +impl Trait for Foo {} + +struct Fat { + f: T +} + +pub fn main() { + { + let _x: Box> = box Fat { f: Foo }; + } + unsafe { + assert!(DROP_RAN); + } +} diff --git a/src/test/run-pass/dst-dtor-2.rs b/src/test/run-pass/dst-dtor-2.rs new file mode 100644 index 0000000000000..deaf49228bc84 --- /dev/null +++ b/src/test/run-pass/dst-dtor-2.rs @@ -0,0 +1,31 @@ +// 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. + +static mut DROP_RAN: int = 0; + +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + unsafe { DROP_RAN += 1; } + } +} + +struct Fat { + f: T +} + +pub fn main() { + { + let _x: Box> = box Fat { f: [Foo, Foo, Foo] }; + } + unsafe { + assert!(DROP_RAN == 3); + } +} diff --git a/src/test/run-pass/dst-struct-reflect.rs b/src/test/run-pass/dst-struct-reflect.rs index 297880a8b53de..2028ebf64c217 100644 --- a/src/test/run-pass/dst-struct-reflect.rs +++ b/src/test/run-pass/dst-struct-reflect.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME(15049) Re-enable this test. +// ignore-test // Test that structs with unsized fields work with {:?} reflection. extern crate debug; -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs index 3f01d013cee32..04fe6d5cefdc3 100644 --- a/src/test/run-pass/dst-struct-sole.rs +++ b/src/test/run-pass/dst-struct-sole.rs @@ -10,7 +10,7 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. -struct Fat { +struct Fat { ptr: T } diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index ae1f854ccab34..6b8e25e85590f 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 7429136716c96..9762730955104 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/run-pass/gc-vec.rs b/src/test/run-pass/gc-vec.rs index d2f43aacd66ab..430ee16bc8a26 100644 --- a/src/test/run-pass/gc-vec.rs +++ b/src/test/run-pass/gc-vec.rs @@ -12,11 +12,11 @@ use std::gc::{GC}; fn main() { // A fixed-size array allocated in a garbage-collected box - let x = box(GC) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let x = box(GC) [1i, 2, 3, 4, 5, 6, 7, 8, 9, 10]; assert_eq!(x[0], 1); assert_eq!(x[6], 7); assert_eq!(x[9], 10); let y = x; - assert!(*y == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + assert!(*y == [1i, 2, 3, 4, 5, 6, 7, 8, 9, 10]); } diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 123ad36ee4f2d..0aca74c76c3e7 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -30,7 +30,8 @@ macro_rules! demo { : "r"(&wrap(y, "in", &mut history))); } assert_eq!((x,y), (1,1)); - assert_eq!(history.as_slice(), &["out", "in"]); + let b: &[_] = &["out", "in"]; + assert_eq!(history.as_slice(), b); } } } diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index b0741391d8039..444e8bd37707e 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let mut x = &[1i, 2, 3, 4]; + let mut x: &[_] = &[1i, 2, 3, 4]; let mut result = vec!(); loop { diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index ffbc4e85cb685..de1bb02bfefc6 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -68,15 +68,21 @@ fn main() { assert_eq!(match_vecs_snoc::(&[], &[]), "both empty"); assert_eq!(match_vecs_snoc(&[1i, 2, 3], &[]), "one empty"); - assert_eq!(match_nested_vecs_cons(None, Ok(&[4u, 2u])), "None, Ok(at least two elements)"); + assert_eq!(match_nested_vecs_cons(None, Ok::<&[_], ()>(&[4u, 2u])), + "None, Ok(at least two elements)"); assert_eq!(match_nested_vecs_cons::(None, Err(())), "None, Ok(less than one element)"); - assert_eq!(match_nested_vecs_cons::(Some(&[]), Ok(&[])), "Some(empty), Ok(empty)"); - assert_eq!(match_nested_vecs_cons(Some(&[1i]), Err(())), "Some(non-empty), any"); - assert_eq!(match_nested_vecs_cons(Some(&[(42i, ())]), Ok(&[(1i, ())])), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_cons::(Some::<&[_]>(&[]), Ok::<&[_], ()>(&[])), + "Some(empty), Ok(empty)"); + assert_eq!(match_nested_vecs_cons(Some::<&[_]>(&[1i]), Err(())), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_cons(Some::<&[_]>(&[(42i, ())]), Ok::<&[_], ()>(&[(1i, ())])), + "Some(non-empty), any"); - assert_eq!(match_nested_vecs_snoc(None, Ok(&[4u, 2u])), "None, Ok(at least two elements)"); + assert_eq!(match_nested_vecs_snoc(None, Ok::<&[_], ()>(&[4u, 2u])), + "None, Ok(at least two elements)"); assert_eq!(match_nested_vecs_snoc::(None, Err(())), "None, Ok(less than one element)"); - assert_eq!(match_nested_vecs_snoc::(Some(&[]), Ok(&[])), "Some(empty), Ok(empty)"); - assert_eq!(match_nested_vecs_snoc(Some(&[1i]), Err(())), "Some(non-empty), any"); - assert_eq!(match_nested_vecs_snoc(Some(&[(42i, ())]), Ok(&[(1i, ())])), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_snoc::(Some::<&[_]>(&[]), Ok::<&[_], ()>(&[])), + "Some(empty), Ok(empty)"); + assert_eq!(match_nested_vecs_snoc(Some::<&[_]>(&[1i]), Err(())), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_snoc(Some::<&[_]>(&[(42i, ())]), Ok::<&[_], ()>(&[(1i, ())])), + "Some(non-empty), any"); } diff --git a/src/test/run-pass/order-drop-with-match.rs b/src/test/run-pass/order-drop-with-match.rs index ed5cff36c8bb2..9a76beac9e5f7 100644 --- a/src/test/run-pass/order-drop-with-match.rs +++ b/src/test/run-pass/order-drop-with-match.rs @@ -59,6 +59,7 @@ fn main() { } } unsafe { - assert_eq!(&[1, 2, 3], ORDER.as_slice()); + let expected: &[_] = &[1, 2, 3]; + assert_eq!(expected, ORDER.as_slice()); } } diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 76f3b7bc28077..e95495a42d282 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -72,7 +72,8 @@ fn d() { } fn e() { - match &[1i, 2, 3] { + let x: &[int] = &[1i, 2, 3]; + match x { [1, 2] => (), [..] => () } diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index b96761f8b6493..52e0ba89479f5 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -9,9 +9,9 @@ // except according to those terms. pub fn main() { - assert_eq!((vec!(0, 1)).to_string(), "[0, 1]".to_string()); + assert_eq!((vec!(0i, 1)).to_string(), "[0, 1]".to_string()); - let foo = vec!(3, 4); + let foo = vec!(3i, 4); let bar: &[int] = &[4, 5]; assert_eq!(foo.to_string(), "[3, 4]".to_string()); From 08364a4cacdcd6f161e0fb0ab573ae825e22447b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 26 Aug 2014 12:35:25 +1200 Subject: [PATCH 5/5] Optimise a particularly clown shoes example of DST codegen --- src/librustc/middle/trans/expr.rs | 46 +++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 5f9788d707ac5..c49bb7f4e6b9d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -193,24 +193,46 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, datum = unpack_datum!(bcx, add_env(bcx, expr, datum)); } AutoDerefRef(ref adj) => { - // Extracting a value from a box counts as a deref, but if we are - // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing - // a deref (and wouldn't if we could treat Box like a normal struct). - let autoderefs = match adj.autoref { - Some(ty::AutoUnsizeUniq(..)) => adj.autoderefs - 1, - _ => adj.autoderefs + let (autoderefs, use_autoref) = match adj.autoref { + // Extracting a value from a box counts as a deref, but if we are + // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing + // a deref (and wouldn't if we could treat Box like a normal struct). + Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true), + // We are a bit paranoid about adjustments and thus might have a re- + // borrow here which merely derefs and then refs again (it might have + // a different region or mutability, but we don't care here. It might + // also be just in case we need to unsize. But if there are no nested + // adjustments then it should be a no-op). + Some(ty::AutoPtr(_, _, None)) if adj.autoderefs == 1 => { + match ty::get(datum.ty).sty { + // Don't skip a conversion from Box to &T, etc. + ty::ty_rptr(..) => { + let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1); + let method = bcx.tcx().method_map.borrow().find(&method_call).is_some(); + if method { + // Don't skip an overloaded deref. + (adj.autoderefs, true) + } else { + (adj.autoderefs - 1, false) + } + } + _ => (adj.autoderefs, true), + } + } + _ => (adj.autoderefs, true) }; if autoderefs > 0 { - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); - + // Schedule cleanup. + let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); datum = unpack_datum!( bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs)); } - match adj.autoref { - Some(ref a) => { + // (You might think there is a more elegant way to do this than a + // use_autoref bool, but then you remember that the borrow checker exists). + match (use_autoref, &adj.autoref) { + (true, &Some(ref a)) => { datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, @@ -221,7 +243,7 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); - return DatumBlock {bcx: bcx, datum: datum}; + return DatumBlock::new(bcx, datum); fn apply_autoref<'a>(autoref: &ty::AutoRef, bcx: &'a Block<'a>,