1
Fork 0

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. // Destroy the next chunk.
let next = self.next; let next = self.next;
let size = calculate_size::<T>(self.capacity); 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>>()); mem::min_align_of::<TypedArenaChunk<T>>());
if !next.is_null() { if !next.is_null() {
let capacity = (*next).capacity; let capacity = (*next).capacity;

View file

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

View file

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

View file

@ -713,7 +713,11 @@ impl<T> UnsafeCell<T> {
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[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 /// Unwraps the value
/// ///

View file

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

View file

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

View file

@ -182,6 +182,8 @@ mod impls {
} }
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) { 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 newlen = data.len() * ::$ty::BYTES as usize;
let ptr = data.as_ptr() as *const u8; let ptr = data.as_ptr() as *const u8;
state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) state.write(unsafe { slice::from_raw_parts(ptr, newlen) })

View file

@ -313,6 +313,8 @@ pub fn drop<T>(_x: T) { }
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U { 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) ptr::read(src as *const T as *const U)
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -529,7 +529,7 @@ impl<T: ?Sized> Unique<T> {
/// Create a new `Unique`. /// Create a new `Unique`.
#[unstable(feature = "unique")] #[unstable(feature = "unique")]
pub unsafe fn new(ptr: *mut T) -> Unique<T> { 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. /// 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")] reason = "use std::ffi::c_str_to_bytes + str::from_utf8")]
pub unsafe fn from_c_str(s: *const i8) -> &'static str { pub unsafe fn from_c_str(s: *const i8) -> &'static str {
let s = s as *const u8; let s = s as *const u8;
let mut len = 0; let mut len: usize = 0;
while *s.offset(len as isize) != 0 { while *s.offset(len as isize) != 0 {
len += 1; len += 1;
} }

View file

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

View file

@ -84,9 +84,9 @@ fn test_as_ref() {
assert_eq!(q.as_ref().unwrap(), &2); assert_eq!(q.as_ref().unwrap(), &2);
// Lifetime inference // 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); assert_eq!(p.as_ref().unwrap(), &2);
} }
} }
@ -102,9 +102,9 @@ fn test_as_mut() {
assert!(q.as_mut().unwrap() == &mut 2); assert!(q.as_mut().unwrap() == &mut 2);
// Lifetime inference // 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); assert!(p.as_mut().unwrap() == &mut 2);
} }
} }
@ -170,9 +170,9 @@ fn test_set_memory() {
#[test] #[test]
fn test_unsized_unique() { fn test_unsized_unique() {
let xs: &mut [_] = &mut [1, 2, 3]; let xs: &mut [i32] = &mut [1, 2, 3];
let ptr = unsafe { Unique::new(xs as *mut [_]) }; let ptr = unsafe { Unique::new(xs as *mut [i32]) };
let ys = unsafe { &mut **ptr }; let ys = unsafe { &mut **ptr };
let zs: &mut [_] = &mut [1, 2, 3]; let zs: &mut [i32] = &mut [1, 2, 3];
assert!(ys == zs); 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 // 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 // frob the slot while we're doing the logging. This will destroy any logger
// set during logging. // set during logging.
let mut logger = LOCAL_LOGGER.with(|s| { let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
s.borrow_mut().take() s.borrow_mut().take()
}).unwrap_or_else(|| { }).unwrap_or_else(|| {
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send> box DefaultLogger { handle: io::stderr() }
}); });
logger.log(&LogRecord { logger.log(&LogRecord {
level: LogLevel(level), level: LogLevel(level),

View file

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

View file

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

View file

@ -353,7 +353,7 @@ pub mod reader {
let (shift, mask) = SHIFT_MASK_TABLE[i]; let (shift, mask) = SHIFT_MASK_TABLE[i];
Ok(Res { Ok(Res {
val: ((val >> shift) & mask) as uint, 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, 0 => doc_as_u8(r_doc) as u64,
1 => doc_as_u16(r_doc) as u64, 1 => doc_as_u16(r_doc) as u64,
2 => doc_as_u32(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!(), _ => unreachable!(),
} }
} else { } else {

View file

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

View file

@ -100,6 +100,17 @@ declare_lint! {
"detects transmutes of fat pointers" "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 /// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler. /// which are used by other parts of the compiler.
#[derive(Copy)] #[derive(Copy)]
@ -121,7 +132,9 @@ impl LintPass for HardwiredLints {
STABLE_FEATURES, STABLE_FEATURES,
UNKNOWN_CRATE_TYPES, UNKNOWN_CRATE_TYPES,
VARIANT_SIZE_DIFFERENCES, 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> { impl<'tcx> Hash for TyS<'tcx> {
fn hash<H: Hasher>(&self, s: &mut H) { 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: {:?}", debug!("Interned type: {:?} Pointer: {:?}",
ty, ty as *const _); ty, ty as *const TyS);
interner.insert(InternedTy { ty: ty }, ty); interner.insert(InternedTy { ty: ty }, ty);
@ -4806,32 +4806,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
RvalueDpsExpr 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::ExprBreak(..) |
ast::ExprAgain(..) | ast::ExprAgain(..) |
ast::ExprRet(..) | ast::ExprRet(..) |
@ -4847,7 +4821,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprUnary(..) | ast::ExprUnary(..) |
ast::ExprBox(None, _) | ast::ExprBox(None, _) |
ast::ExprAddrOf(..) | ast::ExprAddrOf(..) |
ast::ExprBinary(..) => { ast::ExprBinary(..) |
ast::ExprCast(..) => {
RvalueDatumExpr RvalueDatumExpr
} }

View file

@ -1804,6 +1804,9 @@ impl LintPass for UnconditionalRecursion {
fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl, fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
blk: &ast::Block, sp: Span, id: ast::NodeId) { 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>, type F = for<'tcx> fn(&ty::ctxt<'tcx>,
ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; 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; pub use rustc::util as util;
use session::Session; use session::Session;
use lint::{LintPassObject, LintId}; use lint::LintId;
mod builtin; mod builtin;
@ -67,7 +67,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
macro_rules! add_builtin { macro_rules! add_builtin {
($sess:ident, $($name:ident),*,) => ( ($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 { macro_rules! add_builtin_with_new {
($sess:ident, $($name:ident),*,) => ( ($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); UNUSED_UNSAFE, PATH_STATEMENTS);
// We have one lint pass defined specially // 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 // Insert temporary renamings for a one-time deprecation
store.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); store.register_renamed("raw_pointer_deriving", "raw_pointer_derive");

View file

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

View file

@ -43,6 +43,9 @@
#![feature(convert)] #![feature(convert)]
#![feature(path_relative_from)] #![feature(path_relative_from)]
#![allow(trivial_cast)]
#![allow(trivial_numeric_cast)]
extern crate arena; extern crate arena;
extern crate flate; extern crate flate;
extern crate getopts; 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, pub fn to_lvalue_datum<'blk>(self,
bcx: Block<'blk, 'tcx>, bcx: Block<'blk, 'tcx>,
name: &str, 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, trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
vec![(idx_datum, idx.id)], Some(dest), true).bcx vec![(idx_datum, idx.id)], Some(dest), true).bcx
} }
ast::ExprCast(ref val, _) => { ast::ExprCast(..) => {
// DPS output mode means this is a trait cast: // Trait casts used to come this way, now they should be coercions.
if ty::type_is_trait(node_id_type(bcx, expr.id)) { bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
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::ExprAssignOp(op, ref dst, ref src) => { ast::ExprAssignOp(op, ref dst, ref src) => {
trans_assign_op(bcx, expr, op, &**dst, &**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 mut bcx = bcx;
let ccx = bcx.ccx(); 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 t_out = node_id_type(bcx, id);
let k_in = cast_type_kind(bcx.tcx(), t_in); let k_in = cast_type_kind(bcx.tcx(), t_in);
let k_out = cast_type_kind(bcx.tcx(), t_out); 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: // by-value as appropriate given its type:
let mut datum = unpack_datum!(bcx, trans(bcx, expr)); 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; datum.ty = t_out;
return DatumBlock::new(bcx, datum); return DatumBlock::new(bcx, datum);
} }

View file

@ -26,7 +26,7 @@ use trans::common::*;
use trans::consts; use trans::consts;
use trans::datum::*; use trans::datum::*;
use trans::debuginfo::DebugLoc; use trans::debuginfo::DebugLoc;
use trans::expr::{SaveIn, Ignore}; use trans::expr::SaveIn;
use trans::expr; use trans::expr;
use trans::glue; use trans::glue;
use trans::machine; use trans::machine;
@ -861,44 +861,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
.collect() .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. /// 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>) pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-> &'tcx 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))` // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
fn unsize_ty(&self, fn unsize_ty(&self,
ty_a: Ty<'tcx>, ty_a: Ty<'tcx>,
a: Ty<'tcx>, a: Ty<'tcx>, // TODO unwrap ty_a here, not in the caller
ty_b: Ty<'tcx>) ty_b: Ty<'tcx>)
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> { -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)>
debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx())); {
let tcx = self.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) { match (&a.sty, &b.sty) {
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => { (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
let ty = ty::mk_vec(tcx, t_a, None); let ty = ty::mk_vec(tcx, t_a, None);
@ -438,7 +438,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} }
_ => None _ => None
} }
) })
} }
fn coerce_from_fn_pointer(&self, 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`. // Checks that the type of `expr` can be coerced to `expected`.
pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expected: Ty<'tcx>, expr: &ast::Expr) { sp: Span,
expected: Ty<'tcx>,
expr: &ast::Expr) {
let expr_ty = fcx.expr_ty(expr); let expr_ty = fcx.expr_ty(expr);
debug!("demand::coerce(expected = {}, expr_ty = {})", debug!("demand::coerce(expected = {}, expr_ty = {})",
expected.repr(fcx.ccx.tcx), 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 // def-id of the closure, so that once we decide, we can easily go
// back and process them. // back and process them.
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>, deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
deferred_cast_checks: RefCell<Vec<CastCheck<'tcx>>>,
} }
trait DeferredCallResolution<'tcx> { trait DeferredCallResolution<'tcx> {
@ -192,6 +194,15 @@ trait DeferredCallResolution<'tcx> {
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'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 /// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`. /// whatever type hint we are able in the form of an `Expectation`.
#[derive(Copy)] #[derive(Copy)]
@ -399,6 +410,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
fn_sig_map: RefCell::new(NodeMap()), fn_sig_map: RefCell::new(NodeMap()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
deferred_call_resolutions: RefCell::new(DefIdMap()), 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); vtable::select_all_fcx_obligations_and_apply_defaults(&fcx);
upvar::closure_analyze_fn(&fcx, fn_id, decl, body); upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
vtable::select_all_fcx_obligations_or_error(&fcx); vtable::select_all_fcx_obligations_or_error(&fcx);
fcx.check_casts();
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
writeback::resolve_type_vars_in_fn(&fcx, 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>, fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
span: Span,
t_1: Ty<'tcx>,
t_e: Ty<'tcx>,
e: &ast::Expr) {
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span, span: Span,
t_1: Ty<'tcx>, t_1: Ty<'tcx>,
@ -1070,6 +1079,33 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}, t_e, None); }, 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_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_scalar = ty::type_is_scalar(t_e);
let t_e_is_integral = ty::type_is_integral(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; 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 { 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 { } else if t_1_is_char {
let t_e = fcx.infcx().shallow_resolve(t_e); let t_e = fcx.infcx().shallow_resolve(t_e);
if t_e.sty != ty::ty_uint(ast::TyU8) { if t_e.sty != ty::ty_uint(ast::TyU8) {
fcx.type_error_message(span, |actual| { fcx.type_error_message(span, |actual| {
format!("only `u8` can be cast as \ format!("only `u8` can be cast as `char`, not `{}`", actual)
`char`, not `{}`", actual)
}, t_e, None); }, t_e, None);
} }
} else if t_1.sty == ty::ty_bool { } else if t_1.sty == ty::ty_bool {
span_err!(fcx.tcx().sess, span, E0054, 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) && !( } 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) { t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
// Casts to float must go through an integer or boolean // 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 */ /* 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) { } 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> { impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.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 { 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> { 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); 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>) { pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
if !substs.substs.is_noop() { if !substs.substs.is_noop() {
debug!("write_substs({}, {}) in fcx {}", 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)) o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs))
.map(|t| self.normalize_associated_types_in(span, &t)) .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> { 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 { if let ast::TyFixedLengthVec(_, ref count_expr) = t.node {
check_expr_with_hint(fcx, &**count_expr, tcx.types.uint); 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) => { ast::ExprVec(ref args) => {
let uty = expected.to_option(fcx).and_then(|uty| { 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); check_expr_with_hint(fcx, e, declty);
demand::coerce(fcx, e.span, declty, e); demand::coerce(fcx, e.span, declty, e);
vtable::select_all_fcx_obligations_or_error(fcx); vtable::select_all_fcx_obligations_or_error(fcx);
fcx.check_casts();
regionck::regionck_expr(fcx, e); regionck::regionck_expr(fcx, e);
writeback::resolve_type_vars_in_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, ty: attr::IntType,
disr: ty::Disr) -> bool { disr: ty::Disr) -> bool {
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool { fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
#![allow(trivial_numeric_cast)]
match ty { match ty {
ast::TyU8 => disr as u8 as Disr == disr, ast::TyU8 => disr as u8 as Disr == disr,
ast::TyU16 => disr as u16 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, id: ast::NodeId,
hint: attr::ReprAttr) hint: attr::ReprAttr)
-> Vec<Rc<ty::VariantInfo<'tcx>>> { -> Vec<Rc<ty::VariantInfo<'tcx>>> {
#![allow(trivial_numeric_cast)]
use std::num::Int; use std::num::Int;
let rty = ty::node_id_to_type(ccx.tcx, id); let rty = ty::node_id_to_type(ccx.tcx, id);

View file

@ -9,7 +9,6 @@
// except according to those terms. // except according to those terms.
use check::{FnCtxt}; use check::{FnCtxt};
use check::demand;
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode}; use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause}; use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors; use middle::traits::report_fulfillment_errors;
@ -19,83 +18,6 @@ use syntax::codemap::Span;
use util::nodemap::FnvHashSet; use util::nodemap::FnvHashSet;
use util::ppaux::{Repr, UserString}; 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 // 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 // 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 (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= &mut opaque as *mut _ as *mut libc::c_void; = &mut opaque as *mut _ as *mut libc::c_void;
(*renderer).blockcode = Some(block as blockcodefn); (*renderer).blockcode = Some(block);
(*renderer).header = Some(header as headerfn); (*renderer).header = Some(header);
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, s.as_ptr(), hoedown_document_render(document, ob, s.as_ptr(),
@ -380,8 +380,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
unsafe { unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT); let ob = hoedown_buffer_new(DEF_OUNIT);
let renderer = hoedown_html_renderer_new(0, 0); let renderer = hoedown_html_renderer_new(0, 0);
(*renderer).blockcode = Some(block as blockcodefn); (*renderer).blockcode = Some(block);
(*renderer).header = Some(header as headerfn); (*renderer).header = Some(header);
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
= tests as *mut _ as *mut libc::c_void; = tests as *mut _ as *mut libc::c_void;
@ -501,10 +501,10 @@ pub fn plain_summary_line(md: &str) -> String {
unsafe { unsafe {
let ob = hoedown_buffer_new(DEF_OUNIT); let ob = hoedown_buffer_new(DEF_OUNIT);
let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed(); 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).opaque = ob as *mut libc::c_void;
(*renderer).link = Some(link as linkfn); (*renderer).link = Some(link);
(*renderer).normal_text = Some(normal_text as normaltextfn); (*renderer).normal_text = Some(normal_text);
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
hoedown_document_render(document, ob, md.as_ptr(), hoedown_document_render(document, ob, md.as_ptr(),

View file

@ -2429,7 +2429,10 @@ pub trait ToJson {
macro_rules! to_json_impl_i64 { macro_rules! to_json_impl_i64 {
($($t:ty), +) => ( ($($t:ty), +) => (
$(impl ToJson for $t { $(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 { macro_rules! to_json_impl_u64 {
($($t:ty), +) => ( ($($t:ty), +) => (
$(impl ToJson for $t { $(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)] #![feature(no_std)]
#![no_std] #![no_std]
#![allow(trivial_cast)]
#![allow(trivial_numeric_cast)]
#![deny(missing_docs)] #![deny(missing_docs)]
#[cfg(test)] extern crate test; #[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<()> { 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() slot.borrow_mut().take()
}).unwrap_or_else(|| { }).unwrap_or_else(|| {
box stdout() as Box<Writer + Send> box stdout()
}); });
let result = f(&mut *my_stdout); let result = f(&mut *my_stdout);
let mut var = Some(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; use thread::Thread;
let something_around_the_top_of_the_stack = 1; 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; let my_stack_top = addr as uint;
// FIXME #11359 we just assume that this thread has a stack of a // 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 { impl ExpnId {
pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId { pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
ExpnId(cookie as u32) ExpnId(cookie)
} }
pub fn to_llvm_cookie(self) -> i32 { pub fn to_llvm_cookie(self) -> i32 {
@ -376,7 +376,7 @@ impl Encodable for FileMap {
match bytes_per_diff { match bytes_per_diff {
1 => for diff in diff_iter { try! { (diff.0 as u8).encode(s) } }, 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) } }, 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!() _ => unreachable!()
} }
} }
@ -650,7 +650,7 @@ impl CodeMap {
let lo = self.lookup_char_pos(sp.lo); let lo = self.lookup_char_pos(sp.lo);
let hi = self.lookup_char_pos(sp.hi); let hi = self.lookup_char_pos(sp.hi);
let mut lines = Vec::new(); 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); lines.push(i);
}; };
FileLines {file: lo.file, lines: lines} FileLines {file: lo.file, lines: lines}

View file

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

View file

@ -262,6 +262,7 @@ pub mod rt {
(unsigned, $t:ty, $tag:expr) => ( (unsigned, $t:ty, $tag:expr) => (
impl ToSource for $t { impl ToSource for $t {
fn to_source(&self) -> String { fn to_source(&self) -> String {
#![allow(trivial_numeric_cast)]
let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag)); let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
pprust::lit_to_string(&dummy_spanned(lit)) 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. // Weird, but useful for X-macros.
return box ParserAnyMacro { return box ParserAnyMacro {
parser: RefCell::new(p), parser: RefCell::new(p),
} as Box<MacResult+'cx> }
} }
Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
best_fail_spot = sp; best_fail_spot = sp;

View file

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

View file

@ -865,7 +865,7 @@ impl<'a> Parser<'a> {
} else { } else {
// Avoid token copies with `replace`. // Avoid token copies with `replace`.
let buffer_start = self.buffer_start as usize; 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; self.buffer_start = next_index as isize;
let placeholder = TokenAndSpan { let placeholder = TokenAndSpan {

View file

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

View file

@ -103,7 +103,7 @@ impl Write for WriterWrapper {
/// opened. /// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> { pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper { 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. /// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> { pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper { let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Write + Send>, wrapped: box std::io::stdout(),
}); });
match ti { match ti {
Some(t) => Some(t), Some(t) => Some(t),
None => { None => {
WinConsole::new(WriterWrapper { 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. /// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> { pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper { 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. /// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> { pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper { let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Write + Send>, wrapped: box std::io::stderr(),
}); });
match ti { match ti {
Some(t) => Some(t), Some(t) => Some(t),
None => { None => {
WinConsole::new(WriterWrapper { 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, out: out,
ti: msys_terminfo(), ti: msys_terminfo(),
num_colors: 8, num_colors: 8,
} as Box<Terminal<T>+Send>) })
}, },
_ => { _ => {
debug!("error finding terminfo entry: {:?}", err); debug!("error finding terminfo entry: {:?}", err);
@ -213,7 +213,7 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
return Some(box TerminfoTerminal {out: out, return Some(box TerminfoTerminal {out: out,
ti: inf, ti: inf,
num_colors: nc} as Box<Terminal<T>+Send>); num_colors: nc});
} }
fn dim_if_necessary(&self, color: color::Color) -> color::Color { 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)); let magic = try!(read_le_u16(file));
if magic != 0x011A { if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x}, found {:x}", 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; let names_bytes = try!(read_le_u16(file)) as int;

View file

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

View file

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

View file

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

View file

@ -22,11 +22,11 @@ fn main() {
//~| expected u8 //~| expected u8
//~| found array of 1 elements //~| found array of 1 elements
let local = [0]; let local: [u8; 1] = [0];
let _v = &local as *mut u8; let _v = &local as *mut u8;
//~^ ERROR mismatched types //~^ ERROR mismatched types
//~| expected `*mut u8` //~| expected `*mut u8`
//~| found `&[_; 1]` //~| found `&[u8; 1]`
//~| expected u8, //~| expected u8,
//~| found array of 1 elements //~| 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); 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 //~| ERROR function calls in statics are limited to struct and enum constructors
fn main() {} 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>; let a = &t as &Gettable<T>;
//~^ ERROR the trait `core::marker::Send` is not implemented //~^ ERROR the trait `core::marker::Send` is not implemented
//~^^ ERROR the trait `core::marker::Copy` 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) { fn g<T>(val: T) {

View file

@ -86,6 +86,6 @@ mod inner {
} }
pub fn foo() { pub fn foo() {
let a = &1 as &inner::Trait; let a: &inner::Trait = &1_isize;
a.f(); 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_variables)]
#![deny(unused_assignments)] #![deny(unused_assignments)]
#![allow(dead_code, non_camel_case_types)] #![allow(dead_code, non_camel_case_types, trivial_numeric_cast)]
fn f1(x: isize) { fn f1(x: isize) {
//~^ ERROR unused variable: `x` //~^ ERROR unused variable: `x`

View file

@ -12,6 +12,7 @@
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![allow(dead_code)] #![allow(dead_code)]
#![allow(trivial_cast)]
trait Bar { trait Bar {
fn bar(self); 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> { 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 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() {} fn main() {}

View file

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

View file

@ -20,7 +20,7 @@ impl MyAdd for i32 {
} }
fn main() { fn main() {
let x = 5; let x: i32 = 5;
let y = x as MyAdd<i32>; let y = x as MyAdd<i32>;
//~^ ERROR 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 // Issue #14893. Tests that casts from vectors don't behave strangely in the
// presence of the `_` type shorthand notation. // 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 { struct X {
y: [u8; 2], y: [u8; 2],
@ -18,12 +20,14 @@ struct X {
fn main() { fn main() {
let x1 = X { y: [0, 0] }; 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 t1: *const [u8; 2] = &x1.y as *const _;
let h1: *const [u8; 2] = &x1.y as *const [u8; 2]; let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
let mut x1 = X { y: [0, 0] }; 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 p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR mismatched types
let t1: *mut [u8; 2] = &mut x1.y as *mut _; let t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2]; let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];

View file

@ -291,15 +291,15 @@ fn main() {
let slice2 = &*vec2; let slice2 = &*vec2;
// Trait Objects // Trait Objects
let box_trait = (box 0) as Box<Trait1>; let box_trait = (box 0_isize) as Box<Trait1>;
let ref_trait = &0 as &Trait1; let ref_trait = &0_isize as &Trait1;
let mut mut_int1 = 0; let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut Trait1; let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
let generic_box_trait = (box 0) as Box<Trait2<i32, Mod1::Struct2>>; let generic_box_trait = (box 0_isize) as Box<Trait2<i32, Mod1::Struct2>>;
let generic_ref_trait = (&0) as &Trait2<Struct1, Struct1>; 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 let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
&mut Trait2<Mod1::Mod2::Struct3, GenericStruct<usize, isize>>; &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() { fn main() {
let x: Box<Tr+ Sync>; 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() { pub fn dummy() {
// force the vtable to be created // 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() { 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); assert_eq!(x.double(), 6);
} }

View file

@ -9,6 +9,6 @@
// except according to those terms. // except according to those terms.
pub fn main() { pub fn main() {
let x = 3; let x: int = 3;
println!("&x={:x}", (&x as *const int as uint)); 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!(cc().unwrap(), 3);
assert_eq!(dd().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); assert_eq!(i.aaa(), 3);
let i = box 32 as Box<A>; let i = box 32i as Box<A>;
assert_eq!(i.bbb(), 3); 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); 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); assert_eq!(i.ddd().unwrap(), 3);
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -42,7 +42,7 @@ fn do_it_imm(obj: &Foo, v: uint) {
} }
pub fn main() { pub fn main() {
let mut x = 22; let mut x: uint = 22;
let obj = &mut x as &mut Foo; let obj = &mut x as &mut Foo;
do_it_mut(obj); do_it_mut(obj);
do_it_imm(obj, 23); 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> { 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> { enum List<'l> {

View file

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

View file

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

View file

@ -14,17 +14,17 @@
// pretty-expanded FIXME #23616 // pretty-expanded FIXME #23616
struct TestStruct { struct TestStruct {
x: *const int x: *const isize
} }
unsafe impl Sync for TestStruct {} unsafe impl Sync for TestStruct {}
static CONSTEXPR: TestStruct = TestStruct{x: &413 as *const _}; static CONSTEXPR: TestStruct = TestStruct{ x: &413 };
pub fn main() { pub fn main() {
let x: Vec<_> = (0..5).collect(); 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); assert_eq!(x, expected);
let x = (0..5).collect::<Vec<_>>(); let x = (0..5).collect::<Vec<_>>();
@ -33,8 +33,8 @@ pub fn main() {
let y: _ = "hello"; let y: _ = "hello";
assert_eq!(y.len(), 5); assert_eq!(y.len(), 5);
let ptr = &5; let ptr: &usize = &5;
let ptr2 = ptr as *const _; 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 // The subslice used to go out of bounds for zero-sized array items, check that this doesn't
// happen anymore // happen anymore
match x { match x {
[_, y..] => assert_eq!(&x[1] as *const _, &y[0] as *const _) [_, y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
} }
} }