mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #24333 - arielb1:implement-rfc401, r=nrc
This commit is contained in:
commit
c322dbbf8a
@ -394,7 +394,9 @@ impl<T: ?Sized> Drop for Arc<T> {
|
||||
// it's run more than once)
|
||||
let ptr = *self._ptr;
|
||||
// if ptr.is_null() { return }
|
||||
if ptr as usize == 0 || ptr as usize == mem::POST_DROP_USIZE { return }
|
||||
if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
|
||||
return
|
||||
}
|
||||
|
||||
// Because `fetch_sub` is already atomic, we do not need to synchronize
|
||||
// with other threads unless we are going to delete the object. This
|
||||
@ -524,7 +526,9 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
let ptr = *self._ptr;
|
||||
|
||||
// see comments above for why this check is here
|
||||
if ptr as usize == 0 || ptr as usize == mem::POST_DROP_USIZE { return }
|
||||
if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
|
||||
return
|
||||
}
|
||||
|
||||
// If we find out that we were the last weak pointer, then its time to
|
||||
// deallocate the data entirely. See the discussion in Arc::drop() about
|
||||
|
@ -543,7 +543,7 @@ impl<T: ?Sized> Drop for Rc<T> {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
ptr as *const () as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_strong();
|
||||
if self.strong() == 0 {
|
||||
// destroy the contained object
|
||||
@ -1051,7 +1051,7 @@ impl<T: ?Sized> Drop for Weak<T> {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
ptr as *const () as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_weak();
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
|
@ -801,7 +801,6 @@ struct Foo<T: 'static> {
|
||||
|
||||
register_diagnostics! {
|
||||
E0011,
|
||||
E0012,
|
||||
E0014,
|
||||
E0016,
|
||||
E0017,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ use metadata::tydecode;
|
||||
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
|
||||
use metadata::tydecode::{RegionParameter, ClosureSource};
|
||||
use metadata::tyencode;
|
||||
use middle::cast;
|
||||
use middle::check_const::ConstQualif;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::privacy::{AllPublic, LastMod};
|
||||
@ -688,6 +689,10 @@ pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
|
||||
kind.encode(ebml_w).unwrap();
|
||||
}
|
||||
|
||||
pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
|
||||
kind.encode(ebml_w).unwrap();
|
||||
}
|
||||
|
||||
pub trait vtable_decoder_helpers<'tcx> {
|
||||
fn read_vec_per_param_space<T, F>(&mut self, f: F) -> VecPerParamSpace<T> where
|
||||
F: FnMut(&mut Self) -> T;
|
||||
@ -1248,6 +1253,13 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
})
|
||||
}
|
||||
|
||||
if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
|
||||
rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
encode_cast_kind(rbml_w, *cast_kind)
|
||||
})
|
||||
}
|
||||
|
||||
for &qualif in tcx.const_qualif_map.borrow().get(&id).iter() {
|
||||
rbml_w.tag(c::tag_table_const_qualif, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
@ -1289,6 +1301,8 @@ trait rbml_decoder_decoder_helpers<'tcx> {
|
||||
-> subst::Substs<'tcx>;
|
||||
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::AutoAdjustment<'tcx>;
|
||||
fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> cast::CastKind;
|
||||
fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::ClosureKind;
|
||||
fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
@ -1641,6 +1655,12 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> cast::CastKind
|
||||
{
|
||||
Decodable::decode(self).unwrap()
|
||||
}
|
||||
|
||||
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::ClosureKind
|
||||
{
|
||||
@ -1801,6 +1821,11 @@ fn decode_side_tables(dcx: &DecodeContext,
|
||||
dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id),
|
||||
closure_kind);
|
||||
}
|
||||
c::tag_table_cast_kinds => {
|
||||
let cast_kind =
|
||||
val_dsr.read_cast_kind(dcx);
|
||||
dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind);
|
||||
}
|
||||
c::tag_table_const_qualif => {
|
||||
let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap();
|
||||
dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif);
|
||||
|
77
src/librustc/middle/cast.rs
Normal file
77
src/librustc/middle/cast.rs
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Helpers for handling cast expressions, used in both
|
||||
// typeck and trans.
|
||||
|
||||
use middle::ty::{self, Ty};
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
/// Types that are represented as ints.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum IntTy {
|
||||
U(ast::UintTy),
|
||||
I,
|
||||
CEnum,
|
||||
Bool,
|
||||
Char
|
||||
}
|
||||
|
||||
// Valid types for the result of a non-coercion cast
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CastTy<'tcx> {
|
||||
/// Various types that are represented as ints and handled mostly
|
||||
/// in the same way, merged for easier matching.
|
||||
Int(IntTy),
|
||||
/// Floating-Point types
|
||||
Float,
|
||||
/// Function Pointers
|
||||
FnPtr,
|
||||
/// Raw pointers
|
||||
Ptr(&'tcx ty::mt<'tcx>),
|
||||
/// References
|
||||
RPtr(&'tcx ty::mt<'tcx>),
|
||||
}
|
||||
|
||||
/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum CastKind {
|
||||
CoercionCast,
|
||||
PtrPtrCast,
|
||||
PtrAddrCast,
|
||||
AddrPtrCast,
|
||||
NumericCast,
|
||||
EnumCast,
|
||||
PrimIntCast,
|
||||
U8CharCast,
|
||||
ArrayPtrCast,
|
||||
FnPtrPtrCast,
|
||||
FnPtrAddrCast
|
||||
}
|
||||
|
||||
impl<'tcx> CastTy<'tcx> {
|
||||
pub fn from_ty(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>)
|
||||
-> Option<CastTy<'tcx>> {
|
||||
match t.sty {
|
||||
ty::ty_bool => Some(CastTy::Int(IntTy::Bool)),
|
||||
ty::ty_char => Some(CastTy::Int(IntTy::Char)),
|
||||
ty::ty_int(_) => Some(CastTy::Int(IntTy::I)),
|
||||
ty::ty_uint(u) => Some(CastTy::Int(IntTy::U(u))),
|
||||
ty::ty_float(_) => Some(CastTy::Float),
|
||||
ty::ty_enum(..) if ty::type_is_c_like_enum(
|
||||
tcx, t) => Some(CastTy::Int(IntTy::CEnum)),
|
||||
ty::ty_ptr(ref mt) => Some(CastTy::Ptr(mt)),
|
||||
ty::ty_rptr(_, ref mt) => Some(CastTy::RPtr(mt)),
|
||||
ty::ty_bare_fn(..) => Some(CastTy::FnPtr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
|
||||
// by borrowck::gather_loans
|
||||
|
||||
use middle::cast::{CastKind};
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::expr_use_visitor as euv;
|
||||
@ -32,11 +33,10 @@ use middle::mem_categorization as mc;
|
||||
use middle::traits;
|
||||
use middle::ty::{self, Ty};
|
||||
use util::nodemap::NodeMap;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::print::pprust;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -197,7 +197,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, i: &ast::Item) {
|
||||
debug!("visit_item(item={})", pprust::item_to_string(i));
|
||||
debug!("visit_item(item={})", i.repr(self.tcx));
|
||||
match i.node {
|
||||
ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
|
||||
self.check_static_type(&**expr);
|
||||
@ -440,26 +440,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
ast::ExprCast(ref from, _) => {
|
||||
let toty = ty::expr_ty(v.tcx, e);
|
||||
let fromty = ty::expr_ty(v.tcx, &**from);
|
||||
let is_legal_cast =
|
||||
ty::type_is_numeric(toty) ||
|
||||
ty::type_is_unsafe_ptr(toty) ||
|
||||
(ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
|
||||
if !is_legal_cast {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0012,
|
||||
"can not cast to `{}` in {}s",
|
||||
ppaux::ty_to_string(v.tcx, toty), v.msg());
|
||||
}
|
||||
}
|
||||
if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0018,
|
||||
"can not cast a pointer to an integer in {}s", v.msg());
|
||||
debug!("Checking const cast(id={})", from.id);
|
||||
match v.tcx.cast_kinds.borrow().get(&from.id) {
|
||||
None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
|
||||
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0018,
|
||||
"can't cast a pointer to an integer in {}s", v.msg());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ast::ExprPath(..) => {
|
||||
|
@ -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)),
|
||||
|
@ -41,6 +41,7 @@ use session::Session;
|
||||
use lint;
|
||||
use metadata::csearch;
|
||||
use middle;
|
||||
use middle::cast;
|
||||
use middle::check_const;
|
||||
use middle::const_eval;
|
||||
use middle::def::{self, DefMap, ExportMap};
|
||||
@ -288,15 +289,6 @@ pub struct field_ty {
|
||||
pub origin: ast::DefId, // The DefId of the struct in which the field is declared.
|
||||
}
|
||||
|
||||
// Contains information needed to resolve types and (in the future) look up
|
||||
// the types of AST nodes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct creader_cache_key {
|
||||
pub cnum: CrateNum,
|
||||
pub pos: usize,
|
||||
pub len: usize
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
|
||||
pub struct ItemVariances {
|
||||
pub types: VecPerParamSpace<Variance>,
|
||||
@ -562,6 +554,15 @@ pub enum vtable_origin<'tcx> {
|
||||
// expr to the associated trait ref.
|
||||
pub type ObjectCastMap<'tcx> = RefCell<NodeMap<ty::PolyTraitRef<'tcx>>>;
|
||||
|
||||
// Contains information needed to resolve types and (in the future) look up
|
||||
// the types of AST nodes.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct creader_cache_key {
|
||||
pub cnum: CrateNum,
|
||||
pub pos: usize,
|
||||
pub len: usize
|
||||
}
|
||||
|
||||
/// A restriction that certain types must be the same size. The use of
|
||||
/// `transmute` gives rise to these restrictions. These generally
|
||||
/// cannot be checked until trans; therefore, each call to `transmute`
|
||||
@ -827,6 +828,10 @@ pub struct ctxt<'tcx> {
|
||||
|
||||
/// Caches CoerceUnsized kinds for impls on custom types.
|
||||
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
|
||||
|
||||
/// Maps a cast expression to its kind. This is keyed on the
|
||||
/// *from* expression of the cast, not the cast itself.
|
||||
pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ctxt<'tcx> {
|
||||
@ -2817,6 +2822,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
||||
type_impls_sized_cache: RefCell::new(HashMap::new()),
|
||||
const_qualif_map: RefCell::new(NodeMap()),
|
||||
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
||||
cast_kinds: RefCell::new(NodeMap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -795,43 +795,40 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
|
||||
match *r {
|
||||
CEnum(ity, _, _) => ity.is_signed(),
|
||||
General(ity, _, _) => ity.is_signed(),
|
||||
Univariant(..) => false,
|
||||
RawNullablePointer { .. } => false,
|
||||
StructWrappedNullablePointer { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the actual discriminant of a value.
|
||||
pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
|
||||
scrutinee: ValueRef, cast_to: Option<Type>)
|
||||
-> ValueRef {
|
||||
let signed;
|
||||
let val;
|
||||
debug!("trans_get_discr r: {:?}", r);
|
||||
match *r {
|
||||
CEnum(ity, min, max) => {
|
||||
val = load_discr(bcx, ity, scrutinee, min, max);
|
||||
signed = ity.is_signed();
|
||||
}
|
||||
let val = match *r {
|
||||
CEnum(ity, min, max) => load_discr(bcx, ity, scrutinee, min, max),
|
||||
General(ity, ref cases, _) => {
|
||||
let ptr = GEPi(bcx, scrutinee, &[0, 0]);
|
||||
val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
|
||||
signed = ity.is_signed();
|
||||
}
|
||||
Univariant(..) => {
|
||||
val = C_u8(bcx.ccx(), 0);
|
||||
signed = false;
|
||||
load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr)
|
||||
}
|
||||
Univariant(..) => C_u8(bcx.ccx(), 0),
|
||||
RawNullablePointer { nndiscr, nnty, .. } => {
|
||||
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
|
||||
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
|
||||
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None);
|
||||
signed = false;
|
||||
ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None)
|
||||
}
|
||||
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
||||
val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
|
||||
signed = false;
|
||||
struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
|
||||
}
|
||||
}
|
||||
};
|
||||
match cast_to {
|
||||
None => val,
|
||||
Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
|
||||
Some(llty) => if is_discr_signed(r) { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -29,6 +29,7 @@ use trans::declare;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::cast::{CastTy,IntTy};
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty};
|
||||
use util::ppaux::{Repr, ty_to_string};
|
||||
@ -616,53 +617,64 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
ast::ExprCast(ref base, _) => {
|
||||
let llty = type_of::type_of(cx, ety);
|
||||
let (v, basety) = const_expr(cx, &**base, param_substs);
|
||||
if expr::cast_is_noop(basety, ety) {
|
||||
let t_cast = ety;
|
||||
let llty = type_of::type_of(cx, t_cast);
|
||||
let (v, t_expr) = const_expr(cx, &**base, param_substs);
|
||||
debug!("trans_const_cast({} as {})", t_expr.repr(cx.tcx()), t_cast.repr(cx.tcx()));
|
||||
if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
|
||||
return v;
|
||||
}
|
||||
match (expr::cast_type_kind(cx.tcx(), basety),
|
||||
expr::cast_type_kind(cx.tcx(), ety)) {
|
||||
|
||||
(expr::cast_integral, expr::cast_integral) => {
|
||||
let s = ty::type_is_signed(basety) as Bool;
|
||||
if type_is_fat_ptr(cx.tcx(), t_expr) {
|
||||
// Fat pointer casts.
|
||||
let t_cast_inner = ty::deref(t_cast, true).expect("cast to non-pointer").ty;
|
||||
let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
|
||||
let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]),
|
||||
ptr_ty);
|
||||
if type_is_fat_ptr(cx.tcx(), t_cast) {
|
||||
let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
|
||||
return C_struct(cx, &[addr, info], false)
|
||||
} else {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
match (CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"),
|
||||
CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast")) {
|
||||
(CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
|
||||
let repr = adt::represent_type(cx, t_expr);
|
||||
let discr = adt::const_get_discrim(cx, &*repr, v);
|
||||
let iv = C_integral(cx.int_type(), discr, false);
|
||||
let s = adt::is_discr_signed(&*repr) as Bool;
|
||||
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
|
||||
}
|
||||
(CastTy::Int(_), CastTy::Int(_)) => {
|
||||
let s = ty::type_is_signed(t_expr) as Bool;
|
||||
llvm::LLVMConstIntCast(v, llty.to_ref(), s)
|
||||
}
|
||||
(expr::cast_integral, expr::cast_float) => {
|
||||
if ty::type_is_signed(basety) {
|
||||
(CastTy::Int(_), CastTy::Float) => {
|
||||
if ty::type_is_signed(t_expr) {
|
||||
llvm::LLVMConstSIToFP(v, llty.to_ref())
|
||||
} else {
|
||||
llvm::LLVMConstUIToFP(v, llty.to_ref())
|
||||
}
|
||||
}
|
||||
(expr::cast_float, expr::cast_float) => {
|
||||
(CastTy::Float, CastTy::Float) => {
|
||||
llvm::LLVMConstFPCast(v, llty.to_ref())
|
||||
}
|
||||
(expr::cast_float, expr::cast_integral) => {
|
||||
if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
|
||||
else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
|
||||
(CastTy::Float, CastTy::Int(IntTy::I)) => {
|
||||
llvm::LLVMConstFPToSI(v, llty.to_ref())
|
||||
}
|
||||
(expr::cast_enum, expr::cast_integral) => {
|
||||
let repr = adt::represent_type(cx, basety);
|
||||
let discr = adt::const_get_discrim(cx, &*repr, v);
|
||||
let iv = C_integral(cx.int_type(), discr, false);
|
||||
let ety_cast = expr::cast_type_kind(cx.tcx(), ety);
|
||||
match ety_cast {
|
||||
expr::cast_integral => {
|
||||
let s = ty::type_is_signed(ety) as Bool;
|
||||
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
|
||||
}
|
||||
_ => cx.sess().bug("enum cast destination is not \
|
||||
integral")
|
||||
}
|
||||
(CastTy::Float, CastTy::Int(_)) => {
|
||||
llvm::LLVMConstFPToUI(v, llty.to_ref())
|
||||
}
|
||||
(expr::cast_pointer, expr::cast_pointer) => {
|
||||
(CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
|
||||
| (CastTy::RPtr(_), CastTy::Ptr(_)) => {
|
||||
ptrcast(v, llty)
|
||||
}
|
||||
(expr::cast_integral, expr::cast_pointer) => {
|
||||
(CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
|
||||
(CastTy::Int(_), CastTy::Ptr(_)) => {
|
||||
llvm::LLVMConstIntToPtr(v, llty.to_ref())
|
||||
}
|
||||
(expr::cast_pointer, expr::cast_integral) => {
|
||||
(CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
|
||||
llvm::LLVMConstPtrToInt(v, llty.to_ref())
|
||||
}
|
||||
_ => {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub use self::cast_kind::*;
|
||||
pub use self::Dest::*;
|
||||
use self::lazy_binop_ty::*;
|
||||
|
||||
@ -73,6 +72,7 @@ use trans::meth;
|
||||
use trans::monomorphize;
|
||||
use trans::tvec;
|
||||
use trans::type_of;
|
||||
use middle::cast::{CastKind, CastTy};
|
||||
use middle::ty::{struct_fields, tup_fields};
|
||||
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
|
||||
use middle::ty::{self, Ty};
|
||||
@ -1981,177 +1981,147 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
bcx
|
||||
}
|
||||
|
||||
fn int_cast(bcx: Block,
|
||||
lldsttype: Type,
|
||||
llsrctype: Type,
|
||||
llsrc: ValueRef,
|
||||
signed: bool)
|
||||
-> ValueRef {
|
||||
let _icx = push_ctxt("int_cast");
|
||||
let srcsz = llsrctype.int_width();
|
||||
let dstsz = lldsttype.int_width();
|
||||
return if dstsz == srcsz {
|
||||
BitCast(bcx, llsrc, lldsttype)
|
||||
} else if srcsz > dstsz {
|
||||
TruncOrBitCast(bcx, llsrc, lldsttype)
|
||||
} else if signed {
|
||||
SExtOrBitCast(bcx, llsrc, lldsttype)
|
||||
} else {
|
||||
ZExtOrBitCast(bcx, llsrc, lldsttype)
|
||||
pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
expr: &ast::Expr,
|
||||
t_in: Ty<'tcx>,
|
||||
t_out: Ty<'tcx>)
|
||||
-> bool {
|
||||
if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn float_cast(bcx: Block,
|
||||
lldsttype: Type,
|
||||
llsrctype: Type,
|
||||
llsrc: ValueRef)
|
||||
-> ValueRef {
|
||||
let _icx = push_ctxt("float_cast");
|
||||
let srcsz = llsrctype.float_width();
|
||||
let dstsz = lldsttype.float_width();
|
||||
return if dstsz > srcsz {
|
||||
FPExt(bcx, llsrc, lldsttype)
|
||||
} else if srcsz > dstsz {
|
||||
FPTrunc(bcx, llsrc, lldsttype)
|
||||
} else { llsrc };
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum cast_kind {
|
||||
cast_pointer,
|
||||
cast_fat_ptr,
|
||||
cast_integral,
|
||||
cast_float,
|
||||
cast_enum,
|
||||
cast_other,
|
||||
}
|
||||
|
||||
pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
|
||||
match t.sty {
|
||||
ty::ty_char => cast_integral,
|
||||
ty::ty_float(..) => cast_float,
|
||||
ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
|
||||
if type_is_sized(tcx, mt.ty) {
|
||||
cast_pointer
|
||||
} else {
|
||||
cast_fat_ptr
|
||||
}
|
||||
}
|
||||
ty::ty_bare_fn(..) => cast_pointer,
|
||||
ty::ty_int(..) => cast_integral,
|
||||
ty::ty_uint(..) => cast_integral,
|
||||
ty::ty_bool => cast_integral,
|
||||
ty::ty_enum(..) => cast_enum,
|
||||
_ => cast_other
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool {
|
||||
match (ty::deref(t_in, true), ty::deref(t_out, true)) {
|
||||
(Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
|
||||
t_in == t_out
|
||||
}
|
||||
_ => false
|
||||
_ => {
|
||||
// This condition isn't redundant with the check for CoercionCast:
|
||||
// different types can be substituted into the same type, and
|
||||
// == equality can be overconservative if there are regions.
|
||||
t_in == t_out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
expr: &ast::Expr,
|
||||
id: ast::NodeId)
|
||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
-> DatumBlock<'blk, 'tcx, Expr>
|
||||
{
|
||||
use middle::cast::CastTy::*;
|
||||
use middle::cast::IntTy::*;
|
||||
|
||||
fn int_cast(bcx: Block,
|
||||
lldsttype: Type,
|
||||
llsrctype: Type,
|
||||
llsrc: ValueRef,
|
||||
signed: bool)
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("int_cast");
|
||||
let srcsz = llsrctype.int_width();
|
||||
let dstsz = lldsttype.int_width();
|
||||
return if dstsz == srcsz {
|
||||
BitCast(bcx, llsrc, lldsttype)
|
||||
} else if srcsz > dstsz {
|
||||
TruncOrBitCast(bcx, llsrc, lldsttype)
|
||||
} else if signed {
|
||||
SExtOrBitCast(bcx, llsrc, lldsttype)
|
||||
} else {
|
||||
ZExtOrBitCast(bcx, llsrc, lldsttype)
|
||||
}
|
||||
}
|
||||
|
||||
fn float_cast(bcx: Block,
|
||||
lldsttype: Type,
|
||||
llsrctype: Type,
|
||||
llsrc: ValueRef)
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("float_cast");
|
||||
let srcsz = llsrctype.float_width();
|
||||
let dstsz = lldsttype.float_width();
|
||||
return if dstsz > srcsz {
|
||||
FPExt(bcx, llsrc, lldsttype)
|
||||
} else if srcsz > dstsz {
|
||||
FPTrunc(bcx, llsrc, lldsttype)
|
||||
} else { llsrc };
|
||||
}
|
||||
|
||||
let _icx = push_ctxt("trans_cast");
|
||||
let mut bcx = bcx;
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
let t_in = expr_ty_adjusted(bcx, expr);
|
||||
let t_out = node_id_type(bcx, id);
|
||||
let k_in = cast_type_kind(bcx.tcx(), t_in);
|
||||
let k_out = cast_type_kind(bcx.tcx(), t_out);
|
||||
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
|
||||
let ll_t_in = type_of::arg_type_of(ccx, t_in);
|
||||
let ll_t_out = type_of::arg_type_of(ccx, t_out);
|
||||
|
||||
debug!("trans_cast({} as {})", t_in.repr(bcx.tcx()), t_out.repr(bcx.tcx()));
|
||||
let mut ll_t_in = type_of::arg_type_of(ccx, t_in);
|
||||
let ll_t_out = type_of::arg_type_of(ccx, t_out);
|
||||
// Convert the value to be cast into a ValueRef, either by-ref or
|
||||
// by-value as appropriate given its type:
|
||||
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
|
||||
|
||||
let datum_ty = monomorphize_type(bcx, datum.ty);
|
||||
if cast_is_noop(datum_ty, t_out) {
|
||||
|
||||
if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
|
||||
datum.ty = t_out;
|
||||
return DatumBlock::new(bcx, datum);
|
||||
}
|
||||
|
||||
let newval = match (k_in, k_out) {
|
||||
(cast_integral, cast_integral) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
|
||||
if type_is_fat_ptr(bcx.tcx(), t_in) {
|
||||
assert!(datum.kind.is_by_ref());
|
||||
if type_is_fat_ptr(bcx.tcx(), t_out) {
|
||||
return DatumBlock::new(bcx, Datum::new(
|
||||
PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
|
||||
t_out,
|
||||
Rvalue::new(ByRef)
|
||||
)).to_expr_datumblock();
|
||||
} else {
|
||||
// Return the address
|
||||
return immediate_rvalue_bcx(bcx,
|
||||
PointerCast(bcx,
|
||||
Load(bcx, get_dataptr(bcx, datum.val)),
|
||||
ll_t_out),
|
||||
t_out).to_expr_datumblock();
|
||||
}
|
||||
(cast_float, cast_float) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
float_cast(bcx, ll_t_out, ll_t_in, llexpr)
|
||||
}
|
||||
(cast_integral, cast_float) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
if s_in {
|
||||
SIToFP(bcx, llexpr, ll_t_out)
|
||||
} else { UIToFP(bcx, llexpr, ll_t_out) }
|
||||
}
|
||||
(cast_float, cast_integral) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
if ty::type_is_signed(t_out) {
|
||||
FPToSI(bcx, llexpr, ll_t_out)
|
||||
} else { FPToUI(bcx, llexpr, ll_t_out) }
|
||||
}
|
||||
(cast_integral, cast_pointer) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
IntToPtr(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(cast_pointer, cast_integral) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
PtrToInt(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(cast_fat_ptr, cast_integral) => {
|
||||
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||
PtrToInt(bcx, data_ptr, ll_t_out)
|
||||
}
|
||||
(cast_pointer, cast_pointer) => {
|
||||
let llexpr = datum.to_llscalarish(bcx);
|
||||
}
|
||||
|
||||
let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast");
|
||||
let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast");
|
||||
|
||||
let (llexpr, signed) = if let Int(CEnum) = r_t_in {
|
||||
let repr = adt::represent_type(ccx, t_in);
|
||||
let datum = unpack_datum!(
|
||||
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
|
||||
let llexpr_ptr = datum.to_llref();
|
||||
let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
|
||||
ll_t_in = val_ty(discr);
|
||||
(discr, adt::is_discr_signed(&*repr))
|
||||
} else {
|
||||
(datum.to_llscalarish(bcx), ty::type_is_signed(t_in))
|
||||
};
|
||||
|
||||
let newval = match (r_t_in, r_t_out) {
|
||||
(Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
|
||||
PointerCast(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(cast_fat_ptr, cast_pointer) => {
|
||||
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
|
||||
PointerCast(bcx, data_ptr, ll_t_out)
|
||||
}
|
||||
(cast_enum, cast_integral) |
|
||||
(cast_enum, cast_float) => {
|
||||
let mut bcx = bcx;
|
||||
let repr = adt::represent_type(ccx, t_in);
|
||||
let datum = unpack_datum!(
|
||||
bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
|
||||
let llexpr_ptr = datum.to_llref();
|
||||
let lldiscrim_a =
|
||||
adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
|
||||
match k_out {
|
||||
cast_integral => int_cast(bcx, ll_t_out,
|
||||
val_ty(lldiscrim_a),
|
||||
lldiscrim_a, true),
|
||||
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
|
||||
_ => {
|
||||
ccx.sess().bug(&format!("translating unsupported cast: \
|
||||
{} ({:?}) -> {} ({:?})",
|
||||
t_in.repr(bcx.tcx()),
|
||||
k_in,
|
||||
t_out.repr(bcx.tcx()),
|
||||
k_out))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ccx.sess().bug(&format!("translating unsupported cast: \
|
||||
{} ({:?}) -> {} ({:?})",
|
||||
t_in.repr(bcx.tcx()),
|
||||
k_in,
|
||||
t_out.repr(bcx.tcx()),
|
||||
k_out))
|
||||
(Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
|
||||
(Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
|
||||
|
||||
(Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
|
||||
(Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
|
||||
(Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
|
||||
(Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
|
||||
(Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
|
||||
(Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),
|
||||
|
||||
_ => ccx.sess().span_bug(expr.span,
|
||||
&format!("translating unsupported cast: \
|
||||
{} -> {}",
|
||||
t_in.repr(bcx.tcx()),
|
||||
t_out.repr(bcx.tcx()))
|
||||
)
|
||||
};
|
||||
return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
|
||||
}
|
||||
|
@ -9,6 +9,29 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Code for type-checking cast expressions.
|
||||
//!
|
||||
//! A cast `e as U` is valid if one of the following holds:
|
||||
//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
|
||||
//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
|
||||
//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
|
||||
//! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
|
||||
//! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
|
||||
//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
|
||||
//! * `e` is a C-like enum and `U` is an integer type; *enum-cast*
|
||||
//! * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
|
||||
//! * `e` has type `u8` and `U` is `char`; *u8-char-cast*
|
||||
//! * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
|
||||
//! * `e` is a function pointer type and `U` has type `*T`,
|
||||
//! while `T: Sized`; *fptr-ptr-cast*
|
||||
//! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
|
||||
//!
|
||||
//! where `&.T` and `*T` are references of either mutability,
|
||||
//! and where unsize_kind(`T`) is the kind of the unsize info
|
||||
//! in `T` - a vtable or a length (or `()` if `T: Sized`).
|
||||
//!
|
||||
//! Casting is not transitive, that is, even if `e as U1 as U2` is a valid
|
||||
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
|
||||
//! `U1` coerces to `U2`).
|
||||
|
||||
use super::coercion;
|
||||
use super::demand;
|
||||
@ -16,11 +39,13 @@ use super::FnCtxt;
|
||||
use super::structurally_resolved_type;
|
||||
|
||||
use lint;
|
||||
use middle::infer;
|
||||
use middle::cast::{CastKind, CastTy};
|
||||
use middle::ty;
|
||||
use middle::ty::Ty;
|
||||
use syntax::ast;
|
||||
use syntax::ast::UintTy::{TyU8};
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
/// Reifies a cast check to be checked once we have full type information for
|
||||
/// a function context.
|
||||
@ -31,6 +56,52 @@ pub struct CastCheck<'tcx> {
|
||||
span: Span,
|
||||
}
|
||||
|
||||
/// The kind of the unsize info (length or vtable) - we only allow casts between
|
||||
/// fat pointers if their unsize-infos have the same kind.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
enum UnsizeKind<'tcx> {
|
||||
Vtable,
|
||||
Length,
|
||||
/// The unsize info of this projection
|
||||
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
|
||||
/// The unsize info of this parameter
|
||||
OfParam(&'tcx ty::ParamTy)
|
||||
}
|
||||
|
||||
/// Returns the kind of unsize information of t, or None
|
||||
/// if t is sized or it is unknown.
|
||||
fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
t: Ty<'tcx>)
|
||||
-> Option<UnsizeKind<'tcx>> {
|
||||
match t.sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => Some(UnsizeKind::Length),
|
||||
ty::ty_trait(_) => Some(UnsizeKind::Vtable),
|
||||
ty::ty_struct(did, substs) => {
|
||||
match ty::struct_fields(fcx.tcx(), did, substs).pop() {
|
||||
None => None,
|
||||
Some(f) => unsize_kind(fcx, f.mt.ty)
|
||||
}
|
||||
}
|
||||
// We should really try to normalize here.
|
||||
ty::ty_projection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
|
||||
ty::ty_param(ref p) => Some(UnsizeKind::OfParam(p)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum CastError {
|
||||
CastToBool,
|
||||
CastToChar,
|
||||
DifferingKinds,
|
||||
IllegalCast,
|
||||
NeedViaPtr,
|
||||
NeedViaInt,
|
||||
NeedViaUsize,
|
||||
NonScalar,
|
||||
RefToMutPtr
|
||||
}
|
||||
|
||||
impl<'tcx> CastCheck<'tcx> {
|
||||
pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
|
||||
-> CastCheck<'tcx> {
|
||||
@ -41,155 +112,270 @@ impl<'tcx> CastCheck<'tcx> {
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
t_1: Ty<'tcx>,
|
||||
t_e: Ty<'tcx>) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("illegal cast; cast through an \
|
||||
integer first: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
}
|
||||
|
||||
let span = cast.span;
|
||||
let e = &cast.expr;
|
||||
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
|
||||
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
// Check for trivial casts.
|
||||
if !ty::type_has_ty_infer(t_1) {
|
||||
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
|
||||
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
|
||||
tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
} else {
|
||||
tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>,
|
||||
e: CastError) {
|
||||
match e {
|
||||
CastError::NeedViaPtr |
|
||||
CastError::NeedViaInt |
|
||||
CastError::NeedViaUsize => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
format!("illegal cast; cast through {} first: `{}` as `{}`",
|
||||
match e {
|
||||
CastError::NeedViaPtr => "a raw pointer",
|
||||
CastError::NeedViaInt => "an integer",
|
||||
CastError::NeedViaUsize => "a usize",
|
||||
_ => unreachable!()
|
||||
},
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None)
|
||||
}
|
||||
CastError::CastToBool => {
|
||||
span_err!(fcx.tcx().sess, self.span, E0054,
|
||||
"cannot cast as `bool`, compare with zero instead");
|
||||
}
|
||||
CastError::CastToChar => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
format!("only `u8` can be cast as `char`, not `{}`", actual)
|
||||
}, self.expr_ty, None);
|
||||
}
|
||||
CastError::NonScalar => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
format!("non-scalar cast: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None);
|
||||
}
|
||||
CastError::IllegalCast => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
format!("illegal cast: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None);
|
||||
}
|
||||
CastError::DifferingKinds => {
|
||||
fcx.type_error_message(self.span, |actual| {
|
||||
format!("illegal cast: `{}` as `{}`; vtable kinds may not match",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(self.cast_ty))
|
||||
}, self.expr_ty, None);
|
||||
}
|
||||
CastError::RefToMutPtr => {
|
||||
span_err!(fcx.tcx().sess, self.span, E0188,
|
||||
"cannot cast an immutable reference to a \
|
||||
mutable pointer");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
|
||||
let t_e_is_scalar = ty::type_is_scalar(t_e);
|
||||
let t_e_is_integral = ty::type_is_integral(t_e);
|
||||
let t_e_is_float = ty::type_is_floating_point(t_e);
|
||||
let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e);
|
||||
|
||||
let t_1_is_scalar = ty::type_is_scalar(t_1);
|
||||
let t_1_is_integral = ty::type_is_integral(t_1);
|
||||
let t_1_is_char = ty::type_is_char(t_1);
|
||||
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
|
||||
let t_1_is_float = ty::type_is_floating_point(t_1);
|
||||
let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1);
|
||||
let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
|
||||
|
||||
// casts to scalars other than `char` and `bare fn` are trivial
|
||||
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
|
||||
|
||||
if t_e_is_bare_fn_item && t_1_is_bare_fn {
|
||||
demand::coerce(fcx, e.span, t_1, &e);
|
||||
} else if t_1_is_char {
|
||||
let t_e = fcx.infcx().shallow_resolve(t_e);
|
||||
if t_e.sty != ty::ty_uint(ast::TyU8) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("only `u8` can be cast as `char`, not `{}`", actual)
|
||||
}, t_e, None);
|
||||
}
|
||||
} else if t_1.sty == ty::ty_bool {
|
||||
span_err!(tcx.sess, span, E0054,
|
||||
"cannot cast as `bool`, compare with zero instead");
|
||||
} else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) &&
|
||||
!(t_1_is_integral || t_1_is_float) {
|
||||
// Casts from float must go through an integer
|
||||
cast_through_integer_err(fcx, span, t_1, t_e)
|
||||
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) &&
|
||||
!(t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
|
||||
// Casts to float must go through an integer or boolean
|
||||
cast_through_integer_err(fcx, span, t_1, t_e)
|
||||
} else if t_e_is_c_enum && t_1_is_trivial {
|
||||
if ty::type_is_unsafe_ptr(t_1) {
|
||||
// ... and likewise with C enum -> *T
|
||||
cast_through_integer_err(fcx, span, t_1, t_e)
|
||||
}
|
||||
// casts from C-like enums are allowed
|
||||
} else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
|
||||
fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
|
||||
t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
|
||||
match t1.sty {
|
||||
ty::ty_vec(_, Some(_)) => {}
|
||||
_ => return false
|
||||
}
|
||||
if ty::type_needs_infer(t2) {
|
||||
// This prevents this special case from going off when casting
|
||||
// to a type that isn't fully specified; e.g. `as *_`. (Issue
|
||||
// #14893.)
|
||||
return false
|
||||
}
|
||||
|
||||
let el = ty::sequence_element_type(fcx.tcx(), t1);
|
||||
infer::mk_eqty(fcx.infcx(),
|
||||
false,
|
||||
infer::Misc(sp),
|
||||
el,
|
||||
t2).is_ok()
|
||||
fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
let t_cast = self.cast_ty;
|
||||
let t_expr = self.expr_ty;
|
||||
if ty::type_is_numeric(t_cast) && ty::type_is_numeric(t_expr) {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
self.expr.id,
|
||||
self.span,
|
||||
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_expr),
|
||||
fcx.infcx().ty_to_string(t_cast)));
|
||||
} else {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
self.expr.id,
|
||||
self.span,
|
||||
format!("trivial cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_expr),
|
||||
fcx.infcx().ty_to_string(t_cast)));
|
||||
}
|
||||
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow unsafe pointers to work correctly, we
|
||||
// need to special-case obtaining an unsafe pointer
|
||||
// from a region pointer to a vector.
|
||||
}
|
||||
|
||||
/* this cast is only allowed from &[T, ..n] to *T or
|
||||
&T to *T. */
|
||||
match (&t_e.sty, &t_1.sty) {
|
||||
(&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
|
||||
&ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
|
||||
if types_compatible(fcx, e.span, mt1, mt2) => {
|
||||
/* this case is allowed */
|
||||
pub fn check<'a>(mut self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty);
|
||||
self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty);
|
||||
|
||||
debug!("check_cast({}, {} as {})", self.expr.id, self.expr_ty.repr(fcx.tcx()),
|
||||
self.cast_ty.repr(fcx.tcx()));
|
||||
|
||||
if ty::type_is_error(self.expr_ty) || ty::type_is_error(self.cast_ty) {
|
||||
// No sense in giving duplicate error messages
|
||||
} else if self.try_coercion_cast(fcx) {
|
||||
self.trivial_cast_lint(fcx);
|
||||
debug!(" -> CoercionCast");
|
||||
fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id,
|
||||
CastKind::CoercionCast);
|
||||
} else { match self.do_check(fcx) {
|
||||
Ok(k) => {
|
||||
debug!(" -> {:?}", k);
|
||||
fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id, k);
|
||||
}
|
||||
Err(e) => self.report_cast_error(fcx, e)
|
||||
};}
|
||||
}
|
||||
|
||||
/// Check a cast, and report an error if one exists. In some cases, this
|
||||
/// can return Ok and create type errors in the fcx rather than returning
|
||||
/// directly. coercion-cast is handled in check instead of here.
|
||||
fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
use middle::cast::IntTy::*;
|
||||
use middle::cast::CastTy::*;
|
||||
|
||||
let (t_from, t_cast) = match (CastTy::from_ty(fcx.tcx(), self.expr_ty),
|
||||
CastTy::from_ty(fcx.tcx(), self.cast_ty)) {
|
||||
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
|
||||
_ => {
|
||||
demand::coerce(fcx, e.span, t_1, &e);
|
||||
return Err(CastError::NonScalar)
|
||||
}
|
||||
};
|
||||
|
||||
match (t_from, t_cast) {
|
||||
// These types have invariants! can't cast into them.
|
||||
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
|
||||
// * -> Bool
|
||||
(_, Int(Bool)) => Err(CastError::CastToBool),
|
||||
|
||||
// * -> Char
|
||||
(Int(U(ast::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
|
||||
(_, Int(Char)) => Err(CastError::CastToChar),
|
||||
|
||||
// prim -> float,ptr
|
||||
(Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float)
|
||||
=> Err(CastError::NeedViaInt),
|
||||
(Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_))
|
||||
=> Err(CastError::NeedViaUsize),
|
||||
|
||||
// ptr -> *
|
||||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
||||
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
|
||||
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
||||
(RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
|
||||
// * -> ptr
|
||||
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
||||
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||
(Float, Ptr(_)) => Err(CastError::NeedViaUsize),
|
||||
(RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
|
||||
|
||||
// prim -> prim
|
||||
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
|
||||
(Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
|
||||
|
||||
(Int(_), Int(_)) |
|
||||
(Int(_), Float) |
|
||||
(Float, Int(_)) |
|
||||
(Float, Float) => Ok(CastKind::NumericCast),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ptr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::mt<'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
debug!("check_ptr_ptr_cast m_expr={} m_cast={}",
|
||||
m_expr.repr(fcx.tcx()), m_cast.repr(fcx.tcx()));
|
||||
// ptr-ptr cast. vtables must match.
|
||||
|
||||
// Cast to sized is OK
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
return Ok(CastKind::PtrPtrCast);
|
||||
}
|
||||
|
||||
// sized -> unsized? report illegal cast (don't complain about vtable kinds)
|
||||
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
||||
return Err(CastError::IllegalCast);
|
||||
}
|
||||
|
||||
// vtable kinds must match
|
||||
match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) {
|
||||
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
|
||||
_ => Err(CastError::DifferingKinds)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fptr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// fptr-ptr cast. must be to sized ptr
|
||||
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
Ok(CastKind::FnPtrPtrCast)
|
||||
} else {
|
||||
Err(CastError::IllegalCast)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ptr_addr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// ptr-addr cast. must be from sized ptr
|
||||
|
||||
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
||||
Ok(CastKind::PtrAddrCast)
|
||||
} else {
|
||||
Err(CastError::NeedViaPtr)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_ref_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_expr: &'tcx ty::mt<'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// array-ptr-cast.
|
||||
|
||||
if m_expr.mutbl == ast::MutImmutable && m_cast.mutbl == ast::MutImmutable {
|
||||
if let ty::ty_vec(ety, Some(_)) = m_expr.ty.sty {
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
// To allow unsafe pointers to work correctly, we
|
||||
// need to special-case obtaining an unsafe pointer
|
||||
// from a region pointer to a vector.
|
||||
|
||||
// this will report a type mismatch if needed
|
||||
demand::eqtype(fcx, self.span, ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
}
|
||||
} else if t1_is_fat_ptr {
|
||||
// FIXME This should be allowed where the lefthandside is also a fat
|
||||
// pointer and is the same kind of fat pointer, i.e., array to array,
|
||||
// trait object to trait object. That is a bit looser than the current
|
||||
// rquirement that they are pointers to the same type.
|
||||
if !(fcx.type_is_fat_ptr(t_e, span) &&
|
||||
ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("cast to fat pointer: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
}
|
||||
} else if !(t_e_is_scalar && t_1_is_trivial) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("non-scalar cast: `{}` as `{}`",
|
||||
actual,
|
||||
fcx.infcx().ty_to_string(t_1))
|
||||
}, t_e, None);
|
||||
|
||||
Err(CastError::IllegalCast)
|
||||
}
|
||||
|
||||
fn check_addr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// ptr-addr cast. pointer must be thin.
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
Ok(CastKind::AddrPtrCast)
|
||||
} else {
|
||||
Err(CastError::IllegalCast)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
|
||||
if let Ok(()) = coercion::mk_assignty(fcx,
|
||||
&self.expr,
|
||||
self.expr_ty,
|
||||
self.cast_ty) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -528,6 +528,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
|
||||
fcx.select_all_obligations_or_error();
|
||||
fcx.check_casts();
|
||||
|
||||
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
|
||||
|
||||
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
}
|
||||
@ -1112,20 +1115,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
t_span: Span,
|
||||
e_span: Span,
|
||||
t_1: Ty<'tcx>,
|
||||
t_e: Ty<'tcx>,
|
||||
t_cast: Ty<'tcx>,
|
||||
t_expr: Ty<'tcx>,
|
||||
id: ast::NodeId) {
|
||||
let tstr = fcx.infcx().ty_to_string(t_1);
|
||||
let tstr = fcx.infcx().ty_to_string(t_cast);
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
||||
}, t_e, None);
|
||||
match t_e.sty {
|
||||
}, t_expr, None);
|
||||
match t_expr.sty {
|
||||
ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
|
||||
let mtstr = match mt {
|
||||
ast::MutMutable => "mut ",
|
||||
ast::MutImmutable => ""
|
||||
};
|
||||
if ty::type_is_trait(t_1) {
|
||||
if ty::type_is_trait(t_cast) {
|
||||
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
|
||||
Ok(s) => {
|
||||
fcx.tcx().sess.span_suggestion(t_span,
|
||||
@ -1581,13 +1584,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span)
|
||||
}
|
||||
|
||||
pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if let Some(mt) = ty::deref(ty, true) {
|
||||
return !self.type_is_known_to_be_sized(mt.ty, span);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound(&self,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
@ -1810,11 +1806,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
fn check_casts(&self) {
|
||||
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
|
||||
for check in deferred_cast_checks.iter() {
|
||||
cast::check_cast(self, check);
|
||||
for cast in deferred_cast_checks.drain(..) {
|
||||
cast.check(self);
|
||||
}
|
||||
|
||||
deferred_cast_checks.clear();
|
||||
}
|
||||
|
||||
fn select_all_obligations_and_apply_defaults(&self) {
|
||||
@ -3410,24 +3404,24 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
||||
// Find the type of `e`. Supply hints based on the type we are casting to,
|
||||
// if appropriate.
|
||||
let t_1 = fcx.to_ty(t);
|
||||
let t_1 = structurally_resolved_type(fcx, expr.span, t_1);
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
|
||||
let t_e = fcx.expr_ty(e);
|
||||
let t_cast = fcx.to_ty(t);
|
||||
let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
|
||||
let t_expr = fcx.expr_ty(e);
|
||||
|
||||
// Eagerly check for some obvious errors.
|
||||
if ty::type_is_error(t_e) {
|
||||
if ty::type_is_error(t_expr) {
|
||||
fcx.write_error(id);
|
||||
} else if !fcx.type_is_known_to_be_sized(t_1, expr.span) {
|
||||
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id);
|
||||
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
|
||||
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
|
||||
} else {
|
||||
// Write a type for the whole expression, assuming everything is going
|
||||
// to work out Ok.
|
||||
fcx.write_ty(id, t_1);
|
||||
fcx.write_ty(id, t_cast);
|
||||
|
||||
// Defer other checks until we're done type checking.
|
||||
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
|
||||
let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
|
||||
let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
|
||||
deferred_cast_checks.push(cast_check);
|
||||
}
|
||||
}
|
||||
|
@ -977,11 +977,11 @@ register_diagnostics! {
|
||||
E0185,
|
||||
E0186,
|
||||
E0187, // can't infer the kind of the closure
|
||||
E0188, // types differ in mutability
|
||||
E0189, // can only cast a boxed pointer to a boxed object
|
||||
E0190, // can only cast a &-pointer to an &-object
|
||||
E0188, // can not cast a immutable reference to a mutable pointer
|
||||
E0189, // deprecated: can only cast a boxed pointer to a boxed object
|
||||
E0190, // deprecated: can only cast a &-pointer to an &-object
|
||||
E0191, // value of the associated type must be specified
|
||||
E0192, // negative imples are allowed just for `Send` and `Sync`
|
||||
E0192, // negative impls are allowed just for `Send` and `Sync`
|
||||
E0193, // cannot bound type where clause bounds may only be attached to types
|
||||
// involving type parameters
|
||||
E0194,
|
||||
|
@ -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)]
|
||||
|
@ -28,15 +28,15 @@ impl Foo for isize {
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = &42 as &Foo<A=usize, B=char>;
|
||||
let a = &42isize as &Foo<A=usize, B=char>;
|
||||
|
||||
let b = &42 as &Foo<A=usize>;
|
||||
let b = &42isize as &Foo<A=usize>;
|
||||
//~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
|
||||
|
||||
let c = &42 as &Foo<B=char>;
|
||||
let c = &42isize as &Foo<B=char>;
|
||||
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
|
||||
|
||||
let d = &42 as &Foo;
|
||||
let d = &42isize as &Foo;
|
||||
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
|
||||
//~| ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
|
||||
}
|
||||
|
15
src/test/compile-fail/cast-ptr-to-int-const.rs
Normal file
15
src/test/compile-fail/cast-ptr-to-int-const.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
const X: u32 = main as u32; //~ ERROR E0018
|
||||
const Y: u32 = 0;
|
||||
const Z: u32 = &Y as *const u32 as u32; //~ ERROR E0018
|
||||
}
|
75
src/test/compile-fail/cast-rfc0401.rs
Normal file
75
src/test/compile-fail/cast-rfc0401.rs
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn illegal_cast<U:?Sized,V:?Sized>(u: *const U) -> *const V
|
||||
{
|
||||
u as *const V //~ ERROR vtable kinds
|
||||
}
|
||||
|
||||
fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
|
||||
{
|
||||
u as *const str //~ ERROR vtable kinds
|
||||
}
|
||||
|
||||
trait Foo { fn foo(&self) {} }
|
||||
impl<T> Foo for T {}
|
||||
|
||||
enum E {
|
||||
A, B
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let f: f32 = 1.2;
|
||||
let v = 0 as *const u8;
|
||||
let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
|
||||
let foo: &Foo = &f;
|
||||
|
||||
let _ = v as &u8; //~ ERROR non-scalar
|
||||
let _ = v as E; //~ ERROR non-scalar
|
||||
let _ = v as fn(); //~ ERROR non-scalar
|
||||
let _ = v as (u32,); //~ ERROR non-scalar
|
||||
let _ = Some(&v) as *const u8; //~ ERROR non-scalar
|
||||
|
||||
let _ = v as f32; //~ ERROR through a usize first
|
||||
let _ = main as f64; //~ ERROR through a usize first
|
||||
let _ = &v as usize; //~ ERROR through a raw pointer first
|
||||
let _ = f as *const u8; //~ ERROR through a usize first
|
||||
let _ = 3 as bool; //~ ERROR compare with zero
|
||||
let _ = E::A as bool; //~ ERROR compare with zero
|
||||
let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast
|
||||
|
||||
let _ = false as f32; //~ ERROR through an integer first
|
||||
let _ = E::A as f32; //~ ERROR through an integer first
|
||||
let _ = 'a' as f32; //~ ERROR through an integer first
|
||||
|
||||
let _ = false as *const u8; //~ ERROR through a usize first
|
||||
let _ = E::A as *const u8; //~ ERROR through a usize first
|
||||
let _ = 'a' as *const u8; //~ ERROR through a usize first
|
||||
|
||||
let _ = 42usize as *const [u8]; //~ ERROR illegal cast
|
||||
let _ = v as *const [u8]; //~ ERROR illegal cast
|
||||
let _ = fat_v as *const Foo;
|
||||
//~^ ERROR `core::marker::Sized` is not implemented for the type `[u8]`
|
||||
let _ = foo as *const str; //~ ERROR illegal cast
|
||||
let _ = foo as *mut str; //~ ERROR illegal cast
|
||||
let _ = main as *mut str; //~ ERROR illegal cast
|
||||
let _ = &f as *mut f32; //~ ERROR illegal cast
|
||||
let _ = &f as *const f64; //~ ERROR illegal cast
|
||||
let _ = fat_v as usize; //~ ERROR through a raw pointer first
|
||||
|
||||
let a : *const str = "hello";
|
||||
let _ = a as *const Foo;
|
||||
//~^ ERROR `core::marker::Sized` is not implemented for the type `str`
|
||||
|
||||
// check no error cascade
|
||||
let _ = main.f as *const u32; //~ ERROR attempted access of field
|
||||
|
||||
}
|
@ -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());
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -28,29 +28,29 @@ fn main() {
|
||||
// if n > m, it's a type mismatch error.
|
||||
|
||||
// n < m
|
||||
let &x = &(&1 as &T);
|
||||
let &x = &&(&1 as &T);
|
||||
let &&x = &&(&1 as &T);
|
||||
let &x = &(&1isize as &T);
|
||||
let &x = &&(&1isize as &T);
|
||||
let &&x = &&(&1isize as &T);
|
||||
|
||||
// n == m
|
||||
let &x = &1 as &T; //~ ERROR type `&T` cannot be dereferenced
|
||||
let &&x = &(&1 as &T); //~ ERROR type `&T` cannot be dereferenced
|
||||
let box x = box 1 as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
|
||||
let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced
|
||||
let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced
|
||||
let box x = box 1isize as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
|
||||
|
||||
// n > m
|
||||
let &&x = &1 as &T;
|
||||
let &&x = &1isize as &T;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `T`
|
||||
//~| found `&_`
|
||||
//~| expected trait T
|
||||
//~| found &-ptr
|
||||
let &&&x = &(&1 as &T);
|
||||
let &&&x = &(&1isize as &T);
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `T`
|
||||
//~| found `&_`
|
||||
//~| expected trait T
|
||||
//~| found &-ptr
|
||||
let box box x = box 1 as Box<T>;
|
||||
let box box x = box 1isize as Box<T>;
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `T`
|
||||
//~| found `Box<_>`
|
||||
|
@ -8,20 +8,23 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Make sure casts between thin pointer <-> fat pointer are illegal.
|
||||
|
||||
pub trait Trait {}
|
||||
trait Trait {}
|
||||
|
||||
// Make sure casts between thin-pointer <-> fat pointer obey RFC401
|
||||
fn main() {
|
||||
let a: &[i32] = &[1, 2, 3];
|
||||
let b: Box<[i32]> = Box::new([1, 2, 3]);
|
||||
let p = a as *const [i32];
|
||||
let q = a.as_ptr();
|
||||
|
||||
a as usize; //~ ERROR non-scalar cast
|
||||
a as usize; //~ ERROR illegal cast
|
||||
b as usize; //~ ERROR non-scalar cast
|
||||
p as usize; //~ ERROR illegal cast; cast through a raw pointer
|
||||
|
||||
let a: usize = 42;
|
||||
a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
|
||||
// #22955
|
||||
q as *const [i32]; //~ ERROR illegal cast
|
||||
|
||||
let a: *const u8 = &42;
|
||||
a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
|
||||
// #21397
|
||||
let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast
|
||||
let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ fn f<T>(val: T) {
|
||||
let a = &t as &Gettable<T>;
|
||||
//~^ ERROR the trait `core::marker::Send` is not implemented
|
||||
//~^^ ERROR the trait `core::marker::Copy` is not implemented
|
||||
//~^^^ ERROR the parameter type `T` may not live long enough
|
||||
}
|
||||
|
||||
fn g<T>(val: T) {
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
|
44
src/test/run-pass-valgrind/cast-enum-with-dtor.rs
Normal file
44
src/test/run-pass-valgrind/cast-enum-with-dtor.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// check dtor calling order when casting enums.
|
||||
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::mem;
|
||||
|
||||
enum E {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2
|
||||
}
|
||||
|
||||
static FLAG: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
|
||||
|
||||
impl Drop for E {
|
||||
fn drop(&mut self) {
|
||||
// avoid dtor loop
|
||||
unsafe { mem::forget(mem::replace(self, E::B)) };
|
||||
|
||||
FLAG.store(FLAG.load(Ordering::SeqCst)+1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
|
||||
{
|
||||
let e = E::C;
|
||||
assert_eq!(e as u32, 2);
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
|
||||
}
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
|
||||
}
|
55
src/test/run-pass/cast-rfc0401-vtable-kinds.rs
Normal file
55
src/test/run-pass/cast-rfc0401-vtable-kinds.rs
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that you can cast between different pointers to trait objects
|
||||
// whose vtable have the same kind (both lengths, or both trait pointers).
|
||||
|
||||
trait Foo<T> {
|
||||
fn foo(&self, _: T) -> u32 { 42 }
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn bar(&self) { println!("Bar!"); }
|
||||
}
|
||||
|
||||
impl<T> Foo<T> for () {}
|
||||
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
|
||||
impl Bar for () {}
|
||||
|
||||
unsafe fn fool<'a>(t: *const (Foo<u32>+'a)) -> u32 {
|
||||
let bar : *const Bar = t as *const Bar;
|
||||
let foo_e : *const Foo<u16> = t as *const _;
|
||||
let r_1 = foo_e as *mut Foo<u32>;
|
||||
|
||||
(&*r_1).foo(0)*(&*(bar as *const Foo<u32>)).foo(0)
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct FooS<T:?Sized>(T);
|
||||
#[repr(C)]
|
||||
struct BarS<T:?Sized>(T);
|
||||
|
||||
fn foo_to_bar<T:?Sized>(u: *const FooS<T>) -> *const BarS<T> {
|
||||
u as *const BarS<T>
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 4u32;
|
||||
let y : &Foo<u32> = &x;
|
||||
let fl = unsafe { fool(y as *const Foo<u32>) };
|
||||
assert_eq!(fl, (43+4)*(43+4));
|
||||
|
||||
let s = FooS([0,1,2]);
|
||||
let u: &FooS<[u32]> = &s;
|
||||
let u: *const FooS<[u32]> = u;
|
||||
let bar_ref : *const BarS<[u32]> = foo_to_bar(u);
|
||||
let z : &BarS<[u32]> = unsafe{&*bar_ref};
|
||||
assert_eq!(&z.0, &[0,1,2]);
|
||||
}
|
170
src/test/run-pass/cast-rfc0401.rs
Normal file
170
src/test/run-pass/cast-rfc0401.rs
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::vec;
|
||||
|
||||
enum Simple {
|
||||
A,
|
||||
B,
|
||||
C
|
||||
}
|
||||
|
||||
enum Valued {
|
||||
H8=163,
|
||||
Z=0,
|
||||
X=256,
|
||||
H7=67,
|
||||
}
|
||||
|
||||
enum ValuedSigned {
|
||||
M1=-1,
|
||||
P1=1
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
// coercion-cast
|
||||
let mut it = vec![137].into_iter();
|
||||
let itr: &mut vec::IntoIter<u32> = &mut it;
|
||||
assert_eq!((itr as &mut Iterator<Item=u32>).next(), Some(137));
|
||||
assert_eq!((itr as &mut Iterator<Item=u32>).next(), None);
|
||||
|
||||
assert_eq!(Some(4u32) as Option<u32>, Some(4u32));
|
||||
assert_eq!((1u32,2u32) as (u32,u32), (1,2));
|
||||
|
||||
// this isn't prim-int-cast. Check that it works.
|
||||
assert_eq!(false as bool, false);
|
||||
assert_eq!(true as bool, true);
|
||||
|
||||
// numeric-cast
|
||||
let l: u64 = 0x8090a0b0c0d0e0f0;
|
||||
let lsz: usize = l as usize;
|
||||
assert_eq!(l as u32, 0xc0d0e0f0);
|
||||
|
||||
// numeric-cast
|
||||
assert_eq!(l as u8, 0xf0);
|
||||
assert_eq!(l as i8,-0x10);
|
||||
assert_eq!(l as u32, 0xc0d0e0f0);
|
||||
assert_eq!(l as u32 as usize as u32, l as u32);
|
||||
assert_eq!(l as i32,-0x3f2f1f10);
|
||||
assert_eq!(l as i32 as isize as i32, l as i32);
|
||||
assert_eq!(l as i64,-0x7f6f5f4f3f2f1f10);
|
||||
|
||||
assert_eq!(0 as f64, 0f64);
|
||||
assert_eq!(1 as f64, 1f64);
|
||||
|
||||
assert_eq!(l as f64, 9264081114510712022f64);
|
||||
|
||||
assert_eq!(l as i64 as f64, -9182662959198838444f64);
|
||||
// float overflow : needs fixing
|
||||
// assert_eq!(l as f32 as i64 as u64, 9264082620822882088u64);
|
||||
// assert_eq!(l as i64 as f32 as i64, 9182664080220408446i64);
|
||||
|
||||
assert_eq!(4294967040f32 as u32, 0xffffff00u32);
|
||||
assert_eq!(1.844674407370955e19f64 as u64, 0xfffffffffffff800u64);
|
||||
|
||||
assert_eq!(9.223372036854775e18f64 as i64, 0x7ffffffffffffc00i64);
|
||||
assert_eq!(-9.223372036854776e18f64 as i64, 0x8000000000000000u64 as i64);
|
||||
|
||||
// addr-ptr-cast/ptr-addr-cast (thin ptr)
|
||||
let p: *const [u8; 1] = lsz as *const [u8; 1];
|
||||
assert_eq!(p as usize, lsz);
|
||||
|
||||
// ptr-ptr-cast (thin ptr)
|
||||
let w: *const () = p as *const ();
|
||||
assert_eq!(w as usize, lsz);
|
||||
|
||||
// ptr-ptr-cast (fat->thin)
|
||||
let u: *const [u8] = unsafe{&*p};
|
||||
assert_eq!(u as *const u8, p as *const u8);
|
||||
assert_eq!(u as *const u16, p as *const u16);
|
||||
|
||||
// ptr-ptr-cast (both vk=Length)
|
||||
let mut l : [u8; 2] = [0,1];
|
||||
let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
|
||||
let w: *mut [u16] = unsafe {&mut *w};
|
||||
let w_u8 : *const [u8] = w as *const [u8];
|
||||
assert_eq!(unsafe{&*w_u8}, &l);
|
||||
|
||||
let s: *mut str = w as *mut str;
|
||||
let l_via_str = unsafe{&*(s as *const [u8])};
|
||||
assert_eq!(&l, l_via_str);
|
||||
|
||||
// enum-cast
|
||||
assert_eq!(Simple::A as u8, 0);
|
||||
assert_eq!(Simple::B as u8, 1);
|
||||
|
||||
assert_eq!(Valued::H8 as i8, -93);
|
||||
assert_eq!(Valued::H7 as i8, 67);
|
||||
assert_eq!(Valued::Z as i8, 0);
|
||||
|
||||
assert_eq!(Valued::H8 as u8, 163);
|
||||
assert_eq!(Valued::H7 as u8, 67);
|
||||
assert_eq!(Valued::Z as u8, 0);
|
||||
|
||||
assert_eq!(Valued::H8 as u16, 163);
|
||||
assert_eq!(Valued::Z as u16, 0);
|
||||
assert_eq!(Valued::H8 as u16, 163);
|
||||
assert_eq!(Valued::Z as u16, 0);
|
||||
|
||||
assert_eq!(ValuedSigned::M1 as u16, 65535);
|
||||
assert_eq!(ValuedSigned::M1 as i16, -1);
|
||||
assert_eq!(ValuedSigned::P1 as u16, 1);
|
||||
assert_eq!(ValuedSigned::P1 as i16, 1);
|
||||
|
||||
// prim-int-cast
|
||||
assert_eq!(false as u16, 0);
|
||||
assert_eq!(true as u16, 1);
|
||||
assert_eq!(false as i64, 0);
|
||||
assert_eq!(true as i64, 1);
|
||||
assert_eq!('a' as u32, 0x61);
|
||||
assert_eq!('a' as u16, 0x61);
|
||||
assert_eq!('a' as u8, 0x61);
|
||||
assert_eq!('א' as u8, 0xd0);
|
||||
assert_eq!('א' as u16, 0x5d0);
|
||||
assert_eq!('א' as u32, 0x5d0);
|
||||
assert_eq!('🐵' as u8, 0x35);
|
||||
assert_eq!('🐵' as u16, 0xf435);
|
||||
assert_eq!('🐵' as u32, 0x1f435);
|
||||
assert_eq!('英' as i16, -0x7d0f);
|
||||
assert_eq!('英' as u16, 0x82f1);
|
||||
|
||||
// u8-char-cast
|
||||
assert_eq!(0x61 as char, 'a');
|
||||
assert_eq!(0u8 as char, '\0');
|
||||
assert_eq!(0xd7 as char, '×');
|
||||
|
||||
// array-ptr-cast
|
||||
let x = [1,2,3];
|
||||
let first : *const u32 = &x[0];
|
||||
|
||||
assert_eq!(first, &x as *const _);
|
||||
assert_eq!(first, &x as *const u32);
|
||||
|
||||
// fptr-addr-cast
|
||||
fn foo() {
|
||||
println!("foo!");
|
||||
}
|
||||
fn bar() {
|
||||
println!("bar!");
|
||||
}
|
||||
|
||||
assert!(foo as usize != bar as usize);
|
||||
|
||||
assert_eq!(foo as i16, foo as usize as i16);
|
||||
|
||||
// fptr-ptr-cast
|
||||
|
||||
assert_eq!(foo as *const u8 as usize, foo as usize);
|
||||
assert!(foo as *const u32 != first);
|
||||
}
|
||||
fn foo() { }
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user