Auto merge of #24333 - arielb1:implement-rfc401, r=nrc

This commit is contained in:
bors 2015-05-19 20:56:51 +00:00
commit c322dbbf8a
42 changed files with 1073 additions and 486 deletions

View File

@ -394,7 +394,9 @@ impl<T: ?Sized> Drop for Arc<T> {
// it's run more than once)
let ptr = *self._ptr;
// if ptr.is_null() { return }
if ptr as usize == 0 || ptr as usize == mem::POST_DROP_USIZE { return }
if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
return
}
// Because `fetch_sub` is already atomic, we do not need to synchronize
// with other threads unless we are going to delete the object. This
@ -524,7 +526,9 @@ impl<T: ?Sized> Drop for Weak<T> {
let ptr = *self._ptr;
// see comments above for why this check is here
if ptr as usize == 0 || ptr as usize == mem::POST_DROP_USIZE { return }
if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
return
}
// If we find out that we were the last weak pointer, then its time to
// deallocate the data entirely. See the discussion in Arc::drop() about

View File

@ -543,7 +543,7 @@ impl<T: ?Sized> Drop for Rc<T> {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
ptr as usize != mem::POST_DROP_USIZE {
ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_strong();
if self.strong() == 0 {
// destroy the contained object
@ -1051,7 +1051,7 @@ impl<T: ?Sized> Drop for Weak<T> {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
ptr as usize != mem::POST_DROP_USIZE {
ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_weak();
// the weak count starts at 1, and will only go to zero if all
// the strong pointers have disappeared.

View File

@ -801,7 +801,6 @@ struct Foo<T: 'static> {
register_diagnostics! {
E0011,
E0012,
E0014,
E0016,
E0017,

View File

@ -94,6 +94,7 @@ pub mod back {
pub mod middle {
pub mod astconv_util;
pub mod astencode;
pub mod cast;
pub mod cfg;
pub mod check_const;
pub mod check_static_recursion;

View File

@ -148,6 +148,7 @@ enum_from_u32! {
tag_table_capture_modes = 0x67,
tag_table_object_cast_map = 0x68,
tag_table_const_qualif = 0x69,
tag_table_cast_kinds = 0x6a,
}
}

View File

@ -23,6 +23,7 @@ use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
use metadata::tydecode::{RegionParameter, ClosureSource};
use metadata::tyencode;
use middle::cast;
use middle::check_const::ConstQualif;
use middle::mem_categorization::Typer;
use middle::privacy::{AllPublic, LastMod};
@ -688,6 +689,10 @@ pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
kind.encode(ebml_w).unwrap();
}
pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
kind.encode(ebml_w).unwrap();
}
pub trait vtable_decoder_helpers<'tcx> {
fn read_vec_per_param_space<T, F>(&mut self, f: F) -> VecPerParamSpace<T> where
F: FnMut(&mut Self) -> T;
@ -1248,6 +1253,13 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
}
if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
rbml_w.id(id);
encode_cast_kind(rbml_w, *cast_kind)
})
}
for &qualif in tcx.const_qualif_map.borrow().get(&id).iter() {
rbml_w.tag(c::tag_table_const_qualif, |rbml_w| {
rbml_w.id(id);
@ -1289,6 +1301,8 @@ trait rbml_decoder_decoder_helpers<'tcx> {
-> subst::Substs<'tcx>;
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::AutoAdjustment<'tcx>;
fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> cast::CastKind;
fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::ClosureKind;
fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@ -1641,6 +1655,12 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
}).unwrap()
}
fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-> cast::CastKind
{
Decodable::decode(self).unwrap()
}
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::ClosureKind
{
@ -1801,6 +1821,11 @@ fn decode_side_tables(dcx: &DecodeContext,
dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id),
closure_kind);
}
c::tag_table_cast_kinds => {
let cast_kind =
val_dsr.read_cast_kind(dcx);
dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind);
}
c::tag_table_const_qualif => {
let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap();
dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif);

View File

@ -0,0 +1,77 @@
// Copyright 2015 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.
// Helpers for handling cast expressions, used in both
// typeck and trans.
use middle::ty::{self, Ty};
use syntax::ast;
/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntTy {
U(ast::UintTy),
I,
CEnum,
Bool,
Char
}
// Valid types for the result of a non-coercion cast
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum CastTy<'tcx> {
/// Various types that are represented as ints and handled mostly
/// in the same way, merged for easier matching.
Int(IntTy),
/// Floating-Point types
Float,
/// Function Pointers
FnPtr,
/// Raw pointers
Ptr(&'tcx ty::mt<'tcx>),
/// References
RPtr(&'tcx ty::mt<'tcx>),
}
/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum CastKind {
CoercionCast,
PtrPtrCast,
PtrAddrCast,
AddrPtrCast,
NumericCast,
EnumCast,
PrimIntCast,
U8CharCast,
ArrayPtrCast,
FnPtrPtrCast,
FnPtrAddrCast
}
impl<'tcx> CastTy<'tcx> {
pub fn from_ty(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>)
-> Option<CastTy<'tcx>> {
match t.sty {
ty::ty_bool => Some(CastTy::Int(IntTy::Bool)),
ty::ty_char => Some(CastTy::Int(IntTy::Char)),
ty::ty_int(_) => Some(CastTy::Int(IntTy::I)),
ty::ty_uint(u) => Some(CastTy::Int(IntTy::U(u))),
ty::ty_float(_) => Some(CastTy::Float),
ty::ty_enum(..) if ty::type_is_c_like_enum(
tcx, t) => Some(CastTy::Int(IntTy::CEnum)),
ty::ty_ptr(ref mt) => Some(CastTy::Ptr(mt)),
ty::ty_rptr(_, ref mt) => Some(CastTy::RPtr(mt)),
ty::ty_bare_fn(..) => Some(CastTy::FnPtr),
_ => None,
}
}
}

View File

@ -24,6 +24,7 @@
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
// by borrowck::gather_loans
use middle::cast::{CastKind};
use middle::const_eval;
use middle::def;
use middle::expr_use_visitor as euv;
@ -32,11 +33,10 @@ use middle::mem_categorization as mc;
use middle::traits;
use middle::ty::{self, Ty};
use util::nodemap::NodeMap;
use util::ppaux;
use util::ppaux::Repr;
use syntax::ast;
use syntax::codemap::Span;
use syntax::print::pprust;
use syntax::visit::{self, Visitor};
use std::collections::hash_map::Entry;
@ -197,7 +197,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &ast::Item) {
debug!("visit_item(item={})", pprust::item_to_string(i));
debug!("visit_item(item={})", i.repr(self.tcx));
match i.node {
ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
self.check_static_type(&**expr);
@ -440,26 +440,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
}
}
ast::ExprCast(ref from, _) => {
let toty = ty::expr_ty(v.tcx, e);
let fromty = ty::expr_ty(v.tcx, &**from);
let is_legal_cast =
ty::type_is_numeric(toty) ||
ty::type_is_unsafe_ptr(toty) ||
(ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
if !is_legal_cast {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0012,
"can not cast to `{}` in {}s",
ppaux::ty_to_string(v.tcx, toty), v.msg());
}
}
if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0018,
"can not cast a pointer to an integer in {}s", v.msg());
debug!("Checking const cast(id={})", from.id);
match v.tcx.cast_kinds.borrow().get(&from.id) {
None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0018,
"can't cast a pointer to an integer in {}s", v.msg());
}
}
_ => {}
}
}
ast::ExprPath(..) => {

View File

@ -1002,7 +1002,7 @@ fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult
macro_rules! convert_val {
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
match val {
const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
const_bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),

View File

@ -41,6 +41,7 @@ use session::Session;
use lint;
use metadata::csearch;
use middle;
use middle::cast;
use middle::check_const;
use middle::const_eval;
use middle::def::{self, DefMap, ExportMap};
@ -288,15 +289,6 @@ pub struct field_ty {
pub origin: ast::DefId, // The DefId of the struct in which the field is declared.
}
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct creader_cache_key {
pub cnum: CrateNum,
pub pos: usize,
pub len: usize
}
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct ItemVariances {
pub types: VecPerParamSpace<Variance>,
@ -562,6 +554,15 @@ pub enum vtable_origin<'tcx> {
// expr to the associated trait ref.
pub type ObjectCastMap<'tcx> = RefCell<NodeMap<ty::PolyTraitRef<'tcx>>>;
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct creader_cache_key {
pub cnum: CrateNum,
pub pos: usize,
pub len: usize
}
/// A restriction that certain types must be the same size. The use of
/// `transmute` gives rise to these restrictions. These generally
/// cannot be checked until trans; therefore, each call to `transmute`
@ -827,6 +828,10 @@ pub struct ctxt<'tcx> {
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
/// Maps a cast expression to its kind. This is keyed on the
/// *from* expression of the cast, not the cast itself.
pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
}
impl<'tcx> ctxt<'tcx> {
@ -2817,6 +2822,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
type_impls_sized_cache: RefCell::new(HashMap::new()),
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
}
}

View File

@ -206,7 +206,7 @@ impl LintPass for TypeLimits {
let (min, max) = int_ty_range(int_type);
let negative = self.negated_expr_id == e.id;
if (negative && v > (min.abs() as u64)) ||
if (negative && v > min.wrapping_neg() as u64) ||
(!negative && v > (max.abs() as u64)) {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
&*format!("literal out of range for {:?}", t));

View File

@ -795,43 +795,40 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}
pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
match *r {
CEnum(ity, _, _) => ity.is_signed(),
General(ity, _, _) => ity.is_signed(),
Univariant(..) => false,
RawNullablePointer { .. } => false,
StructWrappedNullablePointer { .. } => false,
}
}
/// Obtain the actual discriminant of a value.
pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
scrutinee: ValueRef, cast_to: Option<Type>)
-> ValueRef {
let signed;
let val;
debug!("trans_get_discr r: {:?}", r);
match *r {
CEnum(ity, min, max) => {
val = load_discr(bcx, ity, scrutinee, min, max);
signed = ity.is_signed();
}
let val = match *r {
CEnum(ity, min, max) => load_discr(bcx, ity, scrutinee, min, max),
General(ity, ref cases, _) => {
let ptr = GEPi(bcx, scrutinee, &[0, 0]);
val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
signed = ity.is_signed();
}
Univariant(..) => {
val = C_u8(bcx.ccx(), 0);
signed = false;
load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr)
}
Univariant(..) => C_u8(bcx.ccx(), 0),
RawNullablePointer { nndiscr, nnty, .. } => {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None);
signed = false;
ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None)
}
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
signed = false;
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
}
}
};
match cast_to {
None => val,
Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
Some(llty) => if is_discr_signed(r) { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
}
}

View File

@ -869,8 +869,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
{
let _icx = push_ctxt("with_cond");
if bcx.unreachable.get() ||
(common::is_const(val) && common::const_to_uint(val) == 0) {
if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) {
return bcx;
}

View File

@ -919,12 +919,6 @@ pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint])
}
}
pub fn is_const(v: ValueRef) -> bool {
unsafe {
llvm::LLVMIsConstant(v) == True
}
}
pub fn const_to_int(v: ValueRef) -> i64 {
unsafe {
llvm::LLVMConstIntGetSExtValue(v)

View File

@ -29,6 +29,7 @@ use trans::declare;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use middle::cast::{CastTy,IntTy};
use middle::subst::Substs;
use middle::ty::{self, Ty};
use util::ppaux::{Repr, ty_to_string};
@ -616,53 +617,64 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
ast::ExprCast(ref base, _) => {
let llty = type_of::type_of(cx, ety);
let (v, basety) = const_expr(cx, &**base, param_substs);
if expr::cast_is_noop(basety, ety) {
let t_cast = ety;
let llty = type_of::type_of(cx, t_cast);
let (v, t_expr) = const_expr(cx, &**base, param_substs);
debug!("trans_const_cast({} as {})", t_expr.repr(cx.tcx()), t_cast.repr(cx.tcx()));
if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
return v;
}
match (expr::cast_type_kind(cx.tcx(), basety),
expr::cast_type_kind(cx.tcx(), ety)) {
(expr::cast_integral, expr::cast_integral) => {
let s = ty::type_is_signed(basety) as Bool;
if type_is_fat_ptr(cx.tcx(), t_expr) {
// Fat pointer casts.
let t_cast_inner = ty::deref(t_cast, true).expect("cast to non-pointer").ty;
let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]),
ptr_ty);
if type_is_fat_ptr(cx.tcx(), t_cast) {
let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
return C_struct(cx, &[addr, info], false)
} else {
return addr;
}
}
match (CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"),
CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast")) {
(CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
let repr = adt::represent_type(cx, t_expr);
let discr = adt::const_get_discrim(cx, &*repr, v);
let iv = C_integral(cx.int_type(), discr, false);
let s = adt::is_discr_signed(&*repr) as Bool;
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
}
(CastTy::Int(_), CastTy::Int(_)) => {
let s = ty::type_is_signed(t_expr) as Bool;
llvm::LLVMConstIntCast(v, llty.to_ref(), s)
}
(expr::cast_integral, expr::cast_float) => {
if ty::type_is_signed(basety) {
(CastTy::Int(_), CastTy::Float) => {
if ty::type_is_signed(t_expr) {
llvm::LLVMConstSIToFP(v, llty.to_ref())
} else {
llvm::LLVMConstUIToFP(v, llty.to_ref())
}
}
(expr::cast_float, expr::cast_float) => {
(CastTy::Float, CastTy::Float) => {
llvm::LLVMConstFPCast(v, llty.to_ref())
}
(expr::cast_float, expr::cast_integral) => {
if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
(CastTy::Float, CastTy::Int(IntTy::I)) => {
llvm::LLVMConstFPToSI(v, llty.to_ref())
}
(expr::cast_enum, expr::cast_integral) => {
let repr = adt::represent_type(cx, basety);
let discr = adt::const_get_discrim(cx, &*repr, v);
let iv = C_integral(cx.int_type(), discr, false);
let ety_cast = expr::cast_type_kind(cx.tcx(), ety);
match ety_cast {
expr::cast_integral => {
let s = ty::type_is_signed(ety) as Bool;
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
}
_ => cx.sess().bug("enum cast destination is not \
integral")
}
(CastTy::Float, CastTy::Int(_)) => {
llvm::LLVMConstFPToUI(v, llty.to_ref())
}
(expr::cast_pointer, expr::cast_pointer) => {
(CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
| (CastTy::RPtr(_), CastTy::Ptr(_)) => {
ptrcast(v, llty)
}
(expr::cast_integral, expr::cast_pointer) => {
(CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
(CastTy::Int(_), CastTy::Ptr(_)) => {
llvm::LLVMConstIntToPtr(v, llty.to_ref())
}
(expr::cast_pointer, expr::cast_integral) => {
(CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
llvm::LLVMConstPtrToInt(v, llty.to_ref())
}
_ => {

View File

@ -166,31 +166,24 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
// Drop branches that are known to be impossible
if is_const(cond_val) && !is_undef(cond_val) {
if const_to_uint(cond_val) == 1 {
match els {
Some(elexpr) => {
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
trans.visit_expr(&*elexpr);
}
None => {}
}
if let Some(cv) = const_to_opt_uint(cond_val) {
if cv == 1 {
// if true { .. } [else { .. }]
bcx = trans_block(bcx, &*thn, dest);
trans::debuginfo::clear_source_location(bcx.fcx);
if let Some(elexpr) = els {
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
trans.visit_expr(&*elexpr);
}
} else {
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
// if false { .. } [else { .. }]
let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
trans.visit_block(&*thn);
match els {
// if false { .. } else { .. }
Some(elexpr) => {
bcx = expr::trans_into(bcx, &*elexpr, dest);
trans::debuginfo::clear_source_location(bcx.fcx);
}
// if false { .. }
None => { }
if let Some(elexpr) = els {
bcx = expr::trans_into(bcx, &*elexpr, dest);
trans::debuginfo::clear_source_location(bcx.fcx);
}
}

View File

@ -48,7 +48,6 @@
#![allow(non_camel_case_types)]
pub use self::cast_kind::*;
pub use self::Dest::*;
use self::lazy_binop_ty::*;
@ -73,6 +72,7 @@ use trans::meth;
use trans::monomorphize;
use trans::tvec;
use trans::type_of;
use middle::cast::{CastKind, CastTy};
use middle::ty::{struct_fields, tup_fields};
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
use middle::ty::{self, Ty};
@ -1981,177 +1981,147 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
bcx
}
fn int_cast(bcx: Block,
lldsttype: Type,
llsrctype: Type,
llsrc: ValueRef,
signed: bool)
-> ValueRef {
let _icx = push_ctxt("int_cast");
let srcsz = llsrctype.int_width();
let dstsz = lldsttype.int_width();
return if dstsz == srcsz {
BitCast(bcx, llsrc, lldsttype)
} else if srcsz > dstsz {
TruncOrBitCast(bcx, llsrc, lldsttype)
} else if signed {
SExtOrBitCast(bcx, llsrc, lldsttype)
} else {
ZExtOrBitCast(bcx, llsrc, lldsttype)
pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>,
expr: &ast::Expr,
t_in: Ty<'tcx>,
t_out: Ty<'tcx>)
-> bool {
if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
return true;
}
}
fn float_cast(bcx: Block,
lldsttype: Type,
llsrctype: Type,
llsrc: ValueRef)
-> ValueRef {
let _icx = push_ctxt("float_cast");
let srcsz = llsrctype.float_width();
let dstsz = lldsttype.float_width();
return if dstsz > srcsz {
FPExt(bcx, llsrc, lldsttype)
} else if srcsz > dstsz {
FPTrunc(bcx, llsrc, lldsttype)
} else { llsrc };
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum cast_kind {
cast_pointer,
cast_fat_ptr,
cast_integral,
cast_float,
cast_enum,
cast_other,
}
pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
match t.sty {
ty::ty_char => cast_integral,
ty::ty_float(..) => cast_float,
ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
if type_is_sized(tcx, mt.ty) {
cast_pointer
} else {
cast_fat_ptr
}
}
ty::ty_bare_fn(..) => cast_pointer,
ty::ty_int(..) => cast_integral,
ty::ty_uint(..) => cast_integral,
ty::ty_bool => cast_integral,
ty::ty_enum(..) => cast_enum,
_ => cast_other
}
}
pub fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool {
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
_ => {
// This condition isn't redundant with the check for CoercionCast:
// different types can be substituted into the same type, and
// == equality can be overconservative if there are regions.
t_in == t_out
}
}
}
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
id: ast::NodeId)
-> DatumBlock<'blk, 'tcx, Expr> {
-> DatumBlock<'blk, 'tcx, Expr>
{
use middle::cast::CastTy::*;
use middle::cast::IntTy::*;
fn int_cast(bcx: Block,
lldsttype: Type,
llsrctype: Type,
llsrc: ValueRef,
signed: bool)
-> ValueRef
{
let _icx = push_ctxt("int_cast");
let srcsz = llsrctype.int_width();
let dstsz = lldsttype.int_width();
return if dstsz == srcsz {
BitCast(bcx, llsrc, lldsttype)
} else if srcsz > dstsz {
TruncOrBitCast(bcx, llsrc, lldsttype)
} else if signed {
SExtOrBitCast(bcx, llsrc, lldsttype)
} else {
ZExtOrBitCast(bcx, llsrc, lldsttype)
}
}
fn float_cast(bcx: Block,
lldsttype: Type,
llsrctype: Type,
llsrc: ValueRef)
-> ValueRef
{
let _icx = push_ctxt("float_cast");
let srcsz = llsrctype.float_width();
let dstsz = lldsttype.float_width();
return if dstsz > srcsz {
FPExt(bcx, llsrc, lldsttype)
} else if srcsz > dstsz {
FPTrunc(bcx, llsrc, lldsttype)
} else { llsrc };
}
let _icx = push_ctxt("trans_cast");
let mut bcx = bcx;
let ccx = bcx.ccx();
let t_in = expr_ty_adjusted(bcx, expr);
let t_out = node_id_type(bcx, id);
let k_in = cast_type_kind(bcx.tcx(), t_in);
let k_out = cast_type_kind(bcx.tcx(), t_out);
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
let ll_t_in = type_of::arg_type_of(ccx, t_in);
let ll_t_out = type_of::arg_type_of(ccx, t_out);
debug!("trans_cast({} as {})", t_in.repr(bcx.tcx()), t_out.repr(bcx.tcx()));
let mut ll_t_in = type_of::arg_type_of(ccx, t_in);
let ll_t_out = type_of::arg_type_of(ccx, t_out);
// Convert the value to be cast into a ValueRef, either by-ref or
// by-value as appropriate given its type:
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
let datum_ty = monomorphize_type(bcx, datum.ty);
if cast_is_noop(datum_ty, t_out) {
if cast_is_noop(bcx.tcx(), expr, 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);
int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
if type_is_fat_ptr(bcx.tcx(), t_in) {
assert!(datum.kind.is_by_ref());
if type_is_fat_ptr(bcx.tcx(), t_out) {
return DatumBlock::new(bcx, Datum::new(
PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
t_out,
Rvalue::new(ByRef)
)).to_expr_datumblock();
} else {
// Return the address
return immediate_rvalue_bcx(bcx,
PointerCast(bcx,
Load(bcx, get_dataptr(bcx, datum.val)),
ll_t_out),
t_out).to_expr_datumblock();
}
(cast_float, cast_float) => {
let llexpr = datum.to_llscalarish(bcx);
float_cast(bcx, ll_t_out, ll_t_in, llexpr)
}
(cast_integral, cast_float) => {
let llexpr = datum.to_llscalarish(bcx);
if s_in {
SIToFP(bcx, llexpr, ll_t_out)
} else { UIToFP(bcx, llexpr, ll_t_out) }
}
(cast_float, cast_integral) => {
let llexpr = datum.to_llscalarish(bcx);
if ty::type_is_signed(t_out) {
FPToSI(bcx, llexpr, ll_t_out)
} else { FPToUI(bcx, llexpr, ll_t_out) }
}
(cast_integral, cast_pointer) => {
let llexpr = datum.to_llscalarish(bcx);
IntToPtr(bcx, llexpr, ll_t_out)
}
(cast_pointer, cast_integral) => {
let llexpr = datum.to_llscalarish(bcx);
PtrToInt(bcx, llexpr, ll_t_out)
}
(cast_fat_ptr, cast_integral) => {
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
PtrToInt(bcx, data_ptr, ll_t_out)
}
(cast_pointer, cast_pointer) => {
let llexpr = datum.to_llscalarish(bcx);
}
let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast");
let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast");
let (llexpr, signed) = if let Int(CEnum) = r_t_in {
let repr = adt::represent_type(ccx, t_in);
let datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
let llexpr_ptr = datum.to_llref();
let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
ll_t_in = val_ty(discr);
(discr, adt::is_discr_signed(&*repr))
} else {
(datum.to_llscalarish(bcx), ty::type_is_signed(t_in))
};
let newval = match (r_t_in, r_t_out) {
(Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
PointerCast(bcx, llexpr, ll_t_out)
}
(cast_fat_ptr, cast_pointer) => {
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
PointerCast(bcx, data_ptr, ll_t_out)
}
(cast_enum, cast_integral) |
(cast_enum, cast_float) => {
let mut bcx = bcx;
let repr = adt::represent_type(ccx, t_in);
let datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
let llexpr_ptr = datum.to_llref();
let lldiscrim_a =
adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
match k_out {
cast_integral => int_cast(bcx, ll_t_out,
val_ty(lldiscrim_a),
lldiscrim_a, true),
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
_ => {
ccx.sess().bug(&format!("translating unsupported cast: \
{} ({:?}) -> {} ({:?})",
t_in.repr(bcx.tcx()),
k_in,
t_out.repr(bcx.tcx()),
k_out))
}
}
}
_ => ccx.sess().bug(&format!("translating unsupported cast: \
{} ({:?}) -> {} ({:?})",
t_in.repr(bcx.tcx()),
k_in,
t_out.repr(bcx.tcx()),
k_out))
(Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
(Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
(Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
(Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
(Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
(Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
(Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
(Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),
_ => ccx.sess().span_bug(expr.span,
&format!("translating unsupported cast: \
{} -> {}",
t_in.repr(bcx.tcx()),
t_out.repr(bcx.tcx()))
)
};
return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
}

View File

@ -9,6 +9,29 @@
// except according to those terms.
//! Code for type-checking cast expressions.
//!
//! A cast `e as U` is valid if one of the following holds:
//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
//! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
//! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
//! * `e` is a C-like enum and `U` is an integer type; *enum-cast*
//! * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
//! * `e` has type `u8` and `U` is `char`; *u8-char-cast*
//! * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
//! * `e` is a function pointer type and `U` has type `*T`,
//! while `T: Sized`; *fptr-ptr-cast*
//! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
//!
//! where `&.T` and `*T` are references of either mutability,
//! and where unsize_kind(`T`) is the kind of the unsize info
//! in `T` - a vtable or a length (or `()` if `T: Sized`).
//!
//! Casting is not transitive, that is, even if `e as U1 as U2` is a valid
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
//! `U1` coerces to `U2`).
use super::coercion;
use super::demand;
@ -16,11 +39,13 @@ use super::FnCtxt;
use super::structurally_resolved_type;
use lint;
use middle::infer;
use middle::cast::{CastKind, CastTy};
use middle::ty;
use middle::ty::Ty;
use syntax::ast;
use syntax::ast::UintTy::{TyU8};
use syntax::codemap::Span;
use util::ppaux::Repr;
/// Reifies a cast check to be checked once we have full type information for
/// a function context.
@ -31,6 +56,52 @@ pub struct CastCheck<'tcx> {
span: Span,
}
/// The kind of the unsize info (length or vtable) - we only allow casts between
/// fat pointers if their unsize-infos have the same kind.
#[derive(Copy, Clone, PartialEq, Eq)]
enum UnsizeKind<'tcx> {
Vtable,
Length,
/// The unsize info of this projection
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
/// The unsize info of this parameter
OfParam(&'tcx ty::ParamTy)
}
/// Returns the kind of unsize information of t, or None
/// if t is sized or it is unknown.
fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
t: Ty<'tcx>)
-> Option<UnsizeKind<'tcx>> {
match t.sty {
ty::ty_vec(_, None) | ty::ty_str => Some(UnsizeKind::Length),
ty::ty_trait(_) => Some(UnsizeKind::Vtable),
ty::ty_struct(did, substs) => {
match ty::struct_fields(fcx.tcx(), did, substs).pop() {
None => None,
Some(f) => unsize_kind(fcx, f.mt.ty)
}
}
// We should really try to normalize here.
ty::ty_projection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
ty::ty_param(ref p) => Some(UnsizeKind::OfParam(p)),
_ => None
}
}
#[derive(Copy, Clone)]
enum CastError {
CastToBool,
CastToChar,
DifferingKinds,
IllegalCast,
NeedViaPtr,
NeedViaInt,
NeedViaUsize,
NonScalar,
RefToMutPtr
}
impl<'tcx> CastCheck<'tcx> {
pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
-> CastCheck<'tcx> {
@ -41,155 +112,270 @@ impl<'tcx> CastCheck<'tcx> {
span: span,
}
}
}
pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
t_1: Ty<'tcx>,
t_e: Ty<'tcx>) {
fcx.type_error_message(span, |actual| {
format!("illegal cast; cast through an \
integer first: `{}` as `{}`",
actual,
fcx.infcx().ty_to_string(t_1))
}, t_e, None);
}
let span = cast.span;
let e = &cast.expr;
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
let tcx = fcx.tcx();
// Check for trivial casts.
if !ty::type_has_ty_infer(t_1) {
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
e.id,
span,
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
replaced by coercion, this might require type \
ascription or a temporary variable",
fcx.infcx().ty_to_string(t_e),
fcx.infcx().ty_to_string(t_1)));
} else {
tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS,
e.id,
span,
format!("trivial cast: `{}` as `{}`. Cast can be \
replaced by coercion, this might require type \
ascription or a temporary variable",
fcx.infcx().ty_to_string(t_e),
fcx.infcx().ty_to_string(t_1)));
fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>,
e: CastError) {
match e {
CastError::NeedViaPtr |
CastError::NeedViaInt |
CastError::NeedViaUsize => {
fcx.type_error_message(self.span, |actual| {
format!("illegal cast; cast through {} first: `{}` as `{}`",
match e {
CastError::NeedViaPtr => "a raw pointer",
CastError::NeedViaInt => "an integer",
CastError::NeedViaUsize => "a usize",
_ => unreachable!()
},
actual,
fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None)
}
CastError::CastToBool => {
span_err!(fcx.tcx().sess, self.span, E0054,
"cannot cast as `bool`, compare with zero instead");
}
CastError::CastToChar => {
fcx.type_error_message(self.span, |actual| {
format!("only `u8` can be cast as `char`, not `{}`", actual)
}, self.expr_ty, None);
}
CastError::NonScalar => {
fcx.type_error_message(self.span, |actual| {
format!("non-scalar cast: `{}` as `{}`",
actual,
fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None);
}
CastError::IllegalCast => {
fcx.type_error_message(self.span, |actual| {
format!("illegal cast: `{}` as `{}`",
actual,
fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None);
}
CastError::DifferingKinds => {
fcx.type_error_message(self.span, |actual| {
format!("illegal cast: `{}` as `{}`; vtable kinds may not match",
actual,
fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None);
}
CastError::RefToMutPtr => {
span_err!(fcx.tcx().sess, self.span, E0188,
"cannot cast an immutable reference to a \
mutable pointer");
}
return;
}
}
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
let t_e_is_scalar = ty::type_is_scalar(t_e);
let t_e_is_integral = ty::type_is_integral(t_e);
let t_e_is_float = ty::type_is_floating_point(t_e);
let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e);
let t_1_is_scalar = ty::type_is_scalar(t_1);
let t_1_is_integral = ty::type_is_integral(t_1);
let t_1_is_char = ty::type_is_char(t_1);
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
let t_1_is_float = ty::type_is_floating_point(t_1);
let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1);
let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
// casts to scalars other than `char` and `bare fn` are trivial
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
if t_e_is_bare_fn_item && t_1_is_bare_fn {
demand::coerce(fcx, e.span, t_1, &e);
} else if t_1_is_char {
let t_e = fcx.infcx().shallow_resolve(t_e);
if t_e.sty != ty::ty_uint(ast::TyU8) {
fcx.type_error_message(span, |actual| {
format!("only `u8` can be cast as `char`, not `{}`", actual)
}, t_e, None);
}
} else if t_1.sty == ty::ty_bool {
span_err!(tcx.sess, span, E0054,
"cannot cast as `bool`, compare with zero instead");
} else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) &&
!(t_1_is_integral || t_1_is_float) {
// Casts from float must go through an integer
cast_through_integer_err(fcx, span, t_1, t_e)
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) &&
!(t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
// Casts to float must go through an integer or boolean
cast_through_integer_err(fcx, span, t_1, t_e)
} else if t_e_is_c_enum && t_1_is_trivial {
if ty::type_is_unsafe_ptr(t_1) {
// ... and likewise with C enum -> *T
cast_through_integer_err(fcx, span, t_1, t_e)
}
// casts from C-like enums are allowed
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
match t1.sty {
ty::ty_vec(_, Some(_)) => {}
_ => return false
}
if ty::type_needs_infer(t2) {
// This prevents this special case from going off when casting
// to a type that isn't fully specified; e.g. `as *_`. (Issue
// #14893.)
return false
}
let el = ty::sequence_element_type(fcx.tcx(), t1);
infer::mk_eqty(fcx.infcx(),
false,
infer::Misc(sp),
el,
t2).is_ok()
fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
let t_cast = self.cast_ty;
let t_expr = self.expr_ty;
if ty::type_is_numeric(t_cast) && ty::type_is_numeric(t_expr) {
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
self.expr.id,
self.span,
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
replaced by coercion, this might require type \
ascription or a temporary variable",
fcx.infcx().ty_to_string(t_expr),
fcx.infcx().ty_to_string(t_cast)));
} else {
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
self.expr.id,
self.span,
format!("trivial cast: `{}` as `{}`. Cast can be \
replaced by coercion, this might require type \
ascription or a temporary variable",
fcx.infcx().ty_to_string(t_expr),
fcx.infcx().ty_to_string(t_cast)));
}
// 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, ..n] to *T or
&T to *T. */
match (&t_e.sty, &t_1.sty) {
(&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
&ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
if types_compatible(fcx, e.span, mt1, mt2) => {
/* this case is allowed */
pub fn check<'a>(mut self, fcx: &FnCtxt<'a, 'tcx>) {
self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty);
self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty);
debug!("check_cast({}, {} as {})", self.expr.id, self.expr_ty.repr(fcx.tcx()),
self.cast_ty.repr(fcx.tcx()));
if ty::type_is_error(self.expr_ty) || ty::type_is_error(self.cast_ty) {
// No sense in giving duplicate error messages
} else if self.try_coercion_cast(fcx) {
self.trivial_cast_lint(fcx);
debug!(" -> CoercionCast");
fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id,
CastKind::CoercionCast);
} else { match self.do_check(fcx) {
Ok(k) => {
debug!(" -> {:?}", k);
fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id, k);
}
Err(e) => self.report_cast_error(fcx, e)
};}
}
/// Check a cast, and report an error if one exists. In some cases, this
/// can return Ok and create type errors in the fcx rather than returning
/// directly. coercion-cast is handled in check instead of here.
fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
use middle::cast::IntTy::*;
use middle::cast::CastTy::*;
let (t_from, t_cast) = match (CastTy::from_ty(fcx.tcx(), self.expr_ty),
CastTy::from_ty(fcx.tcx(), self.cast_ty)) {
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
_ => {
demand::coerce(fcx, e.span, t_1, &e);
return Err(CastError::NonScalar)
}
};
match (t_from, t_cast) {
// These types have invariants! can't cast into them.
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
// * -> Bool
(_, Int(Bool)) => Err(CastError::CastToBool),
// * -> Char
(Int(U(ast::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
(_, Int(Char)) => Err(CastError::CastToChar),
// prim -> float,ptr
(Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float)
=> Err(CastError::NeedViaInt),
(Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_))
=> Err(CastError::NeedViaUsize),
// ptr -> *
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
(RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
(Float, Ptr(_)) => Err(CastError::NeedViaUsize),
(RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
// prim -> prim
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
(Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
(Int(_), Int(_)) |
(Int(_), Float) |
(Float, Int(_)) |
(Float, Float) => Ok(CastKind::NumericCast),
}
}
fn check_ptr_ptr_cast<'a>(&self,
fcx: &FnCtxt<'a, 'tcx>,
m_expr: &'tcx ty::mt<'tcx>,
m_cast: &'tcx ty::mt<'tcx>)
-> Result<CastKind, CastError>
{
debug!("check_ptr_ptr_cast m_expr={} m_cast={}",
m_expr.repr(fcx.tcx()), m_cast.repr(fcx.tcx()));
// ptr-ptr cast. vtables must match.
// Cast to sized is OK
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
return Ok(CastKind::PtrPtrCast);
}
// sized -> unsized? report illegal cast (don't complain about vtable kinds)
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
return Err(CastError::IllegalCast);
}
// vtable kinds must match
match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) {
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
_ => Err(CastError::DifferingKinds)
}
}
fn check_fptr_ptr_cast<'a>(&self,
fcx: &FnCtxt<'a, 'tcx>,
m_cast: &'tcx ty::mt<'tcx>)
-> Result<CastKind, CastError>
{
// fptr-ptr cast. must be to sized ptr
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
Ok(CastKind::FnPtrPtrCast)
} else {
Err(CastError::IllegalCast)
}
}
fn check_ptr_addr_cast<'a>(&self,
fcx: &FnCtxt<'a, 'tcx>,
m_expr: &'tcx ty::mt<'tcx>)
-> Result<CastKind, CastError>
{
// ptr-addr cast. must be from sized ptr
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
Ok(CastKind::PtrAddrCast)
} else {
Err(CastError::NeedViaPtr)
}
}
fn check_ref_cast<'a>(&self,
fcx: &FnCtxt<'a, 'tcx>,
m_expr: &'tcx ty::mt<'tcx>,
m_cast: &'tcx ty::mt<'tcx>)
-> Result<CastKind, CastError>
{
// array-ptr-cast.
if m_expr.mutbl == ast::MutImmutable && m_cast.mutbl == ast::MutImmutable {
if let ty::ty_vec(ety, Some(_)) = m_expr.ty.sty {
// 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 will report a type mismatch if needed
demand::eqtype(fcx, self.span, ety, m_cast.ty);
return Ok(CastKind::ArrayPtrCast);
}
}
} else if t1_is_fat_ptr {
// FIXME This should be allowed where the lefthandside is also a fat
// pointer and is the same kind of fat pointer, i.e., array to array,
// trait object to trait object. That is a bit looser than the current
// rquirement that they are pointers to the same type.
if !(fcx.type_is_fat_ptr(t_e, span) &&
ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) {
fcx.type_error_message(span, |actual| {
format!("cast to fat pointer: `{}` as `{}`",
actual,
fcx.infcx().ty_to_string(t_1))
}, t_e, None);
}
} else if !(t_e_is_scalar && t_1_is_trivial) {
fcx.type_error_message(span, |actual| {
format!("non-scalar cast: `{}` as `{}`",
actual,
fcx.infcx().ty_to_string(t_1))
}, t_e, None);
Err(CastError::IllegalCast)
}
fn check_addr_ptr_cast<'a>(&self,
fcx: &FnCtxt<'a, 'tcx>,
m_cast: &'tcx ty::mt<'tcx>)
-> Result<CastKind, CastError>
{
// ptr-addr cast. pointer must be thin.
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
Ok(CastKind::AddrPtrCast)
} else {
Err(CastError::IllegalCast)
}
}
fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
if let Ok(()) = coercion::mk_assignty(fcx,
&self.expr,
self.expr_ty,
self.cast_ty) {
true
} else {
false
}
}
}

View File

@ -528,6 +528,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
fcx.select_all_obligations_or_error();
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
}
@ -1112,20 +1115,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
t_span: Span,
e_span: Span,
t_1: Ty<'tcx>,
t_e: Ty<'tcx>,
t_cast: Ty<'tcx>,
t_expr: Ty<'tcx>,
id: ast::NodeId) {
let tstr = fcx.infcx().ty_to_string(t_1);
let tstr = fcx.infcx().ty_to_string(t_cast);
fcx.type_error_message(span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
}, t_e, None);
match t_e.sty {
}, t_expr, None);
match t_expr.sty {
ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
let mtstr = match mt {
ast::MutMutable => "mut ",
ast::MutImmutable => ""
};
if ty::type_is_trait(t_1) {
if ty::type_is_trait(t_cast) {
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
Ok(s) => {
fcx.tcx().sess.span_suggestion(t_span,
@ -1581,13 +1584,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span)
}
pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool {
if let Some(mt) = ty::deref(ty, true) {
return !self.type_is_known_to_be_sized(mt.ty, span);
}
false
}
pub fn register_builtin_bound(&self,
ty: Ty<'tcx>,
builtin_bound: ty::BuiltinBound,
@ -1810,11 +1806,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_casts(&self) {
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
for check in deferred_cast_checks.iter() {
cast::check_cast(self, check);
for cast in deferred_cast_checks.drain(..) {
cast.check(self);
}
deferred_cast_checks.clear();
}
fn select_all_obligations_and_apply_defaults(&self) {
@ -3410,24 +3404,24 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
let t_1 = fcx.to_ty(t);
let t_1 = structurally_resolved_type(fcx, expr.span, t_1);
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
let t_e = fcx.expr_ty(e);
let t_cast = fcx.to_ty(t);
let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
let t_expr = fcx.expr_ty(e);
// Eagerly check for some obvious errors.
if ty::type_is_error(t_e) {
if ty::type_is_error(t_expr) {
fcx.write_error(id);
} else if !fcx.type_is_known_to_be_sized(t_1, expr.span) {
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id);
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
} else {
// Write a type for the whole expression, assuming everything is going
// to work out Ok.
fcx.write_ty(id, t_1);
fcx.write_ty(id, t_cast);
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
deferred_cast_checks.push(cast_check);
}
}

View File

@ -977,11 +977,11 @@ register_diagnostics! {
E0185,
E0186,
E0187, // can't infer the kind of the closure
E0188, // types differ in mutability
E0189, // can only cast a boxed pointer to a boxed object
E0190, // can only cast a &-pointer to an &-object
E0188, // can not cast a immutable reference to a mutable pointer
E0189, // deprecated: can only cast a boxed pointer to a boxed object
E0190, // deprecated: can only cast a &-pointer to an &-object
E0191, // value of the associated type must be specified
E0192, // negative imples are allowed just for `Send` and `Sync`
E0192, // negative impls are allowed just for `Send` and `Sync`
E0193, // cannot bound type where clause bounds may only be attached to types
// involving type parameters
E0194,

View File

@ -77,7 +77,7 @@ This API is completely unstable and subject to change.
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(collections, collections_drain)]
#![feature(core)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]

View File

@ -28,15 +28,15 @@ impl Foo for isize {
}
pub fn main() {
let a = &42 as &Foo<A=usize, B=char>;
let a = &42isize as &Foo<A=usize, B=char>;
let b = &42 as &Foo<A=usize>;
let b = &42isize as &Foo<A=usize>;
//~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
let c = &42 as &Foo<B=char>;
let c = &42isize as &Foo<B=char>;
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
let d = &42 as &Foo;
let d = &42isize as &Foo;
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
//~| ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
}

View File

@ -0,0 +1,15 @@
// Copyright 2015 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() {
const X: u32 = main as u32; //~ ERROR E0018
const Y: u32 = 0;
const Z: u32 = &Y as *const u32 as u32; //~ ERROR E0018
}

View File

@ -0,0 +1,75 @@
// Copyright 2015 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 illegal_cast<U:?Sized,V:?Sized>(u: *const U) -> *const V
{
u as *const V //~ ERROR vtable kinds
}
fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
{
u as *const str //~ ERROR vtable kinds
}
trait Foo { fn foo(&self) {} }
impl<T> Foo for T {}
enum E {
A, B
}
fn main()
{
let f: f32 = 1.2;
let v = 0 as *const u8;
let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
let foo: &Foo = &f;
let _ = v as &u8; //~ ERROR non-scalar
let _ = v as E; //~ ERROR non-scalar
let _ = v as fn(); //~ ERROR non-scalar
let _ = v as (u32,); //~ ERROR non-scalar
let _ = Some(&v) as *const u8; //~ ERROR non-scalar
let _ = v as f32; //~ ERROR through a usize first
let _ = main as f64; //~ ERROR through a usize first
let _ = &v as usize; //~ ERROR through a raw pointer first
let _ = f as *const u8; //~ ERROR through a usize first
let _ = 3 as bool; //~ ERROR compare with zero
let _ = E::A as bool; //~ ERROR compare with zero
let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast
let _ = false as f32; //~ ERROR through an integer first
let _ = E::A as f32; //~ ERROR through an integer first
let _ = 'a' as f32; //~ ERROR through an integer first
let _ = false as *const u8; //~ ERROR through a usize first
let _ = E::A as *const u8; //~ ERROR through a usize first
let _ = 'a' as *const u8; //~ ERROR through a usize first
let _ = 42usize as *const [u8]; //~ ERROR illegal cast
let _ = v as *const [u8]; //~ ERROR illegal cast
let _ = fat_v as *const Foo;
//~^ ERROR `core::marker::Sized` is not implemented for the type `[u8]`
let _ = foo as *const str; //~ ERROR illegal cast
let _ = foo as *mut str; //~ ERROR illegal cast
let _ = main as *mut str; //~ ERROR illegal cast
let _ = &f as *mut f32; //~ ERROR illegal cast
let _ = &f as *const f64; //~ ERROR illegal cast
let _ = fat_v as usize; //~ ERROR through a raw pointer first
let a : *const str = "hello";
let _ = a as *const Foo;
//~^ ERROR `core::marker::Sized` is not implemented for the type `str`
// check no error cascade
let _ = main.f as *const u32; //~ ERROR attempted access of field
}

View File

@ -13,7 +13,7 @@ fn foo(_x: isize) { }
fn main() {
let v: u64 = 5;
let x = foo as extern "C" fn() -> isize;
//~^ ERROR mismatched types
//~^ ERROR non-scalar cast
let y = v as extern "Rust" fn(isize) -> (isize, isize);
//~^ ERROR non-scalar cast
y(x());

View File

@ -9,18 +9,8 @@
// except according to those terms.
static a: &'static str = "foo";
static b: *const u8 = a as *const u8;
//~^ ERROR mismatched types
//~| expected *const u8
//~| found &'static str
//~| expected u8
//~| found str
static c: *const u8 = &a as *const u8;
//~^ ERROR mismatched types
//~| expected *const u8
//~| found &&'static str
//~| expected u8
//~| found &-ptr
static b: *const u8 = a as *const u8; //~ ERROR illegal cast
static c: *const u8 = &a as *const u8; //~ ERROR illegal cast
fn main() {
}

View File

@ -28,29 +28,29 @@ fn main() {
// if n > m, it's a type mismatch error.
// n < m
let &x = &(&1 as &T);
let &x = &&(&1 as &T);
let &&x = &&(&1 as &T);
let &x = &(&1isize as &T);
let &x = &&(&1isize as &T);
let &&x = &&(&1isize as &T);
// n == m
let &x = &1 as &T; //~ ERROR type `&T` cannot be dereferenced
let &&x = &(&1 as &T); //~ ERROR type `&T` cannot be dereferenced
let box x = box 1 as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced
let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced
let box x = box 1isize as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
// n > m
let &&x = &1 as &T;
let &&x = &1isize as &T;
//~^ ERROR mismatched types
//~| expected `T`
//~| found `&_`
//~| expected trait T
//~| found &-ptr
let &&&x = &(&1 as &T);
let &&&x = &(&1isize as &T);
//~^ ERROR mismatched types
//~| expected `T`
//~| found `&_`
//~| expected trait T
//~| found &-ptr
let box box x = box 1 as Box<T>;
let box box x = box 1isize as Box<T>;
//~^ ERROR mismatched types
//~| expected `T`
//~| found `Box<_>`

View File

@ -8,20 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Make sure casts between thin pointer <-> fat pointer are illegal.
pub trait Trait {}
trait Trait {}
// Make sure casts between thin-pointer <-> fat pointer obey RFC401
fn main() {
let a: &[i32] = &[1, 2, 3];
let b: Box<[i32]> = Box::new([1, 2, 3]);
let p = a as *const [i32];
let q = a.as_ptr();
a as usize; //~ ERROR non-scalar cast
a as usize; //~ ERROR illegal cast
b as usize; //~ ERROR non-scalar cast
p as usize; //~ ERROR illegal cast; cast through a raw pointer
let a: usize = 42;
a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
// #22955
q as *const [i32]; //~ ERROR illegal cast
let a: *const u8 = &42;
a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
// #21397
let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast
let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast
}

View File

@ -15,18 +15,8 @@ struct X {
fn main() {
let x = X { a: [0] };
let _f = &x.a as *mut u8;
//~^ ERROR mismatched types
//~| expected `*mut u8`
//~| found `&[u8; 1]`
//~| expected u8
//~| found array of 1 elements
let _f = &x.a as *mut u8; //~ ERROR illegal cast
let local: [u8; 1] = [0];
let _v = &local as *mut u8;
//~^ ERROR mismatched types
//~| expected `*mut u8`
//~| found `&[u8; 1]`
//~| expected u8,
//~| found array of 1 elements
let _v = &local as *mut u8; //~ ERROR illegal cast
}

View File

@ -14,5 +14,5 @@ enum Test {
fn main() {
let _x = Test::Foo as *const isize;
//~^ ERROR illegal cast; cast through an integer first: `Test` as `*const isize`
//~^ ERROR illegal cast; cast through a usize first: `Test` as `*const isize`
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
static X: usize = 0 as *const usize as usize;
//~^ ERROR: can not cast a pointer to an integer in statics
//~^ ERROR: can't cast a pointer to an integer in statics
fn main() {
assert_eq!(X, 0);

View File

@ -11,5 +11,5 @@
struct Inches(i32);
fn main() {
Inches as f32; //~ ERROR illegal cast; cast through an integer first
Inches as f32; //~ ERROR illegal cast; cast through a usize first
}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any`
0 as &std::any::Any; //~ ERROR non-scalar cast
}

View File

@ -17,6 +17,6 @@ impl Foo for isize {
}
fn main() {
(&5 as &Foo).foo();
(&5isize as &Foo).foo();
//~^ ERROR: no method named `foo` found for type `&Foo` in the current scope
}

View File

@ -28,7 +28,6 @@ fn f<T>(val: T) {
let a = &t as &Gettable<T>;
//~^ ERROR the trait `core::marker::Send` is not implemented
//~^^ ERROR the trait `core::marker::Copy` is not implemented
//~^^^ ERROR the parameter type `T` may not live long enough
}
fn g<T>(val: T) {

View File

@ -11,5 +11,5 @@
fn main() {
let x : i16 = 22;
((&x) as *const i16) as f32;
//~^ ERROR illegal cast; cast through an integer first: `*const i16` as `f32`
//~^ ERROR illegal cast; cast through a usize first: `*const i16` as `f32`
}

View File

@ -28,7 +28,7 @@ fn main() {
let mut x1 = X { y: [0, 0] };
// This is still an error since we don't allow casts from &mut [T; n] to *mut T.
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR mismatched types
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR illegal cast
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
}

View File

@ -0,0 +1,44 @@
// Copyright 2015 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.
#![allow(dead_code)]
// check dtor calling order when casting enums.
use std::sync::atomic;
use std::sync::atomic::Ordering;
use std::mem;
enum E {
A = 0,
B = 1,
C = 2
}
static FLAG: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
impl Drop for E {
fn drop(&mut self) {
// avoid dtor loop
unsafe { mem::forget(mem::replace(self, E::B)) };
FLAG.store(FLAG.load(Ordering::SeqCst)+1, Ordering::SeqCst);
}
}
fn main() {
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
{
let e = E::C;
assert_eq!(e as u32, 2);
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
}
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
}

View File

@ -0,0 +1,55 @@
// Copyright 2015 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.
// Check that you can cast between different pointers to trait objects
// whose vtable have the same kind (both lengths, or both trait pointers).
trait Foo<T> {
fn foo(&self, _: T) -> u32 { 42 }
}
trait Bar {
fn bar(&self) { println!("Bar!"); }
}
impl<T> Foo<T> for () {}
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
impl Bar for () {}
unsafe fn fool<'a>(t: *const (Foo<u32>+'a)) -> u32 {
let bar : *const Bar = t as *const Bar;
let foo_e : *const Foo<u16> = t as *const _;
let r_1 = foo_e as *mut Foo<u32>;
(&*r_1).foo(0)*(&*(bar as *const Foo<u32>)).foo(0)
}
#[repr(C)]
struct FooS<T:?Sized>(T);
#[repr(C)]
struct BarS<T:?Sized>(T);
fn foo_to_bar<T:?Sized>(u: *const FooS<T>) -> *const BarS<T> {
u as *const BarS<T>
}
fn main() {
let x = 4u32;
let y : &Foo<u32> = &x;
let fl = unsafe { fool(y as *const Foo<u32>) };
assert_eq!(fl, (43+4)*(43+4));
let s = FooS([0,1,2]);
let u: &FooS<[u32]> = &s;
let u: *const FooS<[u32]> = u;
let bar_ref : *const BarS<[u32]> = foo_to_bar(u);
let z : &BarS<[u32]> = unsafe{&*bar_ref};
assert_eq!(&z.0, &[0,1,2]);
}

View File

@ -0,0 +1,170 @@
// Copyright 2015 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.
#![allow(dead_code)]
use std::vec;
enum Simple {
A,
B,
C
}
enum Valued {
H8=163,
Z=0,
X=256,
H7=67,
}
enum ValuedSigned {
M1=-1,
P1=1
}
fn main()
{
// coercion-cast
let mut it = vec![137].into_iter();
let itr: &mut vec::IntoIter<u32> = &mut it;
assert_eq!((itr as &mut Iterator<Item=u32>).next(), Some(137));
assert_eq!((itr as &mut Iterator<Item=u32>).next(), None);
assert_eq!(Some(4u32) as Option<u32>, Some(4u32));
assert_eq!((1u32,2u32) as (u32,u32), (1,2));
// this isn't prim-int-cast. Check that it works.
assert_eq!(false as bool, false);
assert_eq!(true as bool, true);
// numeric-cast
let l: u64 = 0x8090a0b0c0d0e0f0;
let lsz: usize = l as usize;
assert_eq!(l as u32, 0xc0d0e0f0);
// numeric-cast
assert_eq!(l as u8, 0xf0);
assert_eq!(l as i8,-0x10);
assert_eq!(l as u32, 0xc0d0e0f0);
assert_eq!(l as u32 as usize as u32, l as u32);
assert_eq!(l as i32,-0x3f2f1f10);
assert_eq!(l as i32 as isize as i32, l as i32);
assert_eq!(l as i64,-0x7f6f5f4f3f2f1f10);
assert_eq!(0 as f64, 0f64);
assert_eq!(1 as f64, 1f64);
assert_eq!(l as f64, 9264081114510712022f64);
assert_eq!(l as i64 as f64, -9182662959198838444f64);
// float overflow : needs fixing
// assert_eq!(l as f32 as i64 as u64, 9264082620822882088u64);
// assert_eq!(l as i64 as f32 as i64, 9182664080220408446i64);
assert_eq!(4294967040f32 as u32, 0xffffff00u32);
assert_eq!(1.844674407370955e19f64 as u64, 0xfffffffffffff800u64);
assert_eq!(9.223372036854775e18f64 as i64, 0x7ffffffffffffc00i64);
assert_eq!(-9.223372036854776e18f64 as i64, 0x8000000000000000u64 as i64);
// addr-ptr-cast/ptr-addr-cast (thin ptr)
let p: *const [u8; 1] = lsz as *const [u8; 1];
assert_eq!(p as usize, lsz);
// ptr-ptr-cast (thin ptr)
let w: *const () = p as *const ();
assert_eq!(w as usize, lsz);
// ptr-ptr-cast (fat->thin)
let u: *const [u8] = unsafe{&*p};
assert_eq!(u as *const u8, p as *const u8);
assert_eq!(u as *const u16, p as *const u16);
// ptr-ptr-cast (both vk=Length)
let mut l : [u8; 2] = [0,1];
let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
let w: *mut [u16] = unsafe {&mut *w};
let w_u8 : *const [u8] = w as *const [u8];
assert_eq!(unsafe{&*w_u8}, &l);
let s: *mut str = w as *mut str;
let l_via_str = unsafe{&*(s as *const [u8])};
assert_eq!(&l, l_via_str);
// enum-cast
assert_eq!(Simple::A as u8, 0);
assert_eq!(Simple::B as u8, 1);
assert_eq!(Valued::H8 as i8, -93);
assert_eq!(Valued::H7 as i8, 67);
assert_eq!(Valued::Z as i8, 0);
assert_eq!(Valued::H8 as u8, 163);
assert_eq!(Valued::H7 as u8, 67);
assert_eq!(Valued::Z as u8, 0);
assert_eq!(Valued::H8 as u16, 163);
assert_eq!(Valued::Z as u16, 0);
assert_eq!(Valued::H8 as u16, 163);
assert_eq!(Valued::Z as u16, 0);
assert_eq!(ValuedSigned::M1 as u16, 65535);
assert_eq!(ValuedSigned::M1 as i16, -1);
assert_eq!(ValuedSigned::P1 as u16, 1);
assert_eq!(ValuedSigned::P1 as i16, 1);
// prim-int-cast
assert_eq!(false as u16, 0);
assert_eq!(true as u16, 1);
assert_eq!(false as i64, 0);
assert_eq!(true as i64, 1);
assert_eq!('a' as u32, 0x61);
assert_eq!('a' as u16, 0x61);
assert_eq!('a' as u8, 0x61);
assert_eq!('א' as u8, 0xd0);
assert_eq!('א' as u16, 0x5d0);
assert_eq!('א' as u32, 0x5d0);
assert_eq!('🐵' as u8, 0x35);
assert_eq!('🐵' as u16, 0xf435);
assert_eq!('🐵' as u32, 0x1f435);
assert_eq!('英' as i16, -0x7d0f);
assert_eq!('英' as u16, 0x82f1);
// u8-char-cast
assert_eq!(0x61 as char, 'a');
assert_eq!(0u8 as char, '\0');
assert_eq!(0xd7 as char, '×');
// array-ptr-cast
let x = [1,2,3];
let first : *const u32 = &x[0];
assert_eq!(first, &x as *const _);
assert_eq!(first, &x as *const u32);
// fptr-addr-cast
fn foo() {
println!("foo!");
}
fn bar() {
println!("bar!");
}
assert!(foo as usize != bar as usize);
assert_eq!(foo as i16, foo as usize as i16);
// fptr-ptr-cast
assert_eq!(foo as *const u8 as usize, foo as usize);
assert!(foo as *const u32 != first);
}
fn foo() { }

View File

@ -32,13 +32,12 @@ fn main() {
// Test conversion to an address (usize).
let a: *const [i32; 3] = &[1, 2, 3];
let b: *const [i32] = a;
assert!(a as usize == b as usize);
assert!(a as usize == b as *const () as usize);
// And conversion to a void pointer/address for trait objects too.
let a: *mut Foo = &mut Bar;
let b = a as *mut ();
let c = a as usize;
let c = a as *const () as usize;
let d = unsafe {
let r: raw::TraitObject = mem::transmute(a);
r.data
@ -46,4 +45,5 @@ fn main() {
assert!(b == d);
assert!(c == d as usize);
}

View File

@ -181,7 +181,6 @@ pub fn main() {
println!("{:?}", true as isize);
println!("{:?}", true as usize);
println!("{:?}", true as *const libc::FILE);
println!("{:?}", true as i8);
println!("{:?}", true as i16);
println!("{:?}", true as i32);
@ -190,8 +189,6 @@ pub fn main() {
println!("{:?}", true as u16);
println!("{:?}", true as u32);
println!("{:?}", true as u64);
println!("{:?}", true as f32);
println!("{:?}", true as f64);
println!("{:?}", 1f32 as isize);
println!("{:?}", 1f32 as usize);