diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 1f91c255ddd..2034e4159a2 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1859,6 +1859,19 @@ pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind { } } +fn cast_is_noop(t_in: ty::t, t_out: ty::t) -> bool { + if ty::type_is_boxed(t_in) || ty::type_is_boxed(t_out) { + return false; + } + + match (ty::deref(t_in, true), ty::deref(t_out, true)) { + (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => { + t_in == t_out + } + _ => false + } +} + fn trans_imm_cast<'a>(bcx: &'a Block<'a>, expr: &ast::Expr, id: ast::NodeId) @@ -1877,7 +1890,13 @@ fn trans_imm_cast<'a>(bcx: &'a Block<'a>, // Convert the value to be cast into a ValueRef, either by-ref or // by-value as appropriate given its type: - let datum = unpack_datum!(bcx, trans(bcx, expr)); + let mut datum = unpack_datum!(bcx, trans(bcx, expr)); + + if cast_is_noop(datum.ty, t_out) { + datum.ty = t_out; + return DatumBlock::new(bcx, datum); + } + let newval = match (k_in, k_out) { (cast_integral, cast_integral) => { let llexpr = datum.to_llscalarish(bcx); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0ce4dd96025..c70e8505174 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1502,10 +1502,9 @@ fn check_cast(fcx: &FnCtxt, } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { fn types_compatible(fcx: &FnCtxt, sp: Span, t1: ty::t, t2: ty::t) -> bool { - if !ty::type_is_vec(t1) { - // If the type being casted from is not a vector, this special - // case does not apply. - return false + match ty::get(t1).sty { + ty::ty_vec(_, Some(_)) => {} + _ => return false } if ty::type_needs_infer(t2) { // This prevents this special case from going off when casting @@ -1529,7 +1528,7 @@ fn check_cast(fcx: &FnCtxt, // need to special-case obtaining an unsafe pointer // from a region pointer to a vector. - /* this cast is only allowed from &[T] to *T or + /* this cast is only allowed from &[T, ..n] to *T or &T to *T. */ match (&ty::get(t_e).sty, &ty::get(t_1).sty) { (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index a977e961b13..ef4a9edaa74 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -53,6 +53,15 @@ pub fn main() { assert!(len == 3); } + // raw slice with explicit cast + let a = &[1i, 2, 3] as *const [_]; + unsafe { + let b = (*a)[2]; + assert!(b == 3); + let len = (*a).len(); + assert!(len == 3); + } + // raw DST struct with slice let c: *const Foo<[_]> = &Foo {f: [1i, 2, 3]}; unsafe { @@ -85,6 +94,14 @@ pub fn main() { assert!(len == 3); } + let a = &mut [1i, 2, 3] as *mut [_]; + unsafe { + let b = (*a)[2]; + assert!(b == 3); + let len = (*a).len(); + assert!(len == 3); + } + let c: *mut Foo<[_]> = &mut Foo {f: [1i, 2, 3]}; unsafe { let b = (&*c).f[0];