Fix ICE when casting `&[T]` to `*const [T]`

Closes #16947
This commit is contained in:
Nick Cameron 2014-09-03 14:09:07 +12:00
parent dfbd4669cd
commit 7d72bdb226
3 changed files with 41 additions and 6 deletions

View File

@ -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);

View File

@ -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 }),

View File

@ -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];