Add trivial cast lints.

This permits all coercions to be performed in casts, but adds lints to warn in those cases.

Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.

[breaking change]

* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:

```
let x = 42;
let y = &x as *const u32;
```

Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:

```
let x: u32 = 42;
let y = &x as *const u32;
```
This commit is contained in:
Nick Cameron 2015-03-20 17:15:27 +13:00
parent ed81038504
commit 95602a759d
90 changed files with 287 additions and 449 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_cast)]
#![allow(trivial_numeric_cast)]
#![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_cast)]
&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_cast)]
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_cast)]
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_cast)]
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_cast)]
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_cast)]
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_cast)]
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_cast)]
int_module! { i16, 16 }

View file

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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![doc(hidden)]
#![allow(trivial_numeric_cast)]
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_cast)]
#[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_cast)]
use self::wrapping::{OverflowingOps, WrappingOps};

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![doc(hidden)]
#![allow(trivial_numeric_cast)]
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_cast)]
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_cast)]
// 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_cast)]
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_cast)]
#![allow(trivial_numeric_cast)]
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_CAST,
Warn,
"detects trivial casts which could be removed"
}
declare_lint! {
pub TRIVIAL_NUMERIC_CAST,
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_CAST,
TRIVIAL_NUMERIC_CAST
)
}
}

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)
}
}
@ -2721,7 +2721,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);
@ -4806,32 +4806,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(..) |
@ -4847,7 +4821,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

@ -1804,6 +1804,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_cast)]
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());
)*}
)
}
@ -129,7 +129,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_cast)]
#![allow(trivial_numeric_cast)]
#![crate_name = "rustc_llvm"]
#![unstable(feature = "rustc_private")]

View file

@ -43,6 +43,9 @@
#![feature(convert)]
#![feature(path_relative_from)]
#![allow(trivial_cast)]
#![allow(trivial_numeric_cast)]
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

@ -26,7 +26,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;
@ -861,44 +861,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

@ -332,14 +332,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
fn unsize_ty(&self,
ty_a: Ty<'tcx>,
a: Ty<'tcx>,
a: Ty<'tcx>, // TODO unwrap ty_a here, not in the caller
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|
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);
@ -438,7 +438,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
_ => 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_CAST,
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_CAST,
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_cast)]
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_cast)]
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_cast)]
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_cast)]
Json::U64(*self as u64)
}
})+
)
}

View file

@ -135,6 +135,8 @@
#![feature(no_std)]
#![no_std]
#![allow(trivial_cast)]
#![allow(trivial_numeric_cast)]
#![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

@ -73,7 +73,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

@ -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_cast)]
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

@ -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_cast)]
fn f1(x: isize) {
//~^ ERROR unused variable: `x`

View file

@ -12,6 +12,7 @@
#![feature(rustc_attrs)]
#![allow(dead_code)]
#![allow(trivial_cast)]
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

@ -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

@ -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 ())
}
}