use syntax::ast;
-
+/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntTy {
U(ast::UintTy),
// 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>),
}
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)),
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,
}
}
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());
}
}
_ => {}
}
}
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())
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())
}
_ => {
}
}
- 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);
};
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),
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
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
}
}
}
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,
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)));
}
}
};}
}
- /// 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),
=> 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
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)
}
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)
}
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)
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.
// 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);
}
}
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)
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,
// 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);
}
}
}
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
}
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
// 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<_>`
// 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);
}
fn main() {
- (&5 as &Foo).foo();
+ (&5isize as &Foo).foo();
//~^ ERROR: no method named `foo` found for type `&Foo` in the current scope
}
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) {
--- /dev/null
+// 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);
+}
+++ /dev/null
-// 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);
-}
// 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 }
}