diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index c0a4a4ea48ca6..510f735377da5 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -96,7 +96,7 @@ fn check_expr(sess: Session, def_map: resolve::DefMap, 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 01533e162830f..cd86e27e436a5 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -325,6 +325,9 @@ fn const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef { if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) } else { llvm::LLVMConstFPToUI(v, llty) } } + (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 c0c990763fbc5..2400f9053a52b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2359,6 +2359,49 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, 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) { + let t1 = structurally_resolved_type(fcx, expr.span, t_e); + let t2 = structurally_resolved_type(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: @fn_ctxt, t1: ty::t, t2: ty::t) + -> bool { + t1 == t2 || + (is_vec(t1) && + ty::sequence_element_type(fcx.tcx(), t1) == t2) + } + + /* this cast is only allowed it's from &static/T or + &static/[T] to *T. */ + match (ty::get(t1).sty, ty::get(t2).sty) { + (ty::ty_rptr(re, mt1), ty::ty_ptr(mt2)) + if types_compatible(fcx, mt1.ty, mt2.ty) => { + match fcx.mk_subr(true, expr.span, ty::re_static, re) { + result::Ok(()) => { + /* this case is allowed for const expresisons */ + } + result::Err(_) => { + fcx.type_error_message(expr.span, |actual| { + fmt!("non-static region to unsafe pointer \ + cast: `%s` as `%s`", actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); + } + } + } + _ => { + fcx.type_error_message(expr.span, |actual| { + fmt!("unrelated cast: `%s` as `%s`", actual, + fcx.infcx().ty_to_str(t_1)) + }, t_e, None); + } + } } else if !(type_is_scalar(fcx,expr.span,t_e) && t_1_is_scalar) { /* If more type combinations should be supported than are @@ -2985,6 +3028,16 @@ fn type_is_scalar(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { return ty::type_is_scalar(typ_s); } +fn type_is_unsafe_ptr(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_unsafe_ptr(typ_s); +} + +fn type_is_region_ptr(fcx: @fn_ctxt, sp: span, typ: ty::t) -> bool { + let typ_s = structurally_resolved_type(fcx, sp, typ); + return ty::type_is_region_ptr(typ_s); +} + fn type_is_c_like_enum(fcx: @fn_ctxt, 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-region-ptr-to-unsafe.rs b/src/test/compile-fail/cast-region-ptr-to-unsafe.rs new file mode 100644 index 0000000000000..aaa8d981f8471 --- /dev/null +++ b/src/test/compile-fail/cast-region-ptr-to-unsafe.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + (&~"hi") as *~str; //~ ERROR illegal borrow +} \ 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 0000000000000..dd5167cf12ee1 --- /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 or the MIT license +// , 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 unrelated cast +const c: *u8 = a as *u8; //~ ERROR non-scalar cast + +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 0000000000000..030cc476a6abe --- /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 or the MIT license +// , 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: &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 0000000000000..10c9ac24a1151 --- /dev/null +++ b/src/test/run-pass/const-str-ptr.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , 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: *u8 = (&a) as *u8; +const c: &[u8 * 3] = &a; + +fn main() { + assert unsafe { str::raw::from_buf(b) } == ~"hi"; + assert unsafe { *b == a[0] }; + assert unsafe { *(c as *u8) == a[0] }; +} \ No newline at end of file