diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 3d81b01a0c9f8..67d25637093e1 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -616,7 +616,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, let must_write = match item.node { item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) | - item_mod(*) | item_foreign_mod(*) => true, + item_mod(*) | item_foreign_mod(*) | item_const(*) => true, _ => false }; if !must_write && !reachable(ecx, item.id) { return; } @@ -639,6 +639,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_symbol(ecx, ebml_w, item.id); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); ebml_w.end_tag(); } item_fn(_, purity, ref generics, _) => { diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index c00856a0a98bd..58099574126f4 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"); @@ -124,17 +124,11 @@ pub fn check_expr(sess: Session, items without type parameters"); } match def_map.find(&e.id) { - Some(def_variant(_, _)) | - Some(def_struct(_)) => { } + Some(def_const(_)) | + Some(def_fn(_, _)) | + Some(def_variant(_, _)) | + Some(def_struct(_)) => { } - Some(def_const(def_id)) | - Some(def_fn(def_id, _)) => { - if !ast_util::is_local(def_id) { - sess.span_err( - e.span, ~"paths in constants may only refer to \ - crate-local constants or functions"); - } - } Some(def) => { debug!("(checking const) found bad def: %?", def); sess.span_err( @@ -246,11 +240,13 @@ pub fn check_item_recursion(sess: Session, expr_path(*) => { match env.def_map.find(&e.id) { Some(def_const(def_id)) => { - match env.ast_map.get(&def_id.node) { - ast_map::node_item(it, _) => { - (v.visit_item)(it, env, v); + if ast_util::is_local(def_id) { + match env.ast_map.get(&def_id.node) { + ast_map::node_item(it, _) => { + (v.visit_item)(it, env, v); + } + _ => fail!(~"const not bound to an item") } - _ => fail!(~"const not bound to an item") } } _ => () diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index d19ffe8cb211f..1117d9b9bf843 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -11,6 +11,7 @@ use core::prelude::*; use lib::llvm::{llvm, ValueRef, TypeRef, Bool, True, False}; +use metadata::csearch; use middle::const_eval; use middle::trans::adt; use middle::trans::base; @@ -18,6 +19,7 @@ use middle::trans::base::get_insn_ctxt; use middle::trans::common::*; use middle::trans::consts; use middle::trans::expr; +use middle::trans::inline; use middle::trans::machine; use middle::trans::type_of; use middle::ty; @@ -110,7 +112,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); @@ -121,10 +123,12 @@ pub fn const_autoderef(cx: @CrateContext, ty: ty::t, v: ValueRef) } pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef { - if !ast_util::is_local(def_id) { - cx.tcx.sess.bug(~"cross-crate constants"); - } - if !cx.const_values.contains_key(&def_id.node) { + let mut def_id = def_id; + if !ast_util::is_local(def_id) || + !cx.const_values.contains_key(&def_id.node) { + if !ast_util::is_local(def_id) { + def_id = inline::maybe_instantiate_inline(cx, def_id, true); + } match cx.tcx.items.get(&def_id.node) { ast_map::node_item(@ast::item { node: ast::item_const(_, subexpr), _ @@ -338,6 +342,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") @@ -416,8 +423,13 @@ fn const_expr_unchecked(cx: @CrateContext, e: @ast::expr) -> ValueRef { assert pth.types.len() == 0; match cx.tcx.def_map.find(&e.id) { Some(ast::def_fn(def_id, _purity)) => { - assert ast_util::is_local(def_id); - let f = base::get_item_val(cx, def_id.node); + let f = if !ast_util::is_local(def_id) { + let ty = csearch::get_type(cx.tcx, def_id).ty; + base::trans_external_path(cx, def_id, ty) + } else { + assert ast_util::is_local(def_id); + base::get_item_val(cx, def_id.node) + }; let ety = ty::expr_ty_adjusted(cx.tcx, e); match ty::get(ety).sty { ty::ty_bare_fn(*) | ty::ty_ptr(*) => { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 1dae9fccc6211..5fb07d6e7d8f6 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -138,6 +138,7 @@ use middle::trans::consts; use middle::trans::controlflow; use middle::trans::datum::*; use middle::trans::debuginfo; +use middle::trans::inline; use middle::trans::machine; use middle::trans::meth; use middle::trans::tvec; @@ -984,15 +985,54 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { match def { ast::def_const(did) => { let const_ty = expr_ty(bcx, ref_expr); - let val = if did.crate == ast::local_crate { + + #[cfg(stage0)] + fn get_did(_ccx: @CrateContext, did: ast::def_id) + -> ast::def_id { + did + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_did(ccx: @CrateContext, did: ast::def_id) + -> ast::def_id { + if did.crate != ast::local_crate { + inline::maybe_instantiate_inline(ccx, did, true) + } else { + did + } + } + + #[cfg(stage0)] + fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t) + -> ValueRef { + let ccx = bcx.ccx(); + if did.crate == ast::local_crate { + // The LLVM global has the type of its initializer, + // which may not be equal to the enum's type for + // non-C-like enums. + PointerCast(bcx, base::get_item_val(ccx, did.node), + T_ptr(type_of(bcx.ccx(), const_ty))) + } else { + base::trans_external_path(ccx, did, const_ty) + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_val(bcx: block, did: ast::def_id, const_ty: ty::t) + -> ValueRef { // The LLVM global has the type of its initializer, // which may not be equal to the enum's type for // non-C-like enums. - PointerCast(bcx, base::get_item_val(ccx, did.node), + PointerCast(bcx, base::get_item_val(bcx.ccx(), did.node), T_ptr(type_of(bcx.ccx(), const_ty))) - } else { - base::trans_external_path(ccx, did, const_ty) - }; + } + + let did = get_did(ccx, did); + let val = get_val(bcx, did, const_ty); DatumBlock { bcx: bcx, datum: Datum {val: val, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 66c2a28da3d6b..80b13341e54e1 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/auxiliary/cci_const.rs b/src/test/auxiliary/cci_const.rs new file mode 100644 index 0000000000000..b2dd0cc8e5860 --- /dev/null +++ b/src/test/auxiliary/cci_const.rs @@ -0,0 +1,16 @@ +// Copyright 2013 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. + +pub extern fn bar() { +} + +pub const foopy: &static/str = "hi there"; +pub const uint_val: uint = 12; +pub const uint_expr: uint = (1 << uint_val) - 1; 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 0000000000000..a083757a0eb9a --- /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 or the MIT license +// , 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 0000000000000..08fa6915106fe --- /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 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 0000000000000..fe91056d47b6f --- /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 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: *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 0000000000000..9174b45d1000c --- /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: &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-cross-crate-const.rs b/src/test/run-pass/const-cross-crate-const.rs new file mode 100644 index 0000000000000..eb3c482737c22 --- /dev/null +++ b/src/test/run-pass/const-cross-crate-const.rs @@ -0,0 +1,25 @@ +// Copyright 2013 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. + +// xfail-fast +// aux-build:cci_const.rs + +extern mod cci_const; +const foo: &static/str = cci_const::foopy; +const a: uint = cci_const::uint_val; +const b: uint = cci_const::uint_expr + 5; + +fn main() { + assert a == 12; + let foo2 = a; + assert foo2 == cci_const::uint_val; + assert b == cci_const::uint_expr + 5; + assert foo == cci_const::foopy; +} diff --git a/src/test/run-pass/const-cross-crate-extern.rs b/src/test/run-pass/const-cross-crate-extern.rs new file mode 100644 index 0000000000000..e86118f3c433c --- /dev/null +++ b/src/test/run-pass/const-cross-crate-extern.rs @@ -0,0 +1,20 @@ +// Copyright 2013 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. + +// xfail-fast +// aux-build:cci_const.rs + +extern mod cci_const; +use cci_const::bar; +const foo: *u8 = bar; + +fn main() { + assert foo == cci_const::bar; +} diff --git a/src/test/run-pass/const-deref.rs b/src/test/run-pass/const-deref.rs new file mode 100644 index 0000000000000..b6dbf44c840fd --- /dev/null +++ b/src/test/run-pass/const-deref.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: [u8 * 1] = ['h' as u8]; +const b: u8 = (&a)[0]; + +fn main() { + assert b == a[0]; +} \ 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..3438e65f05fad --- /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 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 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