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:
parent
ed81038504
commit
95602a759d
@ -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;
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
// FIXME: #6220 Implement floating point formatting
|
||||
|
||||
#![allow(unsigned_negation)]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
use fmt;
|
||||
use iter::IteratorExt;
|
||||
|
@ -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) })
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i16")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
int_module! { i16, 16 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i32")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
int_module! { i32, 32 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i64")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
int_module! { i64, 64 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i8")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
int_module! { i8, 8 }
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![doc(hidden)]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
macro_rules! int_module { ($T:ty, $bits:expr) => (
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
use self::wrapping::{OverflowingOps, WrappingOps};
|
||||
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u16")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
uint_module! { u16, i16, 16 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u32")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
uint_module! { u32, i32, 32 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u64")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
uint_module! { u64, i64, 64 }
|
||||
|
@ -12,5 +12,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u8")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
uint_module! { u8, i8, 8 }
|
||||
|
@ -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) => (
|
||||
|
||||
|
@ -16,5 +16,6 @@
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "usize")]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
|
||||
uint_module! { usize, isize, ::isize::BITS }
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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};
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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")]
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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)
|
||||
}
|
||||
})+
|
||||
)
|
||||
}
|
||||
|
@ -135,6 +135,8 @@
|
||||
#![feature(no_std)]
|
||||
#![no_std]
|
||||
|
||||
#![allow(trivial_cast)]
|
||||
#![allow(trivial_numeric_cast)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)] extern crate test;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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(", ")
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -21,6 +21,6 @@ mod inner {
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let a = &1 as &inner::Trait;
|
||||
let a = &1i as &inner::Trait;
|
||||
a.f();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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`
|
||||
}
|
@ -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) {
|
||||
|
@ -86,6 +86,6 @@ mod inner {
|
||||
}
|
||||
|
||||
pub fn foo() {
|
||||
let a = &1 as &inner::Trait;
|
||||
let a: &inner::Trait = &1_isize;
|
||||
a.f();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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`
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(trivial_cast)]
|
||||
|
||||
trait Bar {
|
||||
fn bar(self);
|
||||
|
@ -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() {}
|
||||
|
@ -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() { }
|
||||
|
@ -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>`
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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>>;
|
||||
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 || {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 ())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user