From a172f4022dd8d63607860733f0ae8647d4651090 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 5 May 2015 19:34:37 +0300 Subject: [PATCH 1/9] Expose enum discriminant signedness --- src/librustc_trans/trans/adt.rs | 37 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 17c9fa24818..6d4c72c132a 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -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) -> 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) } } } From 83acebc46213e30eac3e9e71b213440104914f4c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 5 May 2015 19:36:47 +0300 Subject: [PATCH 2/9] Overhaul cast semantics and make them follow RFC401 This should hopefully fix all cast-related ICEs once and for all. I managed to make diagnostics hate me and give me spurious "decoder error" - removing $build/tmp/extended-errors seems to fix it. --- src/librustc/diagnostics.rs | 1 - src/librustc/lib.rs | 1 + src/librustc/metadata/common.rs | 1 + src/librustc/middle/astencode.rs | 25 ++ src/librustc/middle/cast.rs | 71 ++++ src/librustc/middle/check_const.rs | 35 +- src/librustc/middle/const_eval.rs | 2 +- src/librustc/middle/ty.rs | 24 +- src/librustc_trans/trans/consts.rs | 70 ++-- src/librustc_trans/trans/expr.rs | 252 ++++++-------- src/librustc_typeck/check/cast.rs | 459 ++++++++++++++++++-------- src/librustc_typeck/check/mod.rs | 13 +- src/librustc_typeck/diagnostics.rs | 8 +- src/librustc_typeck/lib.rs | 2 +- src/test/compile-fail/fat-ptr-cast.rs | 16 +- src/test/compile-fail/issue-22289.rs | 2 +- 16 files changed, 614 insertions(+), 368 deletions(-) create mode 100644 src/librustc/middle/cast.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e9f4860f451..f5cb1bd25d6 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -801,7 +801,6 @@ struct Foo { register_diagnostics! { E0011, - E0012, E0014, E0016, E0017, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 2936b6b1c2b..993d0dcf115 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index f410626714f..478c0f2f564 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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, } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 328972c54e3..e325c03d52d 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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(&mut self, f: F) -> VecPerParamSpace 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); diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/cast.rs new file mode 100644 index 00000000000..4b876cfd80f --- /dev/null +++ b/src/librustc/middle/cast.rs @@ -0,0 +1,71 @@ +// 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 or the MIT license +// , 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; + + +#[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> { + Int(IntTy), + Float, + FPtr, + Ptr(&'tcx ty::mt<'tcx>), + 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, + FPtrPtrCast, + FPtrAddrCast +} + +impl<'tcx> CastTy<'tcx> { + pub fn recognize(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) + -> Option> { + 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::FPtr), + _ => None, + } + } +} diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 8bb83c54da8..6d2465a5cb9 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -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::FPtrAddrCast) => { + 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()); + } } + _ => {} } } ast::ExprPath(..) => { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 72415f54336..03de553e648 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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)), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e988423ac57..15e1ac2f2c6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, @@ -562,6 +554,15 @@ pub enum vtable_origin<'tcx> { // expr to the associated trait ref. pub type ObjectCastMap<'tcx> = RefCell>>; +// 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>, + + /// 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>, } 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()), } } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 503bdf8dadb..29430ad10e6 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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,62 @@ 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_1 = ety; + let llty = type_of::type_of(cx, t_1); + let (v, t_e) = const_expr(cx, &**base, param_substs); + debug!("trans_const_cast({} as {})", t_e.repr(cx.tcx()), t_1.repr(cx.tcx())); + if expr::cast_is_noop(cx.tcx(), base, t_e, t_1) { 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_e) { + // Fat pointer casts. + let t_1_inner = ty::deref(t_1, true).expect("cast to non-pointer").ty; + let ptr_ty = type_of::in_memory_type_of(cx, t_1_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_1) { + 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::recognize(cx.tcx(), t_e).expect("bad input type for cast"), + CastTy::recognize(cx.tcx(), t_1).expect("bad output type for cast")) { + (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => { + let repr = adt::represent_type(cx, t_e); + 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_e) 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_e) { 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()) } + (CastTy::Float, CastTy::Int(_)) => { + if ty::type_is_signed(t_1) { llvm::LLVMConstFPToSI(v, llty.to_ref()) } else { llvm::LLVMConstFPToUI(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") - } - } - (expr::cast_pointer, expr::cast_pointer) => { + (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FPtr, CastTy::Ptr(_)) + | (CastTy::RPtr(_), CastTy::Ptr(_)) => { ptrcast(v, llty) } - (expr::cast_integral, expr::cast_pointer) => { + (CastTy::FPtr, CastTy::FPtr) => 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::FPtr, CastTy::Int(_)) => { llvm::LLVMConstPtrToInt(v, llty.to_ref()) } _ => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 270aacfe143..a65d4225a1f 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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,143 @@ 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, + Load(bcx, get_dataptr(bcx, datum.val)), + 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); - 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)) + } + + let r_t_in = CastTy::recognize(bcx.tcx(), t_in).expect("bad input type for cast"); + let r_t_out = CastTy::recognize(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(_)) | (FPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => PointerCast(bcx, llexpr, ll_t_out), + (Ptr(_), Int(_)) | (FPtr, 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(); } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bc6159c0cff..6ae6d21f987 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -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,46 @@ pub struct CastCheck<'tcx> { span: Span, } +#[derive(Copy, Clone, PartialEq, Eq)] +enum UnsizeKind<'tcx> { + Vtable, + Length, + OfTy(Ty<'tcx>) +} + +/// 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> { + 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) + } + } + ty::ty_projection(..) | ty::ty_param(..) => + Some(UnsizeKind::OfTy(t)), + _ => 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 +106,271 @@ 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_1 = self.cast_ty; + let t_e = self.expr_ty; + if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { + 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_e), + fcx.infcx().ty_to_string(t_1))); + } 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_e), + fcx.infcx().ty_to_string(t_1))); } - // 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 rather than returning + /// directly. coercion-cast is handled in check instead of here. + fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { + use middle::cast::IntTy::*; + use middle::cast::CastTy::*; + + let (t_e, t_1) = match (CastTy::recognize(fcx.tcx(), self.expr_ty), + CastTy::recognize(fcx.tcx(), self.cast_ty)) { + (Some(t_e), Some(t_1)) => (t_e, t_1), _ => { - demand::coerce(fcx, e.span, t_1, &e); + return Err(CastError::NonScalar) + } + }; + + match (t_e, t_1) { + // These types have invariants! can't cast into them. + (_, RPtr(_)) | (_, Int(CEnum)) | (_, FPtr) => 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(m1), Ptr(m2)) => self.check_ptr_ptr_cast(fcx, m1, m2), // ptr-ptr-cast + (Ptr(m_e), Int(_)) => self.check_ptr_addr_cast(fcx, m_e), // ptr-addr-cast + (Ptr(_), Float) | (FPtr, Float) => Err(CastError::NeedViaUsize), + (FPtr, Int(_)) => Ok(CastKind::FPtrAddrCast), + (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr), + // * -> ptr + (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast + (FPtr, 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_e: &'tcx ty::mt<'tcx>, + m_1: &'tcx ty::mt<'tcx>) + -> Result + { + debug!("check_ptr_ptr_cast m_e={} m_1={}", + m_e.repr(fcx.tcx()), m_1.repr(fcx.tcx())); + // ptr-ptr cast. vtables must match. + + // Cast to sized is OK + if fcx.type_is_known_to_be_sized(m_1.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_e.ty, self.span) { + return Err(CastError::IllegalCast); + } + + // vtable kinds must match + match (unsize_kind(fcx, m_1.ty), unsize_kind(fcx, m_e.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_1: &'tcx ty::mt<'tcx>) + -> Result + { + // fptr-ptr cast. must be to sized ptr + + if fcx.type_is_known_to_be_sized(m_1.ty, self.span) { + Ok(CastKind::FPtrPtrCast) + } else { + Err(CastError::IllegalCast) + } + } + + fn check_ptr_addr_cast<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_e: &'tcx ty::mt<'tcx>) + -> Result + { + // ptr-addr cast. must be from sized ptr + + if fcx.type_is_known_to_be_sized(m_e.ty, self.span) { + Ok(CastKind::PtrAddrCast) + } else { + Err(CastError::NeedViaPtr) + } + } + + fn check_ref_cast<'a>(&self, + fcx: &FnCtxt<'a, 'tcx>, + m_e: &'tcx ty::mt<'tcx>, + m_1: &'tcx ty::mt<'tcx>) + -> Result + { + // array-ptr-cast. + + if m_e.mutbl == ast::MutImmutable && m_1.mutbl == ast::MutImmutable { + if let ty::ty_vec(ety, Some(_)) = m_e.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. + // TODO: explain comment. + + // this will report a type mismatch if needed + demand::eqtype(fcx, self.span, ety, m_1.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_1: &'tcx ty::mt<'tcx>) + -> Result + { + // ptr-addr cast. pointer must be thin. + if fcx.type_is_known_to_be_sized(m_1.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 + } + } + } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index db39d3c05ed..d3cf9ae6dff 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1581,13 +1581,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 +1803,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) { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index bb60de955f0..51c0f8fea1c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -825,11 +825,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, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index baecaa2e221..25602cb0ee3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -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)] diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 2099424b05c..672dec01e94 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -8,20 +8,24 @@ // 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. +// Make sure casts between thin-pointer <-> fat pointer obey RFC401 pub trait Trait {} 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 - 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 } diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs index 1fdc8735714..bcbc414d353 100644 --- a/src/test/compile-fail/issue-22289.rs +++ b/src/test/compile-fail/issue-22289.rs @@ -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 } From 9ee2335bfcc6974e73b344b948b71cacc1fc5ea4 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 5 May 2015 19:39:27 +0300 Subject: [PATCH 3/9] Fix test fallout, and add some rather comprehensive tests. --- .../compile-fail/cast-ptr-to-int-const.rs | 15 ++ src/test/compile-fail/cast-rfc0401.rs | 70 ++++++++ src/test/compile-fail/cast-to-bare-fn.rs | 2 +- .../const-cast-different-types.rs | 14 +- src/test/compile-fail/fat-ptr-cast.rs | 3 - src/test/compile-fail/issue-14845.rs | 14 +- src/test/compile-fail/issue-17444.rs | 2 +- src/test/compile-fail/issue-21554.rs | 2 +- .../typeck-cast-pointer-to-float.rs | 2 +- .../compile-fail/vector-cast-weirdness.rs | 2 +- src/test/run-pass/cast-enum-with-dtor.rs | 44 +++++ .../run-pass/cast-rfc0401-vtable-kinds.rs | 52 ++++++ src/test/run-pass/cast-rfc0401.rs | 169 ++++++++++++++++++ src/test/run-pass/supported-cast.rs | 3 - 14 files changed, 359 insertions(+), 35 deletions(-) create mode 100644 src/test/compile-fail/cast-ptr-to-int-const.rs create mode 100644 src/test/compile-fail/cast-rfc0401.rs create mode 100644 src/test/run-pass/cast-enum-with-dtor.rs create mode 100644 src/test/run-pass/cast-rfc0401-vtable-kinds.rs create mode 100644 src/test/run-pass/cast-rfc0401.rs diff --git a/src/test/compile-fail/cast-ptr-to-int-const.rs b/src/test/compile-fail/cast-ptr-to-int-const.rs new file mode 100644 index 00000000000..7c32e31d23b --- /dev/null +++ b/src/test/compile-fail/cast-ptr-to-int-const.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs new file mode 100644 index 00000000000..3aa866677a8 --- /dev/null +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -0,0 +1,70 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn illegal_cast(u: *const U) -> *const V +{ + u as *const V //~ ERROR vtable kinds +} + +fn illegal_cast_2(u: *const U) -> *const str +{ + u as *const str //~ ERROR vtable kinds +} + +trait Foo { fn foo(&self) {} } +impl 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 illegal cast + 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 + + // check no error cascade + let _ = main.f as *const u32; //~ ERROR attempted access of field + +} diff --git a/src/test/compile-fail/cast-to-bare-fn.rs b/src/test/compile-fail/cast-to-bare-fn.rs index a7f0917ed86..7cc5c727bc7 100644 --- a/src/test/compile-fail/cast-to-bare-fn.rs +++ b/src/test/compile-fail/cast-to-bare-fn.rs @@ -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()); diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs index 6e3732908ac..e6851f02cb6 100644 --- a/src/test/compile-fail/const-cast-different-types.rs +++ b/src/test/compile-fail/const-cast-different-types.rs @@ -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() { } diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 672dec01e94..f6633547a7b 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -9,9 +9,6 @@ // except according to those terms. // Make sure casts between thin-pointer <-> fat pointer obey RFC401 - -pub trait Trait {} - fn main() { let a: &[i32] = &[1, 2, 3]; let b: Box<[i32]> = Box::new([1, 2, 3]); diff --git a/src/test/compile-fail/issue-14845.rs b/src/test/compile-fail/issue-14845.rs index 3f994102a17..219f08ad35a 100644 --- a/src/test/compile-fail/issue-14845.rs +++ b/src/test/compile-fail/issue-14845.rs @@ -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 } diff --git a/src/test/compile-fail/issue-17444.rs b/src/test/compile-fail/issue-17444.rs index 011a9c17776..a079161d42e 100644 --- a/src/test/compile-fail/issue-17444.rs +++ b/src/test/compile-fail/issue-17444.rs @@ -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` } diff --git a/src/test/compile-fail/issue-21554.rs b/src/test/compile-fail/issue-21554.rs index a2cac55033c..16ce84715b1 100644 --- a/src/test/compile-fail/issue-21554.rs +++ b/src/test/compile-fail/issue-21554.rs @@ -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 } diff --git a/src/test/compile-fail/typeck-cast-pointer-to-float.rs b/src/test/compile-fail/typeck-cast-pointer-to-float.rs index 285a5dbee05..e10a76c65bc 100644 --- a/src/test/compile-fail/typeck-cast-pointer-to-float.rs +++ b/src/test/compile-fail/typeck-cast-pointer-to-float.rs @@ -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` } diff --git a/src/test/compile-fail/vector-cast-weirdness.rs b/src/test/compile-fail/vector-cast-weirdness.rs index cac52306d6a..10227f1820d 100644 --- a/src/test/compile-fail/vector-cast-weirdness.rs +++ b/src/test/compile-fail/vector-cast-weirdness.rs @@ -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]; } diff --git a/src/test/run-pass/cast-enum-with-dtor.rs b/src/test/run-pass/cast-enum-with-dtor.rs new file mode 100644 index 00000000000..0bc1e33ce46 --- /dev/null +++ b/src/test/run-pass/cast-enum-with-dtor.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs new file mode 100644 index 00000000000..76516a69f79 --- /dev/null +++ b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs @@ -0,0 +1,52 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn foo(&self, _: T) -> u32 { 42 } +} + +trait Bar { + fn bar(&self) { println!("Bar!"); } +} + +impl Foo for () {} +impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } +impl Bar for () {} + +unsafe fn fool<'a>(t: *const (Foo+'a)) -> u32 { + let bar : *const Bar = t as *const Bar; + let foo_e : *const Foo = t as *const _; + let r_1 = foo_e as *mut Foo; + + (&*r_1).foo(0)*(&*(bar as *const Foo)).foo(0) +} + +#[repr(C)] +struct FooS(T); +#[repr(C)] +struct BarS(T); + +fn foo_to_bar(u: *const FooS) -> *const BarS { + u as *const BarS +} + +fn main() { + let x = 4u32; + let y : &Foo = &x; + let fl = unsafe { fool(y as *const Foo) }; + 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]); +} diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs new file mode 100644 index 00000000000..92fc2f846ba --- /dev/null +++ b/src/test/run-pass/cast-rfc0401.rs @@ -0,0 +1,169 @@ +// 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 or the MIT license +// , 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 = &mut it; + assert_eq!((itr as &mut Iterator).next(), Some(137)); + assert_eq!((itr as &mut Iterator).next(), None); + + assert_eq!(Some(4u32) as Option, 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); + + // 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() { } diff --git a/src/test/run-pass/supported-cast.rs b/src/test/run-pass/supported-cast.rs index 811b9dce4bc..a47ae52f590 100644 --- a/src/test/run-pass/supported-cast.rs +++ b/src/test/run-pass/supported-cast.rs @@ -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); From d9b9f4ee7de2b5a05547085382a7fc6e196f7c0d Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 13 May 2015 21:58:26 +0300 Subject: [PATCH 4/9] fix conflicts --- src/liballoc/rc.rs | 4 ++-- src/librustc_trans/trans/expr.rs | 9 +++++---- src/librustc_typeck/check/mod.rs | 3 +++ src/test/compile-fail/cast-rfc0401.rs | 3 ++- src/test/compile-fail/fat-ptr-cast.rs | 4 +++- src/test/run-pass/cast-rfc0401.rs | 4 +++- src/test/run-pass/fat-ptr-cast.rs | 6 +++--- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 88c5c38172a..b8d8e6ad0a1 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -543,7 +543,7 @@ impl Drop for Rc { 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 Drop for Weak { 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. diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index a65d4225a1f..e5c9a818183 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -2048,9 +2048,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } else { llsrc }; } - let _icx = push_ctxt("trans_cast"); - let mut bcx = bcx; - let ccx = bcx.ccx(); + 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); @@ -2080,7 +2079,9 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } else { // Return the address return immediate_rvalue_bcx(bcx, - Load(bcx, get_dataptr(bcx, datum.val)), + PointerCast(bcx, + Load(bcx, get_dataptr(bcx, datum.val)), + ll_t_out), t_out).to_expr_datumblock(); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d3cf9ae6dff..d5e3139016f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 3aa866677a8..69ef5421377 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -56,7 +56,8 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR illegal cast let _ = v as *const [u8]; //~ ERROR illegal cast - let _ = fat_v as *const Foo; //~ 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 diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index f6633547a7b..25cab09b7cb 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +trait Trait {} + // Make sure casts between thin-pointer <-> fat pointer obey RFC401 fn main() { let a: &[i32] = &[1, 2, 3]; @@ -17,7 +19,7 @@ fn main() { a as usize; //~ ERROR illegal cast b as usize; //~ ERROR non-scalar cast - p as usize; //~ ERROR illegal cast + p as usize; //~ ERROR illegal cast; cast through a raw pointer // #22955 q as *const [i32]; //~ ERROR illegal cast diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs index 92fc2f846ba..ec4c84a1a6b 100644 --- a/src/test/run-pass/cast-rfc0401.rs +++ b/src/test/run-pass/cast-rfc0401.rs @@ -85,7 +85,9 @@ fn main() 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); + 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]; diff --git a/src/test/run-pass/fat-ptr-cast.rs b/src/test/run-pass/fat-ptr-cast.rs index b7513da99c8..91637d111fe 100644 --- a/src/test/run-pass/fat-ptr-cast.rs +++ b/src/test/run-pass/fat-ptr-cast.rs @@ -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); + } From de4b0e996192d6784e0a65c66d095a6198894c47 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 14 May 2015 01:41:28 +0300 Subject: [PATCH 5/9] remove todo --- src/librustc_typeck/check/cast.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 6ae6d21f987..c3432546b7c 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -338,9 +338,8 @@ impl<'tcx> CastCheck<'tcx> { // To allow unsafe pointers to work correctly, we // need to special-case obtaining an unsafe pointer // from a region pointer to a vector. - // TODO: explain comment. - // this will report a type mismatch if needed + // this will report a type mismatch if needed demand::eqtype(fcx, self.span, ety, m_1.ty); return Ok(CastKind::ArrayPtrCast); } From 32fe2e3ad452128d17ab1ce15f2c77b8cb42a3ea Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 14 May 2015 15:04:49 +0300 Subject: [PATCH 6/9] Address review commets I think I didn't run tests properly - my second call to select_all_obligations_or_error has made 3 tests fail. However, this is just an error message change - integer fallback never worked with casts. --- src/librustc/middle/cast.rs | 20 +++-- src/librustc/middle/check_const.rs | 4 +- src/librustc_trans/trans/consts.rs | 36 ++++---- src/librustc_trans/trans/expr.rs | 10 ++- src/librustc_typeck/check/cast.rs | 88 ++++++++++--------- src/librustc_typeck/check/mod.rs | 30 +++---- .../associated-types-incomplete-object.rs | 8 +- src/test/compile-fail/cast-rfc0401.rs | 4 + .../compile-fail/destructure-trait-ref.rs | 18 ++-- src/test/compile-fail/issue-17458.rs | 2 +- src/test/compile-fail/issue-5153.rs | 2 +- .../compile-fail/kindck-impl-type-params.rs | 1 - .../cast-enum-with-dtor.rs | 0 .../run-pass/cast-rfc0401-vtable-kinds.rs | 3 + 14 files changed, 123 insertions(+), 103 deletions(-) rename src/test/{run-pass => run-pass-valgrind}/cast-enum-with-dtor.rs (100%) diff --git a/src/librustc/middle/cast.rs b/src/librustc/middle/cast.rs index 4b876cfd80f..c534a3ca038 100644 --- a/src/librustc/middle/cast.rs +++ b/src/librustc/middle/cast.rs @@ -15,7 +15,7 @@ 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), @@ -28,10 +28,16 @@ pub enum IntTy { // 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, - FPtr, + /// Function Pointers + FnPtr, + /// Raw pointers Ptr(&'tcx ty::mt<'tcx>), + /// References RPtr(&'tcx ty::mt<'tcx>), } @@ -47,13 +53,13 @@ pub enum CastKind { PrimIntCast, U8CharCast, ArrayPtrCast, - FPtrPtrCast, - FPtrAddrCast + FnPtrPtrCast, + FnPtrAddrCast } impl<'tcx> CastTy<'tcx> { - pub fn recognize(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) - -> Option> { + pub fn from_ty(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) + -> Option> { match t.sty { ty::ty_bool => Some(CastTy::Int(IntTy::Bool)), ty::ty_char => Some(CastTy::Int(IntTy::Char)), @@ -64,7 +70,7 @@ impl<'tcx> CastTy<'tcx> { 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::FPtr), + ty::ty_bare_fn(..) => Some(CastTy::FnPtr), _ => None, } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6d2465a5cb9..794cc4ff38d 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -443,11 +443,11 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, 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::FPtrAddrCast) => { + 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 not cast a pointer to an integer in {}s", v.msg()); + "can't cast a pointer to an integer in {}s", v.msg()); } } _ => {} diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 29430ad10e6..828e4bcc65c 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -617,41 +617,41 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ast::ExprCast(ref base, _) => { - let t_1 = ety; - let llty = type_of::type_of(cx, t_1); - let (v, t_e) = const_expr(cx, &**base, param_substs); - debug!("trans_const_cast({} as {})", t_e.repr(cx.tcx()), t_1.repr(cx.tcx())); - if expr::cast_is_noop(cx.tcx(), base, t_e, t_1) { + 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; } - if type_is_fat_ptr(cx.tcx(), t_e) { + if type_is_fat_ptr(cx.tcx(), t_expr) { // Fat pointer casts. - let t_1_inner = ty::deref(t_1, true).expect("cast to non-pointer").ty; - let ptr_ty = type_of::in_memory_type_of(cx, t_1_inner).ptr_to(); + 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_1) { + 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::recognize(cx.tcx(), t_e).expect("bad input type for cast"), - CastTy::recognize(cx.tcx(), t_1).expect("bad output type for cast")) { + 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_e); + 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_e) as Bool; + let s = ty::type_is_signed(t_expr) as Bool; llvm::LLVMConstIntCast(v, llty.to_ref(), s) } (CastTy::Int(_), CastTy::Float) => { - if ty::type_is_signed(t_e) { + if ty::type_is_signed(t_expr) { llvm::LLVMConstSIToFP(v, llty.to_ref()) } else { llvm::LLVMConstUIToFP(v, llty.to_ref()) @@ -661,18 +661,18 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMConstFPCast(v, llty.to_ref()) } (CastTy::Float, CastTy::Int(_)) => { - if ty::type_is_signed(t_1) { llvm::LLVMConstFPToSI(v, llty.to_ref()) } + if ty::type_is_signed(t_expr) { llvm::LLVMConstFPToSI(v, llty.to_ref()) } else { llvm::LLVMConstFPToUI(v, llty.to_ref()) } } - (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FPtr, CastTy::Ptr(_)) + (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | (CastTy::RPtr(_), CastTy::Ptr(_)) => { ptrcast(v, llty) } - (CastTy::FPtr, CastTy::FPtr) => ptrcast(v, llty), // isn't this a coercion? + (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion? (CastTy::Int(_), CastTy::Ptr(_)) => { llvm::LLVMConstIntToPtr(v, llty.to_ref()) } - (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FPtr, CastTy::Int(_)) => { + (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { llvm::LLVMConstPtrToInt(v, llty.to_ref()) } _ => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index e5c9a818183..90741d1d58f 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -2086,8 +2086,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - let r_t_in = CastTy::recognize(bcx.tcx(), t_in).expect("bad input type for cast"); - let r_t_out = CastTy::recognize(bcx.tcx(), t_out).expect("bad output type for cast"); + 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); @@ -2102,8 +2102,10 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let newval = match (r_t_in, r_t_out) { - (Ptr(_), Ptr(_)) | (FPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => PointerCast(bcx, llexpr, ll_t_out), - (Ptr(_), Int(_)) | (FPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out), + (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => { + PointerCast(bcx, llexpr, ll_t_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), diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index c3432546b7c..5258a77204d 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -56,11 +56,16 @@ 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, - OfTy(Ty<'tcx>) + /// 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 @@ -77,8 +82,9 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(f) => unsize_kind(fcx, f.mt.ty) } } - ty::ty_projection(..) | ty::ty_param(..) => - Some(UnsizeKind::OfTy(t)), + // 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 } } @@ -164,17 +170,17 @@ impl<'tcx> CastCheck<'tcx> { } fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { - let t_1 = self.cast_ty; - let t_e = self.expr_ty; - if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { + 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_e), - fcx.infcx().ty_to_string(t_1))); + 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, @@ -182,8 +188,8 @@ impl<'tcx> CastCheck<'tcx> { 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))); + fcx.infcx().ty_to_string(t_expr), + fcx.infcx().ty_to_string(t_cast))); } } @@ -211,24 +217,24 @@ impl<'tcx> CastCheck<'tcx> { };} } - /// Check a cast, and report an error if one exists. In some cases, - /// this can return Ok and create type errors rather than returning + /// 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 { use middle::cast::IntTy::*; use middle::cast::CastTy::*; - let (t_e, t_1) = match (CastTy::recognize(fcx.tcx(), self.expr_ty), - CastTy::recognize(fcx.tcx(), self.cast_ty)) { - (Some(t_e), Some(t_1)) => (t_e, t_1), + 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), _ => { return Err(CastError::NonScalar) } }; - match (t_e, t_1) { + match (t_from, t_cast) { // These types have invariants! can't cast into them. - (_, RPtr(_)) | (_, Int(CEnum)) | (_, FPtr) => Err(CastError::NonScalar), + (_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar), // * -> Bool (_, Int(Bool)) => Err(CastError::CastToBool), @@ -244,14 +250,14 @@ impl<'tcx> CastCheck<'tcx> { => Err(CastError::NeedViaUsize), // ptr -> * - (Ptr(m1), Ptr(m2)) => self.check_ptr_ptr_cast(fcx, m1, m2), // ptr-ptr-cast - (Ptr(m_e), Int(_)) => self.check_ptr_addr_cast(fcx, m_e), // ptr-addr-cast - (Ptr(_), Float) | (FPtr, Float) => Err(CastError::NeedViaUsize), - (FPtr, Int(_)) => Ok(CastKind::FPtrAddrCast), + (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 - (FPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), + (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 @@ -269,26 +275,26 @@ impl<'tcx> CastCheck<'tcx> { fn check_ptr_ptr_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, - m_e: &'tcx ty::mt<'tcx>, - m_1: &'tcx ty::mt<'tcx>) + m_expr: &'tcx ty::mt<'tcx>, + m_cast: &'tcx ty::mt<'tcx>) -> Result { - debug!("check_ptr_ptr_cast m_e={} m_1={}", - m_e.repr(fcx.tcx()), m_1.repr(fcx.tcx())); + 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_1.ty, self.span) { + 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_e.ty, self.span) { + 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_1.ty), unsize_kind(fcx, m_e.ty)) { + 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) } @@ -296,13 +302,13 @@ impl<'tcx> CastCheck<'tcx> { fn check_fptr_ptr_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, - m_1: &'tcx ty::mt<'tcx>) + m_cast: &'tcx ty::mt<'tcx>) -> Result { // fptr-ptr cast. must be to sized ptr - if fcx.type_is_known_to_be_sized(m_1.ty, self.span) { - Ok(CastKind::FPtrPtrCast) + if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { + Ok(CastKind::FnPtrPtrCast) } else { Err(CastError::IllegalCast) } @@ -310,12 +316,12 @@ impl<'tcx> CastCheck<'tcx> { fn check_ptr_addr_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, - m_e: &'tcx ty::mt<'tcx>) + m_expr: &'tcx ty::mt<'tcx>) -> Result { // ptr-addr cast. must be from sized ptr - if fcx.type_is_known_to_be_sized(m_e.ty, self.span) { + if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) { Ok(CastKind::PtrAddrCast) } else { Err(CastError::NeedViaPtr) @@ -324,14 +330,14 @@ impl<'tcx> CastCheck<'tcx> { fn check_ref_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, - m_e: &'tcx ty::mt<'tcx>, - m_1: &'tcx ty::mt<'tcx>) + m_expr: &'tcx ty::mt<'tcx>, + m_cast: &'tcx ty::mt<'tcx>) -> Result { // array-ptr-cast. - if m_e.mutbl == ast::MutImmutable && m_1.mutbl == ast::MutImmutable { - if let ty::ty_vec(ety, Some(_)) = m_e.ty.sty { + 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. @@ -340,7 +346,7 @@ impl<'tcx> CastCheck<'tcx> { // from a region pointer to a vector. // this will report a type mismatch if needed - demand::eqtype(fcx, self.span, ety, m_1.ty); + demand::eqtype(fcx, self.span, ety, m_cast.ty); return Ok(CastKind::ArrayPtrCast); } } @@ -350,11 +356,11 @@ impl<'tcx> CastCheck<'tcx> { fn check_addr_ptr_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, - m_1: &'tcx ty::mt<'tcx>) + m_cast: &'tcx ty::mt<'tcx>) -> Result { // ptr-addr cast. pointer must be thin. - if fcx.type_is_known_to_be_sized(m_1.ty, self.span) { + if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { Ok(CastKind::AddrPtrCast) } else { Err(CastError::IllegalCast) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d5e3139016f..0e64063d6a4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1115,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, @@ -3404,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); } } diff --git a/src/test/compile-fail/associated-types-incomplete-object.rs b/src/test/compile-fail/associated-types-incomplete-object.rs index 1c708da30a7..c1feb8ac459 100644 --- a/src/test/compile-fail/associated-types-incomplete-object.rs +++ b/src/test/compile-fail/associated-types-incomplete-object.rs @@ -28,15 +28,15 @@ impl Foo for isize { } pub fn main() { - let a = &42 as &Foo; + let a = &42isize as &Foo; - let b = &42 as &Foo; + let b = &42isize as &Foo; //~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified - let c = &42 as &Foo; + let c = &42isize as &Foo; //~^ 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 } diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index 69ef5421377..f3537e54135 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -65,6 +65,10 @@ fn main() 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 diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 3f455e148a0..08db643df00 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -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; //~ 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; //~ 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; + let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected `T` //~| found `Box<_>` diff --git a/src/test/compile-fail/issue-17458.rs b/src/test/compile-fail/issue-17458.rs index d6f70ae1e57..a3a9e17cb3c 100644 --- a/src/test/compile-fail/issue-17458.rs +++ b/src/test/compile-fail/issue-17458.rs @@ -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); diff --git a/src/test/compile-fail/issue-5153.rs b/src/test/compile-fail/issue-5153.rs index da32408e199..b1d96f9b527 100644 --- a/src/test/compile-fail/issue-5153.rs +++ b/src/test/compile-fail/issue-5153.rs @@ -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 } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index d4ee93e9ca5..988a7837b59 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -28,7 +28,6 @@ fn f(val: T) { let a = &t as &Gettable; //~^ 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(val: T) { diff --git a/src/test/run-pass/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs similarity index 100% rename from src/test/run-pass/cast-enum-with-dtor.rs rename to src/test/run-pass-valgrind/cast-enum-with-dtor.rs diff --git a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs index 76516a69f79..e53d4af8e36 100644 --- a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs @@ -8,6 +8,9 @@ // 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 { fn foo(&self, _: T) -> u32 { 42 } } From 27d2bd13c357bed328735da8605fce1416acc060 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 15 May 2015 11:44:26 +0300 Subject: [PATCH 7/9] Make float -> int casts actually work --- src/librustc_trans/trans/consts.rs | 6 ++++-- src/test/run-pass/cast-rfc0401.rs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 828e4bcc65c..5ca14b63bce 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -660,9 +660,11 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, (CastTy::Float, CastTy::Float) => { llvm::LLVMConstFPCast(v, llty.to_ref()) } + (CastTy::Float, CastTy::Int(IntTy::I)) => { + llvm::LLVMConstFPToSI(v, llty.to_ref()) + } (CastTy::Float, CastTy::Int(_)) => { - if ty::type_is_signed(t_expr) { llvm::LLVMConstFPToSI(v, llty.to_ref()) } - else { llvm::LLVMConstFPToUI(v, llty.to_ref()) } + llvm::LLVMConstFPToUI(v, llty.to_ref()) } (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | (CastTy::RPtr(_), CastTy::Ptr(_)) => { diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs index ec4c84a1a6b..7c64c34fae5 100644 --- a/src/test/run-pass/cast-rfc0401.rs +++ b/src/test/run-pass/cast-rfc0401.rs @@ -75,7 +75,6 @@ fn main() 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); From 3afd760bb3fc8c90adfd9451e1cd8b161301f218 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 19 May 2015 17:38:55 +0300 Subject: [PATCH 8/9] Fix translation of semi-constant if-statements Thanks @dotdash --- src/librustc_trans/trans/base.rs | 3 +-- src/librustc_trans/trans/common.rs | 6 ----- src/librustc_trans/trans/controlflow.rs | 31 ++++++++++--------------- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 4879975dde6..06841501124 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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; } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 03dda57e568..758702f54c0 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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) diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 8cecc39ec39..ab8cfa0ce3b 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -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); } } From e7e1fd20deb95f74c4a33c76921907e039dff894 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 19 May 2015 22:54:44 +0300 Subject: [PATCH 9/9] Fix rebase conflicts --- src/liballoc/arc.rs | 8 ++++++-- src/librustc_lint/builtin.rs | 2 +- src/librustc_trans/trans/expr.rs | 5 +++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index ff942444a61..97e85b114b0 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -394,7 +394,9 @@ impl Drop for Arc { // 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 Drop for Weak { 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 diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8d555240e70..3716ee395bf 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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)); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 90741d1d58f..33eb3814087 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -2048,8 +2048,9 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } else { llsrc }; } - let _icx = push_ctxt("trans_cast"); let mut bcx = bcx; let ccx = - bcx.ccx(); + 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);