Skip to content

Fix ICE when casting &[T] to *const [T] #16953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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);
Expand Down
9 changes: 4 additions & 5 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }),
Expand Down
17 changes: 17 additions & 0 deletions src/test/run-pass/dst-raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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];
Expand Down