rollup merge of #23630: nrc/coerce-tidy

See notes on the first commit

Closes #18601

r? @nikomatsakis

cc @eddyb
This commit is contained in:
Alex Crichton 2015-03-24 14:50:46 -07:00
commit a1d2e62c1f
95 changed files with 592 additions and 620 deletions

View file

@ -429,7 +429,8 @@ impl<T> TypedArenaChunk<T> {
// Destroy the next chunk.
let next = self.next;
let size = calculate_size::<T>(self.capacity);
deallocate(self as *mut TypedArenaChunk<T> as *mut u8, size,
let self_ptr: *mut TypedArenaChunk<T> = self;
deallocate(self_ptr as *mut u8, size,
mem::min_align_of::<TypedArenaChunk<T>>());
if !next.is_null() {
let capacity = (*next).capacity;

View file

@ -24,6 +24,8 @@
html_playground_url = "http://play.rust-lang.org/")]
#![doc(test(no_crate_inject))]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
#![feature(alloc)]
#![feature(box_syntax)]
#![feature(box_patterns)]

View file

@ -1199,8 +1199,8 @@ impl<T: PartialEq> Vec<T> {
// Avoid bounds checks by using unsafe pointers.
let p = self.as_mut_ptr();
let mut r = 1;
let mut w = 1;
let mut r: usize = 1;
let mut w: usize = 1;
while r < ln {
let p_r = p.offset(r as isize);

View file

@ -713,7 +713,11 @@ impl<T> UnsafeCell<T> {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> *mut T { &self.value as *const T as *mut T }
pub fn get(&self) -> *mut T {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
&self.value as *const T as *mut T
}
/// Unwraps the value
///

View file

@ -833,6 +833,8 @@ impl<T> Pointer for *const T {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Pointer for *mut T {
fn fmt(&self, f: &mut Formatter) -> Result {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
Pointer::fmt(&(*self as *const T), f)
}
}
@ -840,6 +842,8 @@ impl<T> Pointer for *mut T {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Pointer for &'a T {
fn fmt(&self, f: &mut Formatter) -> Result {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
Pointer::fmt(&(*self as *const T), f)
}
}
@ -847,6 +851,8 @@ impl<'a, T> Pointer for &'a T {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Pointer for &'a mut T {
fn fmt(&self, f: &mut Formatter) -> Result {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
Pointer::fmt(&(&**self as *const T), f)
}
}

View file

@ -13,6 +13,7 @@
// FIXME: #6220 Implement floating point formatting
#![allow(unsigned_negation)]
#![allow(trivial_numeric_casts)]
use fmt;
use iter::IteratorExt;

View file

@ -182,6 +182,8 @@ mod impls {
}
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
let newlen = data.len() * ::$ty::BYTES as usize;
let ptr = data.as_ptr() as *const u8;
state.write(unsafe { slice::from_raw_parts(ptr, newlen) })

View file

@ -313,6 +313,8 @@ pub fn drop<T>(_x: T) { }
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
ptr::read(src as *const T as *const U)
}

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i16")]
#![allow(trivial_numeric_casts)]
int_module! { i16, 16 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i32")]
#![allow(trivial_numeric_casts)]
int_module! { i32, 32 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i64")]
#![allow(trivial_numeric_casts)]
int_module! { i64, 64 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i8")]
#![allow(trivial_numeric_casts)]
int_module! { i8, 8 }

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![doc(hidden)]
#![allow(trivial_numeric_casts)]
macro_rules! int_module { ($T:ty, $bits:expr) => (

View file

@ -16,6 +16,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "isize")]
#![allow(trivial_numeric_casts)]
#[cfg(target_pointer_width = "32")]
int_module! { isize, 32 }

View file

@ -14,6 +14,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
#![allow(trivial_numeric_casts)]
use self::wrapping::{OverflowingOps, WrappingOps};

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u16")]
#![allow(trivial_numeric_casts)]
uint_module! { u16, i16, 16 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u32")]
#![allow(trivial_numeric_casts)]
uint_module! { u32, i32, 32 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u64")]
#![allow(trivial_numeric_casts)]
uint_module! { u64, i64, 64 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u8")]
#![allow(trivial_numeric_casts)]
uint_module! { u8, i8, 8 }

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![doc(hidden)]
#![allow(trivial_numeric_casts)]
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (

View file

@ -16,5 +16,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "usize")]
#![allow(trivial_numeric_casts)]
uint_module! { usize, isize, ::isize::BITS }

View file

@ -529,7 +529,7 @@ impl<T: ?Sized> Unique<T> {
/// Create a new `Unique`.
#[unstable(feature = "unique")]
pub unsafe fn new(ptr: *mut T) -> Unique<T> {
Unique { pointer: NonZero::new(ptr as *const T), _marker: PhantomData }
Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
}
/// Dereference the content.

View file

@ -261,7 +261,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str {
reason = "use std::ffi::c_str_to_bytes + str::from_utf8")]
pub unsafe fn from_c_str(s: *const i8) -> &'static str {
let s = s as *const u8;
let mut len = 0;
let mut len: usize = 0;
while *s.offset(len as isize) != 0 {
len += 1;
}

View file

@ -95,7 +95,7 @@ fn test_transmute() {
trait Foo { fn dummy(&self) { } }
impl Foo for int {}
let a = box 100 as Box<Foo>;
let a = box 100isize as Box<Foo>;
unsafe {
let x: ::core::raw::TraitObject = transmute(a);
assert!(*(x.data as *const int) == 100);

View file

@ -84,9 +84,9 @@ fn test_as_ref() {
assert_eq!(q.as_ref().unwrap(), &2);
// Lifetime inference
let u = 2;
let u = 2isize;
{
let p: *const int = &u as *const _;
let p = &u as *const int;
assert_eq!(p.as_ref().unwrap(), &2);
}
}
@ -102,9 +102,9 @@ fn test_as_mut() {
assert!(q.as_mut().unwrap() == &mut 2);
// Lifetime inference
let mut u = 2;
let mut u = 2isize;
{
let p: *mut int = &mut u as *mut _;
let p = &mut u as *mut int;
assert!(p.as_mut().unwrap() == &mut 2);
}
}
@ -170,9 +170,9 @@ fn test_set_memory() {
#[test]
fn test_unsized_unique() {
let xs: &mut [_] = &mut [1, 2, 3];
let ptr = unsafe { Unique::new(xs as *mut [_]) };
let xs: &mut [i32] = &mut [1, 2, 3];
let ptr = unsafe { Unique::new(xs as *mut [i32]) };
let ys = unsafe { &mut **ptr };
let zs: &mut [_] = &mut [1, 2, 3];
let zs: &mut [i32] = &mut [1, 2, 3];
assert!(ys == zs);
}

View file

@ -304,10 +304,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
// Completely remove the local logger from TLS in case anyone attempts to
// frob the slot while we're doing the logging. This will destroy any logger
// set during logging.
let mut logger = LOCAL_LOGGER.with(|s| {
let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
s.borrow_mut().take()
}).unwrap_or_else(|| {
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
box DefaultLogger { handle: io::stderr() }
});
logger.log(&LogRecord {
level: LogLevel(level),

View file

@ -10,6 +10,8 @@
//! Generating numbers between two others.
#![allow(trivial_numeric_casts)]
// this is surprisingly complicated to be both generic & correct
use core::prelude::{PartialOrd};

View file

@ -447,6 +447,7 @@ impl Rng for Isaac64Rng {
#[inline]
fn next_u64(&mut self) -> u64 {
#![allow(trivial_numeric_casts)]
if self.cnt == 0 {
// make some more numbers
self.isaac64();

View file

@ -353,7 +353,7 @@ pub mod reader {
let (shift, mask) = SHIFT_MASK_TABLE[i];
Ok(Res {
val: ((val >> shift) & mask) as uint,
next: start + (((32 - shift) >> 3) as uint)
next: start + ((32 - shift) >> 3),
})
}
}
@ -573,7 +573,7 @@ pub mod reader {
0 => doc_as_u8(r_doc) as u64,
1 => doc_as_u16(r_doc) as u64,
2 => doc_as_u32(r_doc) as u64,
3 => doc_as_u64(r_doc) as u64,
3 => doc_as_u64(r_doc),
_ => unreachable!(),
}
} else {

View file

@ -47,6 +47,9 @@
#![feature(into_cow)]
#![cfg_attr(test, feature(test))]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
extern crate arena;
extern crate flate;
extern crate fmt_macros;

View file

@ -100,6 +100,17 @@ declare_lint! {
"detects transmutes of fat pointers"
}
declare_lint! {
pub TRIVIAL_CASTS,
Warn,
"detects trivial casts which could be removed"
}
declare_lint! {
pub TRIVIAL_NUMERIC_CASTS,
Warn,
"detects trivial casts of numeric types which could be removed"
}
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy)]
@ -121,7 +132,9 @@ impl LintPass for HardwiredLints {
STABLE_FEATURES,
UNKNOWN_CRATE_TYPES,
VARIANT_SIZE_DIFFERENCES,
FAT_PTR_TRANSMUTES
FAT_PTR_TRANSMUTES,
TRIVIAL_CASTS,
TRIVIAL_NUMERIC_CASTS
)
}
}

View file

@ -968,7 +968,7 @@ impl<'tcx> Eq for TyS<'tcx> {}
impl<'tcx> Hash for TyS<'tcx> {
fn hash<H: Hasher>(&self, s: &mut H) {
(self as *const _).hash(s)
(self as *const TyS).hash(s)
}
}
@ -2738,7 +2738,7 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
};
debug!("Interned type: {:?} Pointer: {:?}",
ty, ty as *const _);
ty, ty as *const TyS);
interner.insert(InternedTy { ty: ty }, ty);
@ -4823,32 +4823,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
RvalueDpsExpr
}
ast::ExprCast(..) => {
match tcx.node_types.borrow().get(&expr.id) {
Some(&ty) => {
if type_is_trait(ty) {
RvalueDpsExpr
} else {
RvalueDatumExpr
}
}
None => {
// Technically, it should not happen that the expr is not
// present within the table. However, it DOES happen
// during type check, because the final types from the
// expressions are not yet recorded in the tcx. At that
// time, though, we are only interested in knowing lvalue
// vs rvalue. It would be better to base this decision on
// the AST type in cast node---but (at the time of this
// writing) it's not easy to distinguish casts to traits
// from other casts based on the AST. This should be
// easier in the future, when casts to traits
// would like @Foo, Box<Foo>, or &Foo.
RvalueDatumExpr
}
}
}
ast::ExprBreak(..) |
ast::ExprAgain(..) |
ast::ExprRet(..) |
@ -4864,7 +4838,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprUnary(..) |
ast::ExprBox(None, _) |
ast::ExprAddrOf(..) |
ast::ExprBinary(..) => {
ast::ExprBinary(..) |
ast::ExprCast(..) => {
RvalueDatumExpr
}

View file

@ -84,30 +84,6 @@ impl LintPass for WhileTrue {
}
}
declare_lint! {
UNUSED_TYPECASTS,
Allow,
"detects unnecessary type casts that can be removed"
}
#[derive(Copy)]
pub struct UnusedCasts;
impl LintPass for UnusedCasts {
fn get_lints(&self) -> LintArray {
lint_array!(UNUSED_TYPECASTS)
}
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
if let ast::ExprCast(ref expr, ref ty) = e.node {
let t_t = ty::expr_ty(cx.tcx, e);
if ty::expr_ty(cx.tcx, &**expr) == t_t {
cx.span_lint(UNUSED_TYPECASTS, ty.span, "unnecessary type cast");
}
}
}
}
declare_lint! {
UNSIGNED_NEGATION,
Warn,
@ -1804,6 +1780,9 @@ impl LintPass for UnconditionalRecursion {
fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
blk: &ast::Block, sp: Span, id: ast::NodeId) {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
type F = for<'tcx> fn(&ty::ctxt<'tcx>,
ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;

View file

@ -56,7 +56,7 @@ pub use rustc::session as session;
pub use rustc::util as util;
use session::Session;
use lint::{LintPassObject, LintId};
use lint::LintId;
mod builtin;
@ -67,7 +67,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
macro_rules! add_builtin {
($sess:ident, $($name:ident),*,) => (
{$(
store.register_pass($sess, false, box builtin::$name as LintPassObject);
store.register_pass($sess, false, box builtin::$name);
)*}
)
}
@ -75,7 +75,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
macro_rules! add_builtin_with_new {
($sess:ident, $($name:ident),*,) => (
{$(
store.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
store.register_pass($sess, false, box builtin::$name::new());
)*}
)
}
@ -89,7 +89,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
add_builtin!(sess,
HardwiredLints,
WhileTrue,
UnusedCasts,
ImproperCTypes,
BoxPointers,
UnusedAttributes,
@ -129,7 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UNUSED_UNSAFE, PATH_STATEMENTS);
// We have one lint pass defined specially
store.register_pass(sess, false, box lint::GatherNodeLevels as LintPassObject);
store.register_pass(sess, false, box lint::GatherNodeLevels);
// Insert temporary renamings for a one-time deprecation
store.register_renamed("raw_pointer_deriving", "raw_pointer_derive");

View file

@ -14,6 +14,8 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
#![crate_name = "rustc_llvm"]
#![unstable(feature = "rustc_private")]

View file

@ -43,6 +43,9 @@
#![feature(convert)]
#![feature(path_relative_from)]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
extern crate arena;
extern crate flate;
extern crate getopts;

View file

@ -471,15 +471,6 @@ impl<'tcx> Datum<'tcx, Expr> {
})
}
/// Ensures that `self` will get cleaned up, if it is not an lvalue already.
pub fn clean<'blk>(self,
bcx: Block<'blk, 'tcx>,
name: &'static str,
expr_id: ast::NodeId)
-> Block<'blk, 'tcx> {
self.to_lvalue_datum(bcx, name, expr_id).bcx
}
pub fn to_lvalue_datum<'blk>(self,
bcx: Block<'blk, 'tcx>,
name: &str,

View file

@ -1227,22 +1227,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
vec![(idx_datum, idx.id)], Some(dest), true).bcx
}
ast::ExprCast(ref val, _) => {
// DPS output mode means this is a trait cast:
if ty::type_is_trait(node_id_type(bcx, expr.id)) {
let trait_ref =
bcx.tcx().object_cast_map.borrow()
.get(&expr.id)
.cloned()
.unwrap();
let trait_ref = bcx.monomorphize(&trait_ref);
let datum = unpack_datum!(bcx, trans(bcx, &**val));
meth::trans_trait_cast(bcx, datum, expr.id,
trait_ref, dest)
} else {
bcx.tcx().sess.span_bug(expr.span,
"expr_cast of non-trait");
}
ast::ExprCast(..) => {
// Trait casts used to come this way, now they should be coercions.
bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
}
ast::ExprAssignOp(op, ref dst, ref src) => {
trans_assign_op(bcx, expr, op, &**dst, &**src)
@ -2091,7 +2078,7 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let mut bcx = bcx;
let ccx = bcx.ccx();
let t_in = expr_ty(bcx, expr);
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);
@ -2103,7 +2090,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// by-value as appropriate given its type:
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
if cast_is_noop(datum.ty, t_out) {
let datum_ty = monomorphize_type(bcx, datum.ty);
if cast_is_noop(datum_ty, t_out) {
datum.ty = t_out;
return DatumBlock::new(bcx, datum);
}

View file

@ -28,7 +28,7 @@ use trans::common::*;
use trans::consts;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
use trans::expr::{SaveIn, Ignore};
use trans::expr::SaveIn;
use trans::expr;
use trans::glue;
use trans::machine;
@ -863,44 +863,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
.collect()
}
/// Generates the code to convert from a pointer (`Box<T>`, `&T`, etc) into an object
/// (`Box<Trait>`, `&Trait`, etc). This means creating a pair where the first word is the vtable
/// and the second word is the pointer.
pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
datum: Datum<'tcx, Expr>,
id: ast::NodeId,
trait_ref: ty::PolyTraitRef<'tcx>,
dest: expr::Dest)
-> Block<'blk, 'tcx> {
let mut bcx = bcx;
let _icx = push_ctxt("meth::trans_trait_cast");
let lldest = match dest {
Ignore => {
return datum.clean(bcx, "trait_trait_cast", id);
}
SaveIn(dest) => dest
};
debug!("trans_trait_cast: trait_ref={}",
trait_ref.repr(bcx.tcx()));
let llty = type_of(bcx.ccx(), datum.ty);
// Store the pointer into the first half of pair.
let llboxdest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]);
let llboxdest = PointerCast(bcx, llboxdest, llty.ptr_to());
bcx = datum.store_to(bcx, llboxdest);
// Store the vtable into the second half of pair.
let vtable = get_vtable(bcx.ccx(), trait_ref, bcx.fcx.param_substs);
let llvtabledest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]);
let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to());
Store(bcx, vtable, llvtabledest);
bcx
}
/// Replace the self type (&Self or Box<Self>) with an opaque pointer.
pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-> &'tcx ty::BareFnTy<'tcx> {

View file

@ -258,70 +258,64 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match (&a.sty, &b.sty) {
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
self.unpack_actual_value(t_a, |a| {
match self.unsize_ty(t_a, a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
let coercion = Coercion(self.trace.clone());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
match self.unsize_ty(t_a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
_ => Err(ty::terr_mismatch)
let coercion = Coercion(self.trace.clone());
let r_borrow = self.fcx.infcx().next_region_var(coercion);
let ty = ty::mk_rptr(self.tcx(),
self.tcx().mk_region(r_borrow),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
}
})
_ => Err(ty::terr_mismatch)
}
}
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
self.unpack_actual_value(t_a, |a| {
match self.unsize_ty(t_a, a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
match self.unsize_ty(t_a, mt_b.ty) {
Some((ty, kind)) => {
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
return Err(ty::terr_mutability);
}
_ => Err(ty::terr_mismatch)
let ty = ty::mk_ptr(self.tcx(),
ty::mt{ty: ty, mutbl: mt_b.mutbl});
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
Some(box AutoUnsize(kind))))
})))
}
})
_ => Err(ty::terr_mismatch)
}
}
(&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
self.unpack_actual_value(t_a, |a| {
match self.unsize_ty(t_a, a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsizeUniq(kind))
})))
}
_ => Err(ty::terr_mismatch)
match self.unsize_ty(t_a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.tcx(), ty);
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AdjustDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(ty::AutoUnsizeUniq(kind))
})))
}
})
_ => Err(ty::terr_mismatch)
}
}
_ => Err(ty::terr_mismatch)
}
@ -332,113 +326,112 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
fn unsize_ty(&self,
ty_a: Ty<'tcx>,
a: Ty<'tcx>,
ty_b: Ty<'tcx>)
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx()));
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)>
{
let tcx = self.tcx();
self.unpack_actual_value(ty_b, |b|
match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None);
Some((ty, ty::UnsizeLength(len)))
}
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
//
// Note that neither of these changes requires any
// change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
// #2 (region bounds).
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
// construct a type `a1` which is a version of
// `a` using the upcast bounds from `b`
let bounds_a1 = ty::ExistentialBounds {
// From type b
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
// From type a
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
let result = self.fcx.infcx().try(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
try!(self.outlives(data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
// if that was successful, we have a coercion
match result {
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
Err(_) => None,
}
} else {
None
self.unpack_actual_value(ty_a, |a| {
self.unpack_actual_value(ty_b, |b| {
debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None);
Some((ty, ty::UnsizeLength(len)))
}
}
(_, &ty::ty_trait(ref data)) => {
Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(),
bounds: data.bounds.clone() },
ty_a)))
}
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
if did_a == did_b => {
debug!("unsizing a struct");
// Try unsizing each type param in turn to see if we end up with ty_b.
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
assert!(ty_substs_a.len() == ty_substs_b.len());
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
//
// Note that neither of these changes requires any
// change at runtime. Eventually this will be
// generalized.
//
// We always upcast when we can because of reason
// #2 (region bounds).
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
// construct a type `a1` which is a version of
// `a` using the upcast bounds from `b`
let bounds_a1 = ty::ExistentialBounds {
// From type b
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
continue;
// From type a
projection_bounds: data_a.bounds.projection_bounds.clone(),
};
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
// relate `a1` to `b`
let result = self.fcx.infcx().try(|_| {
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
try!(self.outlives(data_a.bounds.region_bound,
data_b.bounds.region_bound));
self.subtype(ty_a1, ty_b)
});
// if that was successful, we have a coercion
match result {
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
Err(_) => None,
}
} else {
None
}
match
self.unpack_actual_value(
*tp_a,
|tp| self.unsize_ty(*tp_a, tp, *tp_b))
{
Some((new_tp, k)) => {
// Check that the whole types match.
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
ppaux::ty_to_string(tcx, ty),
ppaux::ty_to_string(tcx, ty_b));
// We can only unsize a single type parameter, so
// if we unsize one and it doesn't give us the
// type we want, then we won't succeed later.
}
(_, &ty::ty_trait(ref data)) => {
Some((ty_b, ty::UnsizeVtable(ty::TyTrait {
principal: data.principal.clone(),
bounds: data.bounds.clone()
},
ty_a)))
}
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
if did_a == did_b => {
debug!("unsizing a struct");
// Try unsizing each type param in turn to see if we end up with ty_b.
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
assert!(ty_substs_a.len() == ty_substs_b.len());
let mut result = None;
let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
for (i, (tp_a, tp_b)) in tps {
if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() {
continue;
}
match self.unsize_ty(*tp_a, *tp_b) {
Some((new_tp, k)) => {
// Check that the whole types match.
let mut new_substs = substs_a.clone();
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs));
if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() {
debug!("Unsized type parameter '{}', but still \
could not match types {} and {}",
ppaux::ty_to_string(tcx, *tp_a),
ppaux::ty_to_string(tcx, ty),
ppaux::ty_to_string(tcx, ty_b));
// We can only unsize a single type parameter, so
// if we unsize one and it doesn't give us the
// type we want, then we won't succeed later.
break;
}
result = Some((ty, ty::UnsizeStruct(box k, i)));
break;
}
result = Some((ty, ty::UnsizeStruct(box k, i)));
break;
None => {}
}
None => {}
}
result
}
result
_ => None
}
_ => None
}
)
})
})
}
fn coerce_from_fn_pointer(&self,

View file

@ -53,9 +53,11 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
}
}
// Checks that the type `actual` can be coerced to `expected`.
pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
expected: Ty<'tcx>, expr: &ast::Expr) {
// Checks that the type of `expr` can be coerced to `expected`.
pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
expected: Ty<'tcx>,
expr: &ast::Expr) {
let expr_ty = fcx.expr_ty(expr);
debug!("demand::coerce(expected = {}, expr_ty = {})",
expected.repr(fcx.ccx.tcx),

View file

@ -184,6 +184,8 @@ pub struct Inherited<'a, 'tcx: 'a> {
// def-id of the closure, so that once we decide, we can easily go
// back and process them.
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
deferred_cast_checks: RefCell<Vec<CastCheck<'tcx>>>,
}
trait DeferredCallResolution<'tcx> {
@ -192,6 +194,15 @@ trait DeferredCallResolution<'tcx> {
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx>;
/// Reifies a cast check to be checked once we have full type information for
/// a function context.
struct CastCheck<'tcx> {
expr: ast::Expr,
expr_ty: Ty<'tcx>,
cast_ty: Ty<'tcx>,
span: Span,
}
/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
#[derive(Copy)]
@ -399,6 +410,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
fn_sig_map: RefCell::new(NodeMap()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
}
}
@ -508,6 +520,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vtable::select_all_fcx_obligations_and_apply_defaults(&fcx);
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
vtable::select_all_fcx_obligations_or_error(&fcx);
fcx.check_casts();
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
}
@ -1053,11 +1066,7 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
t_1: Ty<'tcx>,
t_e: Ty<'tcx>,
e: &ast::Expr) {
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>,
@ -1070,6 +1079,33 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}, 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);
// 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) {
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
e.id,
span,
format!("trivial numeric cast: `{}` as `{}`",
fcx.infcx().ty_to_string(t_e),
fcx.infcx().ty_to_string(t_1)));
} else {
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
e.id,
span,
format!("trivial cast: `{}` as `{}`",
fcx.infcx().ty_to_string(t_e),
fcx.infcx().ty_to_string(t_1)));
}
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);
@ -1085,18 +1121,17 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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);
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)
format!("only `u8` can be cast as `char`, not `{}`", actual)
}, t_e, None);
}
} else if t_1.sty == ty::ty_bool {
span_err!(fcx.tcx().sess, span, E0054,
"cannot cast as `bool`, compare with zero instead");
"cannot cast as `bool`, compare with zero instead");
} 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
@ -1145,7 +1180,7 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
/* this case is allowed */
}
_ => {
demand::coerce(fcx, e.span, t_1, &*e);
demand::coerce(fcx, e.span, t_1, &e);
}
}
} else if !(t_e_is_scalar && t_1_is_trivial) {
@ -1162,49 +1197,6 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
}
fn check_cast<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
cast_expr: &ast::Expr,
e: &'tcx ast::Expr,
t: &ast::Ty) {
let id = cast_expr.id;
let span = cast_expr.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, span, t_1);
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
let t_e = fcx.expr_ty(e);
debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
if ty::type_is_error(t_e) {
fcx.write_error(id);
return
}
if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
report_cast_to_unsized_type(fcx, span, t.span, e.span, t_1, t_e, id);
return
}
if ty::type_is_trait(t_1) {
// This will be looked up later on.
vtable::check_object_cast(fcx, cast_expr, e, t_1);
fcx.write_ty(id, t_1);
return
}
let t_1 = structurally_resolved_type(fcx, span, t_1);
let t_e = structurally_resolved_type(fcx, span, t_e);
check_cast_inner(fcx, span, t_1, t_e, e);
fcx.write_ty(id, t_1);
}
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
@ -1372,7 +1364,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
pub fn tag(&self) -> String {
format!("{:?}", self as *const FnCtxt)
let self_ptr: *const FnCtxt = self;
format!("{:?}", self_ptr)
}
pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> {
@ -1416,14 +1409,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.inh.node_types.borrow_mut().insert(node_id, ty);
}
pub fn write_object_cast(&self,
key: ast::NodeId,
trait_ref: ty::PolyTraitRef<'tcx>) {
debug!("write_object_cast key={} trait_ref={}",
key, trait_ref.repr(self.tcx()));
self.inh.object_cast_map.borrow_mut().insert(key, trait_ref);
}
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
if !substs.substs.is_noop() {
debug!("write_substs({}, {}) in fcx {}",
@ -1923,6 +1908,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs))
.map(|t| self.normalize_associated_types_in(span, &t))
}
fn check_casts(&self) {
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
for check in deferred_cast_checks.iter() {
check_cast(self, check);
}
deferred_cast_checks.clear();
}
}
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
@ -3828,7 +3822,33 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
if let ast::TyFixedLengthVec(_, ref count_expr) = t.node {
check_expr_with_hint(fcx, &**count_expr, tcx.types.uint);
}
check_cast(fcx, expr, &**e, &**t);
// 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);
// Eagerly check for some obvious errors.
if ty::type_is_error(t_e) {
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 {
// Write a type for the whole expression, assuming everything is going
// to work out Ok.
fcx.write_ty(id, t_1);
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
deferred_cast_checks.push(CastCheck {
expr: (**e).clone(),
expr_ty: t_e,
cast_ty: t_1,
span: expr.span,
});
}
}
ast::ExprVec(ref args) => {
let uty = expected.to_option(fcx).and_then(|uty| {
@ -4461,6 +4481,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
check_expr_with_hint(fcx, e, declty);
demand::coerce(fcx, e.span, declty, e);
vtable::select_all_fcx_obligations_or_error(fcx);
fcx.check_casts();
regionck::regionck_expr(fcx, e);
writeback::resolve_type_vars_in_expr(fcx, e);
}
@ -4560,6 +4581,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
ty: attr::IntType,
disr: ty::Disr) -> bool {
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
#![allow(trivial_numeric_casts)]
match ty {
ast::TyU8 => disr as u8 as Disr == disr,
ast::TyU16 => disr as u16 as Disr == disr,
@ -4588,6 +4611,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
id: ast::NodeId,
hint: attr::ReprAttr)
-> Vec<Rc<ty::VariantInfo<'tcx>>> {
#![allow(trivial_numeric_casts)]
use std::num::Int;
let rty = ty::node_id_to_type(ccx.tcx, id);

View file

@ -9,7 +9,6 @@
// except according to those terms.
use check::{FnCtxt};
use check::demand;
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;
@ -19,83 +18,6 @@ use syntax::codemap::Span;
use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString};
pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
cast_expr: &ast::Expr,
source_expr: &ast::Expr,
target_object_ty: Ty<'tcx>)
{
let tcx = fcx.tcx();
debug!("check_object_cast(cast_expr={}, target_object_ty={})",
cast_expr.repr(tcx),
target_object_ty.repr(tcx));
// Look up vtables for the type we're casting to,
// passing in the source and target type. The source
// must be a pointer type suitable to the object sigil,
// e.g.: `&x as &Trait` or `box x as Box<Trait>`
// First, construct a fresh type that we can feed into `<expr>`
// within `<expr> as <type>` to inform type inference (e.g. to
// tell it that we are expecting a `Box<_>` or an `&_`).
let fresh_ty = fcx.infcx().next_ty_var();
let (object_trait_ty, source_expected_ty) = match target_object_ty.sty {
ty::ty_uniq(object_trait_ty) => {
(object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty))
}
ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
mutbl: target_mutbl }) => {
(object_trait_ty,
ty::mk_rptr(fcx.tcx(),
target_region, ty::mt { ty: fresh_ty,
mutbl: target_mutbl }))
}
_ => {
fcx.tcx().sess.span_bug(source_expr.span, "expected object type");
}
};
let source_ty = fcx.expr_ty(source_expr);
debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx));
// This ensures that the source_ty <: source_expected_ty, which
// will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait`
//
// FIXME (pnkfelix): do we need to use suptype_with_fn in order to
// override the error message emitted when the types do not work
// out in the manner desired?
demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);
debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));
let object_trait = object_trait(&object_trait_ty);
// Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
push_cast_obligation(fcx, cast_expr, object_trait, fresh_ty);
check_object_safety(tcx, object_trait, source_expr.span);
fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
match t.sty {
ty::ty_trait(ref ty_trait) => &**ty_trait,
_ => panic!("expected ty_trait")
}
}
fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
cast_expr: &ast::Expr,
object_trait: &ty::TyTrait<'tcx>,
referent_ty: Ty<'tcx>) {
let object_trait_ref =
register_object_cast_obligations(fcx,
cast_expr.span,
object_trait,
referent_ty);
// Finally record the object_trait_ref for use during trans
// (it would prob be better not to do this, but it's just kind
// of a pain to have to reconstruct it).
fcx.write_object_cast(cast_expr.id, object_trait_ref);
}
}
// Check that a trait is 'object-safe'. This should be checked whenever a trait object
// is created (by casting or coercion, etc.). A trait is object-safe if all its

View file

@ -308,8 +308,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
};
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= &mut opaque as *mut _ as *mut libc::c_void;
(*renderer).blockcode = Some(block as blockcodefn);
(*renderer).header = Some(header as headerfn);
(*renderer).blockcode = Some(block);
(*renderer).header = Some(header);
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, s.as_ptr(),
@ -380,8 +380,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT);
let renderer = hoedown_html_renderer_new(0, 0);
(*renderer).blockcode = Some(block as blockcodefn);
(*renderer).header = Some(header as headerfn);
(*renderer).blockcode = Some(block);
(*renderer).header = Some(header);
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= tests as *mut _ as *mut libc::c_void;
@ -501,10 +501,10 @@ pub fn plain_summary_line(md: &str) -> String {
unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT);
let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed();
let renderer = &mut plain_renderer as *mut hoedown_renderer;
let renderer: *mut hoedown_renderer = &mut plain_renderer;
(*renderer).opaque = ob as *mut libc::c_void;
(*renderer).link = Some(link as linkfn);
(*renderer).normal_text = Some(normal_text as normaltextfn);
(*renderer).link = Some(link);
(*renderer).normal_text = Some(normal_text);
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, md.as_ptr(),

View file

@ -2429,7 +2429,10 @@ pub trait ToJson {
macro_rules! to_json_impl_i64 {
($($t:ty), +) => (
$(impl ToJson for $t {
fn to_json(&self) -> Json { Json::I64(*self as i64) }
fn to_json(&self) -> Json {
#![allow(trivial_numeric_casts)]
Json::I64(*self as i64)
}
})+
)
}
@ -2439,7 +2442,10 @@ to_json_impl_i64! { int, i8, i16, i32, i64 }
macro_rules! to_json_impl_u64 {
($($t:ty), +) => (
$(impl ToJson for $t {
fn to_json(&self) -> Json { Json::U64(*self as u64) }
fn to_json(&self) -> Json {
#![allow(trivial_numeric_casts)]
Json::U64(*self as u64)
}
})+
)
}

View file

@ -135,6 +135,8 @@
#![feature(no_std)]
#![no_std]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
#![deny(missing_docs)]
#[cfg(test)] extern crate test;

View file

@ -337,10 +337,10 @@ pub fn set_stderr(_stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
// })
// })
fn with_task_stdout<F>(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> {
let mut my_stdout = LOCAL_STDOUT.with(|slot| {
let mut my_stdout: Box<Writer + Send> = LOCAL_STDOUT.with(|slot| {
slot.borrow_mut().take()
}).unwrap_or_else(|| {
box stdout() as Box<Writer + Send>
box stdout()
});
let result = f(&mut *my_stdout);
let mut var = Some(my_stdout);

View file

@ -68,7 +68,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
use thread::Thread;
let something_around_the_top_of_the_stack = 1;
let addr = &something_around_the_top_of_the_stack as *const int;
let addr = &something_around_the_top_of_the_stack as *const _ as *const int;
let my_stack_top = addr as uint;
// FIXME #11359 we just assume that this thread has a stack of a

View file

@ -109,7 +109,7 @@ impl Iterator for Env {
if *self.cur == 0 { return None }
let p = &*self.cur;
let mut len = 0;
while *(p as *const _).offset(len) != 0 {
while *(p as *const u16).offset(len) != 0 {
len += 1;
}
let p = p as *const u16;

View file

@ -176,6 +176,7 @@ macro_rules! __thread_local_inner {
}
};
#[allow(trivial_casts)]
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
::std::thread::__local::__impl::KeyInner {

View file

@ -284,7 +284,7 @@ pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(-2);
impl ExpnId {
pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
ExpnId(cookie as u32)
ExpnId(cookie)
}
pub fn to_llvm_cookie(self) -> i32 {
@ -376,7 +376,7 @@ impl Encodable for FileMap {
match bytes_per_diff {
1 => for diff in diff_iter { try! { (diff.0 as u8).encode(s) } },
2 => for diff in diff_iter { try! { (diff.0 as u16).encode(s) } },
4 => for diff in diff_iter { try! { (diff.0 as u32).encode(s) } },
4 => for diff in diff_iter { try! { diff.0.encode(s) } },
_ => unreachable!()
}
}
@ -650,7 +650,7 @@ impl CodeMap {
let lo = self.lookup_char_pos(sp.lo);
let hi = self.lookup_char_pos(sp.hi);
let mut lines = Vec::new();
for i in lo.line - 1..hi.line as usize {
for i in lo.line - 1..hi.line {
lines.push(i);
};
FileLines {file: lo.file, lines: lines}

View file

@ -264,7 +264,7 @@ macro_rules! make_MacEager {
box MacEager {
$fld: Some(v),
..Default::default()
} as Box<MacResult>
}
}
)*
}
@ -330,7 +330,7 @@ impl DummyResult {
/// Use this as a return value after hitting any errors and
/// calling `span_err`.
pub fn any(sp: Span) -> Box<MacResult+'static> {
box DummyResult { expr_only: false, span: sp } as Box<MacResult+'static>
box DummyResult { expr_only: false, span: sp }
}
/// Create a default MacResult that can only be an expression.
@ -339,7 +339,7 @@ impl DummyResult {
/// if an error is encountered internally, the user will receive
/// an error that they also used it in the wrong place.
pub fn expr(sp: Span) -> Box<MacResult+'static> {
box DummyResult { expr_only: true, span: sp } as Box<MacResult+'static>
box DummyResult { expr_only: true, span: sp }
}
/// A plain dummy expression.

View file

@ -262,6 +262,7 @@ pub mod rt {
(unsigned, $t:ty, $tag:expr) => (
impl ToSource for $t {
fn to_source(&self) -> String {
#![allow(trivial_numeric_casts)]
let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
pprust::lit_to_string(&dummy_spanned(lit))
}

View file

@ -169,7 +169,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
// Weird, but useful for X-macros.
return box ParserAnyMacro {
parser: RefCell::new(p),
} as Box<MacResult+'cx>
}
}
Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
best_fail_spot = sp;

View file

@ -758,7 +758,7 @@ impl<'a> StringReader<'a> {
self.err_span_char(self.last_pos, self.pos,
"illegal character in numeric character escape", c);
0
}) as u32;
});
self.bump();
}
@ -887,7 +887,7 @@ impl<'a> StringReader<'a> {
self.fatal_span_char(self.last_pos, self.pos,
"illegal character in unicode escape", c);
}
}) as u32;
});
self.bump();
count += 1;
}

View file

@ -865,7 +865,7 @@ impl<'a> Parser<'a> {
} else {
// Avoid token copies with `replace`.
let buffer_start = self.buffer_start as usize;
let next_index = (buffer_start + 1) & 3 as usize;
let next_index = (buffer_start + 1) & 3;
self.buffer_start = next_index as isize;
let placeholder = TokenAndSpan {

View file

@ -2831,7 +2831,7 @@ impl<'a> State<'a> {
ast::LitBinary(ref v) => {
let mut escaped: String = String::new();
for &ch in &**v {
escaped.extend(ascii::escape_default(ch as u8)
escaped.extend(ascii::escape_default(ch)
.map(|c| c as char));
}
word(&mut self.s, &format!("b\"{}\"", escaped))

View file

@ -103,7 +103,7 @@ impl Write for WriterWrapper {
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Write + Send>,
wrapped: box std::io::stdout(),
})
}
@ -112,14 +112,14 @@ pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Write + Send>,
wrapped: box std::io::stdout(),
});
match ti {
Some(t) => Some(t),
None => {
WinConsole::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Write + Send>,
wrapped: box std::io::stdout(),
})
}
}
@ -130,7 +130,7 @@ pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Write + Send>,
wrapped: box std::io::stderr(),
})
}
@ -139,14 +139,14 @@ pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Write + Send>,
wrapped: box std::io::stderr(),
});
match ti {
Some(t) => Some(t),
None => {
WinConsole::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Write + Send>,
wrapped: box std::io::stderr(),
})
}
}

View file

@ -190,7 +190,7 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
out: out,
ti: msys_terminfo(),
num_colors: 8,
} as Box<Terminal<T>+Send>)
})
},
_ => {
debug!("error finding terminfo entry: {:?}", err);
@ -213,7 +213,7 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
return Some(box TerminfoTerminal {out: out,
ti: inf,
num_colors: nc} as Box<Terminal<T>+Send>);
num_colors: nc});
}
fn dim_if_necessary(&self, color: color::Color) -> color::Color {

View file

@ -186,7 +186,7 @@ pub fn parse(file: &mut Read, longnames: bool)
let magic = try!(read_le_u16(file));
if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x}, found {:x}",
0x011A as usize, magic as usize));
0x011A_usize, magic as usize));
}
let names_bytes = try!(read_le_u16(file)) as int;

View file

@ -126,7 +126,7 @@ impl<T: Write+Send+'static> WinConsole<T> {
}
Some(box WinConsole { buf: out,
def_foreground: fg, def_background: bg,
foreground: fg, background: bg } as Box<Terminal<T>+Send>)
foreground: fg, background: bg })
}
}

View file

@ -1021,7 +1021,7 @@ impl MetricMap {
let MetricMap(ref mm) = *self;
let v : Vec<String> = mm.iter()
.map(|(k,v)| format!("{}: {} (+/- {})", *k,
v.value as f64, v.noise as f64))
v.value, v.noise))
.collect();
v.connect(", ")
}

View file

@ -32,11 +32,11 @@ pub trait Subcommand {
/// Create a Subcommand object based on its name.
pub fn parse_name(name: &str) -> Option<Box<Subcommand>> {
for parser in [
help::parse_cmd as fn(&str) -> Option<Box<Subcommand>>,
build::parse_cmd as fn(&str) -> Option<Box<Subcommand>>,
serve::parse_cmd as fn(&str) -> Option<Box<Subcommand>>,
test::parse_cmd as fn(&str) -> Option<Box<Subcommand>>].iter() {
let cmds: [fn(&str) -> Option<Box<Subcommand>>; 4] = [help::parse_cmd,
build::parse_cmd,
serve::parse_cmd,
test::parse_cmd];
for parser in cmds.iter() {
let parsed = (*parser)(name);
if parsed.is_some() { return parsed }
}

View file

@ -21,6 +21,6 @@ mod inner {
}
pub fn foo() {
let a = &1 as &inner::Trait;
let a = &1i as &inner::Trait;
a.f();
}

View file

@ -22,11 +22,11 @@ fn main() {
//~| expected u8
//~| found array of 1 elements
let local = [0];
let local: [u8; 1] = [0];
let _v = &local as *mut u8;
//~^ ERROR mismatched types
//~| expected `*mut u8`
//~| found `&[_; 1]`
//~| found `&[u8; 1]`
//~| expected u8,
//~| found array of 1 elements
}

View file

@ -19,8 +19,7 @@ mod Y {
}
static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
//~^ ERROR cannot refer to other statics by value
//~| ERROR the trait `core::marker::Sync` is not implemented for the type
//~^ ERROR the trait `core::marker::Sync` is not implemented for the type
//~| ERROR function calls in statics are limited to struct and enum constructors
fn main() {}

View file

@ -1,19 +0,0 @@
// Copyright 2014 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.
trait Foo { fn foo(&self) {} }
impl Foo for u8 {}
fn main() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
let r: Box<Foo> = Box::new(5);
let _m: Box<Foo> = r as Box<Foo>;
//~^ ERROR `core::marker::Sized` is not implemented for the type `Foo`
}

View file

@ -28,6 +28,7 @@ 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) {

View file

@ -86,6 +86,6 @@ mod inner {
}
pub fn foo() {
let a = &1 as &inner::Trait;
let a: &inner::Trait = &1_isize;
a.f();
}

View file

@ -1,24 +0,0 @@
// Copyright 2013 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.
#![forbid(unused_typecasts)]
fn foo_i32(_: i32) {}
fn foo_u64(a: u64) {
let b: i32 = a as i32;
foo_i32(b as i32); //~ ERROR: unnecessary type cast
}
fn main() {
let x: u64 = 1;
let y: u64 = x as u64; //~ ERROR: unnecessary type cast
foo_u64(y as u64); //~ ERROR: unnecessary type cast
}

View file

@ -10,7 +10,7 @@
#![deny(unused_variables)]
#![deny(unused_assignments)]
#![allow(dead_code, non_camel_case_types)]
#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)]
fn f1(x: isize) {
//~^ ERROR unused variable: `x`

View file

@ -12,6 +12,7 @@
#![feature(rustc_attrs)]
#![allow(dead_code)]
#![allow(trivial_casts)]
trait Bar {
fn bar(self);

View file

@ -24,6 +24,7 @@ impl<'a, T> X for B<'a, T> {}
fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR the parameter type `T` may not live long enough
//~^ ERROR the parameter type `T` may not live long enough
}
fn main() {}

View file

@ -19,6 +19,7 @@ trait SomeTrait { fn get(&self) -> isize; }
fn make_object1<A:SomeTrait>(v: A) -> Box<SomeTrait+'static> {
box v as Box<SomeTrait+'static>
//~^ ERROR the parameter type `A` may not live long enough
//~^^ ERROR the parameter type `A` may not live long enough
}
fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'a> {
@ -28,6 +29,7 @@ fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'a> {
fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'b> {
box v as Box<SomeTrait+'b>
//~^ ERROR the parameter type `A` may not live long enough
//~^^ ERROR the parameter type `A` may not live long enough
}
fn main() { }

View file

@ -0,0 +1,94 @@
// 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.
// Test the trivial_casts and trivial_numeric_casts lints. For each error we also
// check that the cast can be done using just coercion.
#![deny(trivial_casts, trivial_numeric_casts)]
trait Foo {
fn foo(&self) {}
}
pub struct Bar;
impl Foo for Bar {}
pub fn main() {
// Numeric
let _ = 42_i32 as i32; //~ ERROR trivial numeric cast: `i32` as `i32`
let _: i32 = 42_i32;
let _ = 42_u8 as u8; //~ ERROR trivial numeric cast: `u8` as `u8`
let _: u8 = 42_u8;
// & to * pointers
let x: &u32 = &42;
let _ = x as *const u32; //~ERROR trivial cast: `&u32` as `*const u32`
let _: *const u32 = x;
let x: &mut u32 = &mut 42;
let _ = x as *mut u32; //~ERROR trivial cast: `&mut u32` as `*mut u32`
let _: *mut u32 = x;
// unsize array
let x: &[u32; 3] = &[42, 43, 44];
let _ = x as &[u32]; //~ERROR trivial cast: `&[u32; 3]` as `&[u32]`
let _ = x as *const [u32]; //~ERROR trivial cast: `&[u32; 3]` as `*const [u32]`
let _: &[u32] = x;
let _: *const [u32] = x;
let x: &mut [u32; 3] = &mut [42, 43, 44];
let _ = x as &mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `&mut [u32]`
let _ = x as *mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `*mut [u32]`
let _: &mut [u32] = x;
let _: *mut [u32] = x;
let x: Box<[u32; 3]> = Box::new([42, 43, 44]);
let _ = x as Box<[u32]>; //~ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>`
let x: Box<[u32; 3]> = Box::new([42, 43, 44]);
let _: Box<[u32]> = x;
// unsize trait
let x: &Bar = &Bar;
let _ = x as &Foo; //~ERROR trivial cast: `&Bar` as `&Foo`
let _ = x as *const Foo; //~ERROR trivial cast: `&Bar` as `*const Foo`
let _: &Foo = x;
let _: *const Foo = x;
let x: &mut Bar = &mut Bar;
let _ = x as &mut Foo; //~ERROR trivial cast: `&mut Bar` as `&mut Foo`
let _ = x as *mut Foo; //~ERROR trivial cast: `&mut Bar` as `*mut Foo`
let _: &mut Foo = x;
let _: *mut Foo = x;
let x: Box<Bar> = Box::new(Bar);
let _ = x as Box<Foo>; //~ERROR trivial cast: `Box<Bar>` as `Box<Foo>`
let x: Box<Bar> = Box::new(Bar);
let _: Box<Foo> = x;
// functions
fn baz(_x: i32) {}
let _ = &baz as &Fn(i32); //~ERROR trivial cast: `&fn(i32) {main::baz}` as `&core::ops::Fn(i32)`
let _: &Fn(i32) = &baz;
let x = |_x: i32| {};
let _ = &x as &Fn(i32); //~ERROR trivial cast
let _: &Fn(i32) = &x;
}
// subtyping
pub fn test_subtyping<'a, 'b: 'a>(a: &'a Bar, b: &'b Bar) {
let _ = a as &'a Bar; //~ERROR trivial cast
let _: &'a Bar = a;
let _ = b as &'a Bar; //~ERROR trivial cast
let _: &'a Bar = b;
let _ = b as &'b Bar; //~ERROR trivial cast
let _: &'b Bar = b;
}

View file

@ -20,7 +20,7 @@ impl MyAdd for i32 {
}
fn main() {
let x = 5;
let x: i32 = 5;
let y = x as MyAdd<i32>;
//~^ ERROR as `MyAdd<i32>`
}

View file

@ -10,6 +10,8 @@
// Issue #14893. Tests that casts from vectors don't behave strangely in the
// presence of the `_` type shorthand notation.
// Update: after a change to the way casts are done, we have more type information
// around and so the errors here are no longer exactly the same.
struct X {
y: [u8; 2],
@ -18,12 +20,14 @@ struct X {
fn main() {
let x1 = X { y: [0, 0] };
let p1: *const u8 = &x1.y as *const _; //~ ERROR mismatched types
// No longer a type mismatch - the `_` can be fully resolved by type inference.
let p1: *const u8 = &x1.y as *const _;
let t1: *const [u8; 2] = &x1.y as *const _;
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
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 t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];

View file

@ -291,15 +291,15 @@ fn main() {
let slice2 = &*vec2;
// Trait Objects
let box_trait = (box 0) as Box<Trait1>;
let ref_trait = &0 as &Trait1;
let mut mut_int1 = 0;
let box_trait = (box 0_isize) as Box<Trait1>;
let ref_trait = &0_isize as &Trait1;
let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
let generic_box_trait = (box 0) as Box<Trait2<i32, Mod1::Struct2>>;
let generic_ref_trait = (&0) as &Trait2<Struct1, Struct1>;
let generic_box_trait = (box 0_isize) as Box<Trait2<i32, Mod1::Struct2>>;
let generic_ref_trait = (&0_isize) as &Trait2<Struct1, Struct1>;
let mut generic_mut_ref_trait_impl = 0;
let mut generic_mut_ref_trait_impl = 0_isize;
let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
&mut Trait2<Mod1::Mod2::Struct3, GenericStruct<usize, isize>>;

View file

@ -21,5 +21,5 @@ fn foo<'a>(x: Box<Tr+ Sync + 'a>) -> Box<Tr+ Sync + 'a> { x }
fn main() {
let x: Box<Tr+ Sync>;
Box::new(1) as Box<Tr+ Sync>;
Box::new(1isize) as Box<Tr+ Sync>;
}

View file

@ -16,5 +16,5 @@ impl Foo for uint {}
pub fn dummy() {
// force the vtable to be created
let _x = &1 as &Foo;
let _x = &1u as &Foo;
}

View file

@ -22,6 +22,6 @@ impl double for uint {
}
pub fn main() {
let x: Box<_> = box() (box 3 as Box<double>);
let x: Box<_> = box() (box 3u as Box<double>);
assert_eq!(x.double(), 6);
}

View file

@ -9,6 +9,6 @@
// except according to those terms.
pub fn main() {
let x = 3;
let x: int = 3;
println!("&x={:x}", (&x as *const int as uint));
}

View file

@ -1,61 +0,0 @@
// 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.
// Given `<expr> as Box<Trait>`, we should be able to infer that a
// `Box<_>` is the expected type.
// pretty-expanded FIXME #23616
trait Foo { fn foo(&self) -> u32; }
impl Foo for u32 { fn foo(&self) -> u32 { *self } }
// (another impl to ensure trait-matching cannot just choose from a singleton set)
impl Foo for () { fn foo(&self) -> u32 { -176 } }
trait Boxed { fn make() -> Self; }
impl Boxed for Box<u32> { fn make() -> Self { Box::new(7) } }
// (another impl to ensure trait-matching cannot just choose from a singleton set)
impl Boxed for () { fn make() -> Self { () } }
fn boxed_foo() {
let b7 = Boxed::make() as Box<Foo>;
assert_eq!(b7.foo(), 7);
}
trait Refed<'a,T> { fn make(&'a T) -> Self; }
impl<'a> Refed<'a, u32> for &'a u32 { fn make(x: &'a u32) -> Self { x } }
// (another impl to ensure trait-matching cannot just choose from a singleton set)
impl<'a,'b> Refed<'a, ()> for &'b () { fn make(_: &'a ()) -> Self { static U: () = (); &U } }
fn refed_foo() {
let a = 8;
let b7 = Refed::make(&a) as &Foo;
assert_eq!(b7.foo(), 8);
}
fn check_subtyping_works() {
fn inner<'short, 'long:'short>(_s: &'short u32,
l: &'long u32) -> &'short (Foo+'short) {
Refed::make(l) as &Foo
}
let a = 9;
let b = 10;
let r = inner(&b, &a);
assert_eq!(r.foo(), 9);
}
pub fn main() {
boxed_foo();
refed_foo();
check_subtyping_works();
}

View file

@ -87,12 +87,12 @@ fn main() {
assert_eq!(cc().unwrap(), 3);
assert_eq!(dd().unwrap(), 3);
let i = box 32 as Box<A>;
let i = box 32i as Box<A>;
assert_eq!(i.aaa(), 3);
let i = box 32 as Box<A>;
let i = box 32i as Box<A>;
assert_eq!(i.bbb(), 3);
let i = box 32 as Box<A>;
let i = box 32i as Box<A>;
assert_eq!(i.ccc().unwrap(), 3);
let i = box 32 as Box<A>;
let i = box 32i as Box<A>;
assert_eq!(i.ddd().unwrap(), 3);
}

View file

@ -41,7 +41,7 @@ impl<'a> Outer<'a> {
}
pub fn main() {
let inner = 5;
let inner: int = 5;
let outer = Outer::new(&inner as &Inner);
outer.inner.print();
}

View file

@ -21,7 +21,7 @@ mod a {
impl X for int {}
pub struct Z<'a>(Enum<&'a (X+'a)>);
fn foo() { let x = 42; let z = Z(Enum::A(&x as &X)); let _ = z; }
fn foo() { let x: int = 42; let z = Z(Enum::A(&x as &X)); let _ = z; }
}
mod b {
@ -34,7 +34,7 @@ mod b {
}
fn bar() {
let x = 42;
let x: int = 42;
let _y = Y { x: Some(&x as &X) };
}
}
@ -43,7 +43,7 @@ mod c {
pub trait X { fn f(&self); }
impl X for int { fn f(&self) {} }
pub struct Z<'a>(Option<&'a (X+'a)>);
fn main() { let x = 42; let z = Z(Some(&x as &X)); let _ = z; }
fn main() { let x: int = 42; let z = Z(Some(&x as &X)); let _ = z; }
}
pub fn main() {}

View file

@ -33,6 +33,6 @@ impl<T> B for *const [T] {
fn main() {
let x: [int; 4] = [1,2,3,4];
let xptr = x.as_slice() as *const _;
let xptr = x.as_slice() as *const [int];
xptr.foo();
}

View file

@ -35,7 +35,7 @@ fn is<T:'static>(x: &Any) -> bool {
}
fn main() {
let x = box 22 as Box<Wrap>;
let x = box 22isize as Box<Wrap>;
println!("x={}", x.get());
let y = x.wrap();
}

View file

@ -42,7 +42,7 @@ fn do_it_imm(obj: &Foo, v: uint) {
}
pub fn main() {
let mut x = 22;
let mut x: uint = 22;
let obj = &mut x as &mut Foo;
do_it_mut(obj);
do_it_imm(obj, 23);

View file

@ -83,7 +83,10 @@ impl<'s> Trait<'s> for (int,int) {
}
impl<'t> MakerTrait for Box<Trait<'t>+'static> {
fn mk() -> Box<Trait<'t>+'static> { box() (4,5) as Box<Trait> }
fn mk() -> Box<Trait<'t>+'static> {
let tup: Box<(int, int)> = box() (4,5);
tup as Box<Trait>
}
}
enum List<'l> {

View file

@ -13,6 +13,6 @@
// pretty-expanded FIXME #23616
pub fn main() {
let foo = 1;
let foo: int = 1;
assert_eq!(&foo as *const int, &foo as *const int);
}

View file

@ -19,7 +19,7 @@ use std::sync::mpsc::channel;
pub fn main() {
let (tx, rx) = channel::<uint>();
let x: Box<_> = box 1;
let x: Box<int> = box 1;
let x_in_parent = &(*x) as *const int as uint;
let _t = Thread::spawn(move || {

View file

@ -0,0 +1,71 @@
// 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.
// Test that all coercions can actually be done using casts (modulo the lints).
#![allow(trivial_casts, trivial_numeric_casts)]
trait Foo {
fn foo(&self) {}
}
pub struct Bar;
impl Foo for Bar {}
pub fn main() {
// Numeric
let _ = 42_i32 as i32;
let _ = 42_u8 as u8;
// & to * pointers
let x: &u32 = &42;
let _ = x as *const u32;
let x: &mut u32 = &mut 42;
let _ = x as *mut u32;
// unsize array
let x: &[u32; 3] = &[42, 43, 44];
let _ = x as &[u32];
let _ = x as *const [u32];
let x: &mut [u32; 3] = &mut [42, 43, 44];
let _ = x as &mut [u32];
let _ = x as *mut [u32];
let x: Box<[u32; 3]> = Box::new([42, 43, 44]);
let _ = x as Box<[u32]>;
// unsize trait
let x: &Bar = &Bar;
let _ = x as &Foo;
let _ = x as *const Foo;
let x: &mut Bar = &mut Bar;
let _ = x as &mut Foo;
let _ = x as *mut Foo;
let x: Box<Bar> = Box::new(Bar);
let _ = x as Box<Foo>;
// functions
fn baz(_x: i32) {}
let _ = &baz as &Fn(i32);
let x = |_x: i32| {};
let _ = &x as &Fn(i32);
}
// subtyping
pub fn test_subtyping<'a, 'b: 'a>(a: &'a Bar, b: &'b Bar) {
let _ = a as &'a Bar;
let _ = b as &'a Bar;
let _ = b as &'b Bar;
}

View file

@ -14,17 +14,17 @@
// pretty-expanded FIXME #23616
struct TestStruct {
x: *const int
x: *const isize
}
unsafe impl Sync for TestStruct {}
static CONSTEXPR: TestStruct = TestStruct{x: &413 as *const _};
static CONSTEXPR: TestStruct = TestStruct{ x: &413 };
pub fn main() {
let x: Vec<_> = (0..5).collect();
let expected: &[uint] = &[0,1,2,3,4];
let expected: &[usize] = &[0,1,2,3,4];
assert_eq!(x, expected);
let x = (0..5).collect::<Vec<_>>();
@ -33,8 +33,8 @@ pub fn main() {
let y: _ = "hello";
assert_eq!(y.len(), 5);
let ptr = &5;
let ptr: &usize = &5;
let ptr2 = ptr as *const _;
assert_eq!(ptr as *const uint as uint, ptr2 as uint);
assert_eq!(ptr as *const usize as usize, ptr2 as usize);
}

View file

@ -16,6 +16,6 @@ fn main() {
// The subslice used to go out of bounds for zero-sized array items, check that this doesn't
// happen anymore
match x {
[_, y..] => assert_eq!(&x[1] as *const _, &y[0] as *const _)
[_, y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
}
}