Address review commets
I think I didn't run tests properly - my second call to select_all_obligations_or_error has made 3 tests fail. However, this is just an error message change - integer fallback never worked with casts.
This commit is contained in:
parent
de4b0e9961
commit
32fe2e3ad4
14 changed files with 123 additions and 103 deletions
|
@ -15,7 +15,7 @@ use middle::ty::{self, Ty};
|
|||
|
||||
use syntax::ast;
|
||||
|
||||
|
||||
/// Types that are represented as ints.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum IntTy {
|
||||
U(ast::UintTy),
|
||||
|
@ -28,10 +28,16 @@ pub enum IntTy {
|
|||
// Valid types for the result of a non-coercion cast
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CastTy<'tcx> {
|
||||
/// Various types that are represented as ints and handled mostly
|
||||
/// in the same way, merged for easier matching.
|
||||
Int(IntTy),
|
||||
/// Floating-Point types
|
||||
Float,
|
||||
FPtr,
|
||||
/// Function Pointers
|
||||
FnPtr,
|
||||
/// Raw pointers
|
||||
Ptr(&'tcx ty::mt<'tcx>),
|
||||
/// References
|
||||
RPtr(&'tcx ty::mt<'tcx>),
|
||||
}
|
||||
|
||||
|
@ -47,13 +53,13 @@ pub enum CastKind {
|
|||
PrimIntCast,
|
||||
U8CharCast,
|
||||
ArrayPtrCast,
|
||||
FPtrPtrCast,
|
||||
FPtrAddrCast
|
||||
FnPtrPtrCast,
|
||||
FnPtrAddrCast
|
||||
}
|
||||
|
||||
impl<'tcx> CastTy<'tcx> {
|
||||
pub fn recognize(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>)
|
||||
-> Option<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)),
|
||||
|
@ -64,7 +70,7 @@ impl<'tcx> CastTy<'tcx> {
|
|||
tcx, t) => Some(CastTy::Int(IntTy::CEnum)),
|
||||
ty::ty_ptr(ref mt) => Some(CastTy::Ptr(mt)),
|
||||
ty::ty_rptr(_, ref mt) => Some(CastTy::RPtr(mt)),
|
||||
ty::ty_bare_fn(..) => Some(CastTy::FPtr),
|
||||
ty::ty_bare_fn(..) => Some(CastTy::FnPtr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -443,11 +443,11 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
debug!("Checking const cast(id={})", from.id);
|
||||
match v.tcx.cast_kinds.borrow().get(&from.id) {
|
||||
None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
|
||||
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FPtrAddrCast) => {
|
||||
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0018,
|
||||
"can not cast a pointer to an integer in {}s", v.msg());
|
||||
"can't cast a pointer to an integer in {}s", v.msg());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -617,41 +617,41 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
ast::ExprCast(ref base, _) => {
|
||||
let t_1 = ety;
|
||||
let llty = type_of::type_of(cx, t_1);
|
||||
let (v, t_e) = const_expr(cx, &**base, param_substs);
|
||||
debug!("trans_const_cast({} as {})", t_e.repr(cx.tcx()), t_1.repr(cx.tcx()));
|
||||
if expr::cast_is_noop(cx.tcx(), base, t_e, t_1) {
|
||||
let t_cast = ety;
|
||||
let llty = type_of::type_of(cx, t_cast);
|
||||
let (v, t_expr) = const_expr(cx, &**base, param_substs);
|
||||
debug!("trans_const_cast({} as {})", t_expr.repr(cx.tcx()), t_cast.repr(cx.tcx()));
|
||||
if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
|
||||
return v;
|
||||
}
|
||||
if type_is_fat_ptr(cx.tcx(), t_e) {
|
||||
if type_is_fat_ptr(cx.tcx(), t_expr) {
|
||||
// Fat pointer casts.
|
||||
let t_1_inner = ty::deref(t_1, true).expect("cast to non-pointer").ty;
|
||||
let ptr_ty = type_of::in_memory_type_of(cx, t_1_inner).ptr_to();
|
||||
let t_cast_inner = ty::deref(t_cast, true).expect("cast to non-pointer").ty;
|
||||
let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
|
||||
let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]),
|
||||
ptr_ty);
|
||||
if type_is_fat_ptr(cx.tcx(), t_1) {
|
||||
if type_is_fat_ptr(cx.tcx(), t_cast) {
|
||||
let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
|
||||
return C_struct(cx, &[addr, info], false)
|
||||
} else {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
match (CastTy::recognize(cx.tcx(), t_e).expect("bad input type for cast"),
|
||||
CastTy::recognize(cx.tcx(), t_1).expect("bad output type for cast")) {
|
||||
match (CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"),
|
||||
CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast")) {
|
||||
(CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
|
||||
let repr = adt::represent_type(cx, t_e);
|
||||
let repr = adt::represent_type(cx, t_expr);
|
||||
let discr = adt::const_get_discrim(cx, &*repr, v);
|
||||
let iv = C_integral(cx.int_type(), discr, false);
|
||||
let s = adt::is_discr_signed(&*repr) as Bool;
|
||||
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
|
||||
}
|
||||
(CastTy::Int(_), CastTy::Int(_)) => {
|
||||
let s = ty::type_is_signed(t_e) as Bool;
|
||||
let s = ty::type_is_signed(t_expr) as Bool;
|
||||
llvm::LLVMConstIntCast(v, llty.to_ref(), s)
|
||||
}
|
||||
(CastTy::Int(_), CastTy::Float) => {
|
||||
if ty::type_is_signed(t_e) {
|
||||
if ty::type_is_signed(t_expr) {
|
||||
llvm::LLVMConstSIToFP(v, llty.to_ref())
|
||||
} else {
|
||||
llvm::LLVMConstUIToFP(v, llty.to_ref())
|
||||
|
@ -661,18 +661,18 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
llvm::LLVMConstFPCast(v, llty.to_ref())
|
||||
}
|
||||
(CastTy::Float, CastTy::Int(_)) => {
|
||||
if ty::type_is_signed(t_1) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
|
||||
if ty::type_is_signed(t_expr) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
|
||||
else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
|
||||
}
|
||||
(CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FPtr, CastTy::Ptr(_))
|
||||
(CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
|
||||
| (CastTy::RPtr(_), CastTy::Ptr(_)) => {
|
||||
ptrcast(v, llty)
|
||||
}
|
||||
(CastTy::FPtr, CastTy::FPtr) => ptrcast(v, llty), // isn't this a coercion?
|
||||
(CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
|
||||
(CastTy::Int(_), CastTy::Ptr(_)) => {
|
||||
llvm::LLVMConstIntToPtr(v, llty.to_ref())
|
||||
}
|
||||
(CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FPtr, CastTy::Int(_)) => {
|
||||
(CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
|
||||
llvm::LLVMConstPtrToInt(v, llty.to_ref())
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -2086,8 +2086,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
let r_t_in = CastTy::recognize(bcx.tcx(), t_in).expect("bad input type for cast");
|
||||
let r_t_out = CastTy::recognize(bcx.tcx(), t_out).expect("bad output type for cast");
|
||||
let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast");
|
||||
let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast");
|
||||
|
||||
let (llexpr, signed) = if let Int(CEnum) = r_t_in {
|
||||
let repr = adt::represent_type(ccx, t_in);
|
||||
|
@ -2102,8 +2102,10 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
};
|
||||
|
||||
let newval = match (r_t_in, r_t_out) {
|
||||
(Ptr(_), Ptr(_)) | (FPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => PointerCast(bcx, llexpr, ll_t_out),
|
||||
(Ptr(_), Int(_)) | (FPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
|
||||
(Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
|
||||
PointerCast(bcx, llexpr, ll_t_out)
|
||||
}
|
||||
(Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
|
||||
(Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
|
||||
|
||||
(Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
|
||||
|
|
|
@ -56,11 +56,16 @@ pub struct CastCheck<'tcx> {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
/// The kind of the unsize info (length or vtable) - we only allow casts between
|
||||
/// fat pointers if their unsize-infos have the same kind.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
enum UnsizeKind<'tcx> {
|
||||
Vtable,
|
||||
Length,
|
||||
OfTy(Ty<'tcx>)
|
||||
/// The unsize info of this projection
|
||||
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
|
||||
/// The unsize info of this parameter
|
||||
OfParam(&'tcx ty::ParamTy)
|
||||
}
|
||||
|
||||
/// Returns the kind of unsize information of t, or None
|
||||
|
@ -77,8 +82,9 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
Some(f) => unsize_kind(fcx, f.mt.ty)
|
||||
}
|
||||
}
|
||||
ty::ty_projection(..) | ty::ty_param(..) =>
|
||||
Some(UnsizeKind::OfTy(t)),
|
||||
// We should really try to normalize here.
|
||||
ty::ty_projection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
|
||||
ty::ty_param(ref p) => Some(UnsizeKind::OfParam(p)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
@ -164,17 +170,17 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
}
|
||||
|
||||
fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
let t_1 = self.cast_ty;
|
||||
let t_e = self.expr_ty;
|
||||
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
|
||||
let t_cast = self.cast_ty;
|
||||
let t_expr = self.expr_ty;
|
||||
if ty::type_is_numeric(t_cast) && ty::type_is_numeric(t_expr) {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
self.expr.id,
|
||||
self.span,
|
||||
format!("trivial numeric cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
fcx.infcx().ty_to_string(t_expr),
|
||||
fcx.infcx().ty_to_string(t_cast)));
|
||||
} else {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
self.expr.id,
|
||||
|
@ -182,8 +188,8 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
format!("trivial cast: `{}` as `{}`. Cast can be \
|
||||
replaced by coercion, this might require type \
|
||||
ascription or a temporary variable",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
fcx.infcx().ty_to_string(t_expr),
|
||||
fcx.infcx().ty_to_string(t_cast)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -211,24 +217,24 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
};}
|
||||
}
|
||||
|
||||
/// Check a cast, and report an error if one exists. In some cases,
|
||||
/// this can return Ok and create type errors rather than returning
|
||||
/// Check a cast, and report an error if one exists. In some cases, this
|
||||
/// can return Ok and create type errors in the fcx rather than returning
|
||||
/// directly. coercion-cast is handled in check instead of here.
|
||||
fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
use middle::cast::IntTy::*;
|
||||
use middle::cast::CastTy::*;
|
||||
|
||||
let (t_e, t_1) = match (CastTy::recognize(fcx.tcx(), self.expr_ty),
|
||||
CastTy::recognize(fcx.tcx(), self.cast_ty)) {
|
||||
(Some(t_e), Some(t_1)) => (t_e, t_1),
|
||||
let (t_from, t_cast) = match (CastTy::from_ty(fcx.tcx(), self.expr_ty),
|
||||
CastTy::from_ty(fcx.tcx(), self.cast_ty)) {
|
||||
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
|
||||
_ => {
|
||||
return Err(CastError::NonScalar)
|
||||
}
|
||||
};
|
||||
|
||||
match (t_e, t_1) {
|
||||
match (t_from, t_cast) {
|
||||
// These types have invariants! can't cast into them.
|
||||
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FPtr) => Err(CastError::NonScalar),
|
||||
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
|
||||
// * -> Bool
|
||||
(_, Int(Bool)) => Err(CastError::CastToBool),
|
||||
|
@ -244,14 +250,14 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
=> Err(CastError::NeedViaUsize),
|
||||
|
||||
// ptr -> *
|
||||
(Ptr(m1), Ptr(m2)) => self.check_ptr_ptr_cast(fcx, m1, m2), // ptr-ptr-cast
|
||||
(Ptr(m_e), Int(_)) => self.check_ptr_addr_cast(fcx, m_e), // ptr-addr-cast
|
||||
(Ptr(_), Float) | (FPtr, Float) => Err(CastError::NeedViaUsize),
|
||||
(FPtr, Int(_)) => Ok(CastKind::FPtrAddrCast),
|
||||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
||||
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
|
||||
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
||||
(RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
|
||||
// * -> ptr
|
||||
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
||||
(FPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||
(Float, Ptr(_)) => Err(CastError::NeedViaUsize),
|
||||
(RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
|
||||
|
||||
|
@ -269,26 +275,26 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
|
||||
fn check_ptr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_e: &'tcx ty::mt<'tcx>,
|
||||
m_1: &'tcx ty::mt<'tcx>)
|
||||
m_expr: &'tcx ty::mt<'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
debug!("check_ptr_ptr_cast m_e={} m_1={}",
|
||||
m_e.repr(fcx.tcx()), m_1.repr(fcx.tcx()));
|
||||
debug!("check_ptr_ptr_cast m_expr={} m_cast={}",
|
||||
m_expr.repr(fcx.tcx()), m_cast.repr(fcx.tcx()));
|
||||
// ptr-ptr cast. vtables must match.
|
||||
|
||||
// Cast to sized is OK
|
||||
if fcx.type_is_known_to_be_sized(m_1.ty, self.span) {
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
return Ok(CastKind::PtrPtrCast);
|
||||
}
|
||||
|
||||
// sized -> unsized? report illegal cast (don't complain about vtable kinds)
|
||||
if fcx.type_is_known_to_be_sized(m_e.ty, self.span) {
|
||||
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
||||
return Err(CastError::IllegalCast);
|
||||
}
|
||||
|
||||
// vtable kinds must match
|
||||
match (unsize_kind(fcx, m_1.ty), unsize_kind(fcx, m_e.ty)) {
|
||||
match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) {
|
||||
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
|
||||
_ => Err(CastError::DifferingKinds)
|
||||
}
|
||||
|
@ -296,13 +302,13 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
|
||||
fn check_fptr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_1: &'tcx ty::mt<'tcx>)
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// fptr-ptr cast. must be to sized ptr
|
||||
|
||||
if fcx.type_is_known_to_be_sized(m_1.ty, self.span) {
|
||||
Ok(CastKind::FPtrPtrCast)
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
Ok(CastKind::FnPtrPtrCast)
|
||||
} else {
|
||||
Err(CastError::IllegalCast)
|
||||
}
|
||||
|
@ -310,12 +316,12 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
|
||||
fn check_ptr_addr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_e: &'tcx ty::mt<'tcx>)
|
||||
m_expr: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// ptr-addr cast. must be from sized ptr
|
||||
|
||||
if fcx.type_is_known_to_be_sized(m_e.ty, self.span) {
|
||||
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
|
||||
Ok(CastKind::PtrAddrCast)
|
||||
} else {
|
||||
Err(CastError::NeedViaPtr)
|
||||
|
@ -324,14 +330,14 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
|
||||
fn check_ref_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_e: &'tcx ty::mt<'tcx>,
|
||||
m_1: &'tcx ty::mt<'tcx>)
|
||||
m_expr: &'tcx ty::mt<'tcx>,
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// array-ptr-cast.
|
||||
|
||||
if m_e.mutbl == ast::MutImmutable && m_1.mutbl == ast::MutImmutable {
|
||||
if let ty::ty_vec(ety, Some(_)) = m_e.ty.sty {
|
||||
if m_expr.mutbl == ast::MutImmutable && m_cast.mutbl == ast::MutImmutable {
|
||||
if let ty::ty_vec(ety, Some(_)) = m_expr.ty.sty {
|
||||
// Due to the limitations of LLVM global constants,
|
||||
// region pointers end up pointing at copies of
|
||||
// vector elements instead of the original values.
|
||||
|
@ -340,7 +346,7 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
// from a region pointer to a vector.
|
||||
|
||||
// this will report a type mismatch if needed
|
||||
demand::eqtype(fcx, self.span, ety, m_1.ty);
|
||||
demand::eqtype(fcx, self.span, ety, m_cast.ty);
|
||||
return Ok(CastKind::ArrayPtrCast);
|
||||
}
|
||||
}
|
||||
|
@ -350,11 +356,11 @@ impl<'tcx> CastCheck<'tcx> {
|
|||
|
||||
fn check_addr_ptr_cast<'a>(&self,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
m_1: &'tcx ty::mt<'tcx>)
|
||||
m_cast: &'tcx ty::mt<'tcx>)
|
||||
-> Result<CastKind, CastError>
|
||||
{
|
||||
// ptr-addr cast. pointer must be thin.
|
||||
if fcx.type_is_known_to_be_sized(m_1.ty, self.span) {
|
||||
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
|
||||
Ok(CastKind::AddrPtrCast)
|
||||
} else {
|
||||
Err(CastError::IllegalCast)
|
||||
|
|
|
@ -1115,20 +1115,20 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
span: Span,
|
||||
t_span: Span,
|
||||
e_span: Span,
|
||||
t_1: Ty<'tcx>,
|
||||
t_e: Ty<'tcx>,
|
||||
t_cast: Ty<'tcx>,
|
||||
t_expr: Ty<'tcx>,
|
||||
id: ast::NodeId) {
|
||||
let tstr = fcx.infcx().ty_to_string(t_1);
|
||||
let tstr = fcx.infcx().ty_to_string(t_cast);
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
|
||||
}, t_e, None);
|
||||
match t_e.sty {
|
||||
}, t_expr, None);
|
||||
match t_expr.sty {
|
||||
ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
|
||||
let mtstr = match mt {
|
||||
ast::MutMutable => "mut ",
|
||||
ast::MutImmutable => ""
|
||||
};
|
||||
if ty::type_is_trait(t_1) {
|
||||
if ty::type_is_trait(t_cast) {
|
||||
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
|
||||
Ok(s) => {
|
||||
fcx.tcx().sess.span_suggestion(t_span,
|
||||
|
@ -3404,24 +3404,24 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
|
||||
// Find the type of `e`. Supply hints based on the type we are casting to,
|
||||
// if appropriate.
|
||||
let t_1 = fcx.to_ty(t);
|
||||
let t_1 = structurally_resolved_type(fcx, expr.span, t_1);
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
|
||||
let t_e = fcx.expr_ty(e);
|
||||
let t_cast = fcx.to_ty(t);
|
||||
let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
|
||||
let t_expr = fcx.expr_ty(e);
|
||||
|
||||
// Eagerly check for some obvious errors.
|
||||
if ty::type_is_error(t_e) {
|
||||
if ty::type_is_error(t_expr) {
|
||||
fcx.write_error(id);
|
||||
} else if !fcx.type_is_known_to_be_sized(t_1, expr.span) {
|
||||
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id);
|
||||
} else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
|
||||
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
|
||||
} else {
|
||||
// Write a type for the whole expression, assuming everything is going
|
||||
// to work out Ok.
|
||||
fcx.write_ty(id, t_1);
|
||||
fcx.write_ty(id, t_cast);
|
||||
|
||||
// Defer other checks until we're done type checking.
|
||||
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
|
||||
let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
|
||||
let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
|
||||
deferred_cast_checks.push(cast_check);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -65,6 +65,10 @@ fn main()
|
|||
let _ = &f as *const f64; //~ ERROR illegal cast
|
||||
let _ = fat_v as usize; //~ ERROR through a raw pointer first
|
||||
|
||||
let a : *const str = "hello";
|
||||
let _ = a as *const Foo;
|
||||
//~^ ERROR `core::marker::Sized` is not implemented for the type `str`
|
||||
|
||||
// check no error cascade
|
||||
let _ = main.f as *const u32; //~ ERROR attempted access of field
|
||||
|
||||
|
|
|
@ -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<_>`
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Check that you can cast between different pointers to trait objects
|
||||
// whose vtable have the same kind (both lengths, or both trait pointers).
|
||||
|
||||
trait Foo<T> {
|
||||
fn foo(&self, _: T) -> u32 { 42 }
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue