about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-03-04 18:22:03 -0500
committerJosh Matthews <josh@joshmatthews.net>2013-03-07 14:48:28 -0500
commit50277ec555ccc0b72b98028c6fcc0b84511cf9ef (patch)
tree5a73a4d6c09dc159d191d18b46b0690649694513 /src
parent2bc301fd6821a76d91d7c121b2737c473a54897f (diff)
downloadrust-50277ec555ccc0b72b98028c6fcc0b84511cf9ef.tar.gz
rust-50277ec555ccc0b72b98028c6fcc0b84511cf9ef.zip
Permit casting region pointers to unsafe ones.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/trans/consts.rs5
-rw-r--r--src/librustc/middle/typeck/check/mod.rs50
-rw-r--r--src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs14
-rw-r--r--src/test/compile-fail/const-cast-different-types.rs16
-rw-r--r--src/test/compile-fail/const-cast-wrong-type.rs15
-rw-r--r--src/test/run-pass/const-cast.rs21
-rw-r--r--src/test/run-pass/const-str-ptr.rs22
8 files changed, 142 insertions, 3 deletions
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index c00856a0a98..2e528b4c0df 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -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");
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index d19ffe8cb21..0dca64ee8d3 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -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);
@@ -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")
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 66c2a28da3d..80b13341e54 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -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};
@@ -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
@@ -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);
diff --git a/src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs b/src/test/compile-fail/cast-vector-to-unsafe-nonstatic.rs
new file mode 100644
index 00000000000..a083757a0eb
--- /dev/null
+++ b/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
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs
new file mode 100644
index 00000000000..08fa6915106
--- /dev/null
+++ b/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() {
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/const-cast-wrong-type.rs b/src/test/compile-fail/const-cast-wrong-type.rs
new file mode 100644
index 00000000000..fe91056d47b
--- /dev/null
+++ b/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() {
+}
\ No newline at end of file
diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs
new file mode 100644
index 00000000000..9174b45d100
--- /dev/null
+++ b/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;
+}
\ No newline at end of file
diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs
new file mode 100644
index 00000000000..3438e65f05f
--- /dev/null
+++ b/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] };
+}
\ No newline at end of file