Skip to content

Commit

Permalink
Permit casting region pointers to unsafe ones.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdm committed Mar 7, 2013
1 parent 2bc301f commit 50277ec
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/librustc/middle/check_const.rs
Expand Up @@ -107,7 +107,7 @@ pub fn check_expr(sess: Session,
expr_lit(_) => (),
expr_cast(_, _) => {
let ety = ty::expr_ty(tcx, e);
if !ty::type_is_numeric(ety) {
if !ty::type_is_numeric(ety) && !ty::type_is_unsafe_ptr(ety) {
sess.span_err(e.span, ~"can not cast to `" +
ppaux::ty_to_str(tcx, ety) +
~"` in a constant expression");
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/trans/consts.rs
Expand Up @@ -110,7 +110,7 @@ pub fn const_autoderef(cx: @CrateContext, ty: ty::t, v: ValueRef)
let mut v1 = v;
loop {
// Only rptrs can be autoderef'ed in a const context.
match ty::get(ty).sty {
match ty::get(t1).sty {
ty::ty_rptr(_, mt) => {
t1 = mt.ty;
v1 = const_deref(cx, v1);
Expand Down Expand Up @@ -338,6 +338,9 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef {
integral or float")
}
}
(expr::cast_pointer, expr::cast_pointer) => {
llvm::LLVMConstPointerCast(v, llty)
}
_ => {
cx.sess.impossible_case(e.span,
~"bad combination of types for cast")
Expand Down
50 changes: 49 additions & 1 deletion src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -93,7 +93,7 @@ use middle::typeck::check::method::TransformTypeNormally;
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer::{resolve_type, force_tvar, mk_eqty};
use middle::typeck::infer;
use middle::typeck::rscope::{binding_rscope, bound_self_region};
use middle::typeck::rscope::{RegionError};
Expand Down Expand Up @@ -2452,6 +2452,44 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
if type_is_c_like_enum(fcx,expr.span,t_e) && t_1_is_scalar {
/* this case is allowed */
} else if type_is_region_ptr(fcx, expr.span, t_e) &&
type_is_unsafe_ptr(fcx, expr.span, t_1) {

fn is_vec(t: ty::t) -> bool {
match ty::get(t).sty {
ty::ty_evec(_,_) => true,
_ => false
}
}
fn types_compatible(fcx: @mut FnCtxt, sp: span, t1: ty::t,
t2: ty::t) -> bool {
if !is_vec(t1) {
false
} else {
let el = ty::sequence_element_type(fcx.tcx(), t1);
infer::mk_eqty(fcx.infcx(), false, sp, el, t2).is_ok()
}
}

// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
// vector elements instead of the original values.
// To allow unsafe pointers to work correctly, we
// 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
&T to *T. */
let te = structurally_resolved_type(fcx, e.span, t_e);
match (&ty::get(te).sty, &ty::get(t_1).sty) {
(&ty::ty_rptr(_, mt1), &ty::ty_ptr(mt2))
if types_compatible(fcx, e.span, mt1.ty, mt2.ty) => {
/* this case is allowed */
}
_ => {
demand::coerce(fcx, e.span, t_1, e);
}
}
} else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) {
/*
If more type combinations should be supported than are
Expand Down Expand Up @@ -3081,6 +3119,16 @@ pub fn type_is_scalar(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool {
return ty::type_is_scalar(typ_s);
}
pub fn type_is_unsafe_ptr(fcx: @mut 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: @mut 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: @mut 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);
Expand Down
14 changes: 14 additions & 0 deletions src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs
@@ -0,0 +1,14 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
let foo = ['h' as u8, 'i' as u8, 0 as u8];
let bar = &foo as *u8; //~ ERROR mismatched types
}
16 changes: 16 additions & 0 deletions src/test/compile-fail/const-cast-different-types.rs
@@ -0,0 +1,16 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

const a: &static/str = &"foo";
const b: *u8 = a as *u8; //~ ERROR non-scalar cast
const c: *u8 = &a as *u8; //~ ERROR mismatched types

fn main() {
}
15 changes: 15 additions & 0 deletions src/test/compile-fail/const-cast-wrong-type.rs
@@ -0,0 +1,15 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

const a: [u8 * 3] = ['h' as u8, 'i' as u8, 0 as u8];
const b: *i8 = &a as *i8; //~ ERROR mismatched types

fn main() {
}
21 changes: 21 additions & 0 deletions src/test/run-pass/const-cast.rs
@@ -0,0 +1,21 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern fn foo() {}

const x: *u8 = foo;
const y: *libc::c_void = x as *libc::c_void;
const a: &static/int = &10;
const b: *int = a as *int;

fn main() {
assert x as *libc::c_void == y;
assert a as *int == b;
}
22 changes: 22 additions & 0 deletions src/test/run-pass/const-str-ptr.rs
@@ -0,0 +1,22 @@
// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

const a: [u8 * 3] = ['h' as u8, 'i' as u8, 0 as u8];
const c: &static/[u8 * 3] = &a;
const b: *u8 = c as *u8;

fn main() {
let foo = &a as *u8;
assert unsafe { str::raw::from_bytes(a) } == ~"hi\x00";
assert unsafe { str::raw::from_buf(foo) } == ~"hi";
assert unsafe { str::raw::from_buf(b) } == ~"hi";
assert unsafe { *b == a[0] };
assert unsafe { *(&c[0] as *u8) == a[0] };
}

0 comments on commit 50277ec

Please sign in to comment.