提交 83acebc4 编写于 作者: A Ariel Ben-Yehuda 提交者: Ariel Ben-Yehuda

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.
上级 a172f402
......@@ -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 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f
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::{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 @@ fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, '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 @@ fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
}).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);
......
// 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;
#[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<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::FPtr),
_ => 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::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 @@ fn check_static_type(&self, e: &ast::Expr) {
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(..) => {
......
......@@ -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 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 @@ fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a
// 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()),
}
}
......
......@@ -29,6 +29,7 @@
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())
}
_ => {
......
......@@ -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::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)
}
}
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>(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;
}
}
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)
}
(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))
}
}
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();
}
_ => 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();
}
......
此差异已折叠。
......@@ -1581,13 +1581,6 @@ pub fn type_is_known_to_be_sized(&self,
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 @@ pub fn lookup_tup_field_ty(&self,
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) {
......
......@@ -825,11 +825,11 @@ impl Baz for Bar { } // Note: This is OK
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 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(collections, collections_drain)]
#![feature(core)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
......
......@@ -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
}
......@@ -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
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册