Skip to content

Commit

Permalink
DST coercions and DST structs
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
nrc committed Aug 26, 2014
1 parent 37a94b8 commit 3e62637
Show file tree
Hide file tree
Showing 116 changed files with 3,243 additions and 1,822 deletions.
6 changes: 6 additions & 0 deletions src/liballoc/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
}

Expand Down
60 changes: 0 additions & 60 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -284,64 +282,6 @@ pub trait CloneableVector<T> {

impl<'a, T: Clone> CloneableVector<T> 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<T> = Slice{data: 0 as *T, len: 0};
mem::transmute(slice)
}
} else {
let unit_size = mem::size_of::<T>();
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<T> = 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<T> { Vec::from_slice(*self) }

Expand Down
7 changes: 7 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/libcore/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 0 additions & 1 deletion src/libcore/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,6 @@ pub mod bytes {




//
// Boilerplate traits
//
Expand Down
13 changes: 13 additions & 0 deletions src/libdebug/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}

// NOTE: remove after snapshot
#[cfg(stage0)]
fn visit_estr_fixed(&mut self, n: uint,
sz: uint,
align: uint) -> bool {
Expand Down Expand Up @@ -237,6 +239,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
true
}

#[cfg(stage0)]
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
mtbl: uint, inner: *const TyDesc) -> bool {
self.align(align);
Expand All @@ -246,6 +249,16 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
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);
Expand Down
14 changes: 14 additions & 0 deletions src/libdebug/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(); }

Expand Down Expand Up @@ -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 };
Expand All @@ -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'{']));
Expand Down
2 changes: 1 addition & 1 deletion src/libgreen/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/liblibc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> {
pub enum Nullable<type T> {
Null,
NotNull(T)
}
Expand Down
2 changes: 1 addition & 1 deletion src/librlibc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
// implementations below. If pointer arithmetic is done through integers the
// optimizations start to break down.
extern "rust-intrinsic" {
fn offset<T>(dst: *const T, offset: int) -> *const T;
fn offset<type T>(dst: *const T, offset: int) -> *const T;
}

#[no_mangle]
Expand Down
11 changes: 6 additions & 5 deletions src/librustc/front/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,13 +477,14 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc<ast::Expr> {

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,
}
}
Expand Down
20 changes: 5 additions & 15 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand All @@ -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");
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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)");
}
}
}

Expand Down
Loading

0 comments on commit 3e62637

Please sign in to comment.