use super::structurally_resolved_type;
use lint;
-use middle::def_id::DefId;
-use middle::ty::{self, Ty, TypeFoldable};
-use middle::ty::cast::{CastKind, CastTy};
+use hir::def_id::DefId;
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::cast::{CastKind, CastTy};
use syntax::codemap::Span;
-use rustc_front::hir;
+use rustc::hir;
use syntax::ast;
/// Reifies a cast check to be checked once we have full type information for
/// a function context.
pub struct CastCheck<'tcx> {
- expr: hir::Expr,
+ expr: &'tcx hir::Expr,
expr_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
span: Span,
CastToBool,
CastToChar,
DifferingKinds,
+ /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
+ SizedUnsizedCast,
IllegalCast,
NeedViaPtr,
NeedViaThinPtr,
}
impl<'tcx> CastCheck<'tcx> {
- pub fn new(expr: hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
+ pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
-> CastCheck<'tcx> {
CastCheck {
expr: expr,
CastError::NeedViaThinPtr => "a thin pointer",
CastError::NeedViaInt => "an integer",
CastError::NeedViaUsize => "a usize",
- _ => unreachable!()
+ _ => bug!()
}))
.emit();
}
fcx.infcx().ty_to_string(self.cast_ty))
}, self.expr_ty, None);
}
+ CastError::SizedUnsizedCast => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("cannot cast thin pointer `{}` to fat pointer `{}`",
+ actual,
+ fcx.infcx().ty_to_string(self.cast_ty))
+ }, self.expr_ty, None)
+ }
CastError::DifferingKinds => {
fcx.type_error_struct(self.span, |actual| {
format!("casting `{}` as `{}` is invalid",
/// 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::ty::cast::IntTy::*;
- use middle::ty::cast::CastTy::*;
+ use rustc::ty::cast::IntTy::*;
+ use rustc::ty::cast::CastTy::*;
let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty),
CastTy::from_ty(self.cast_ty)) {
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
+ // Function item types may need to be reified before casts.
+ (None, Some(t_cast)) => {
+ if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
+ // Attempt a coercion to a fn pointer type.
+ let res = coercion::try(fcx, self.expr,
+ fcx.tcx().mk_ty(ty::TyFnPtr(f)));
+ if !res.is_ok() {
+ return Err(CastError::NonScalar);
+ }
+ (FnPtr, t_cast)
+ } else {
+ return Err(CastError::NonScalar);
+ }
+ }
_ => {
return Err(CastError::NonScalar)
}
// sized -> unsized? report invalid cast (don't complain about vtable kinds)
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
- return Err(CastError::IllegalCast);
+ return Err(CastError::SizedUnsizedCast);
}
// vtable kinds must match
}
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
- }
+ coercion::try(fcx, self.expr, self.cast_ty).is_ok()
}
}