From 1ec9adcfc0da7b1cdfe8d42f7eedcbd727c6861c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 21 Mar 2015 11:08:15 -0700 Subject: [PATCH 01/32] std: Tweak rt::at_exit behavior There have been some recent panics on the bots and this commit is an attempt to appease them. Previously it was considered invalid to run `rt::at_exit` after the handlers had already started running. Due to the multithreaded nature of applications, however, it is not always possible to guarantee this. For example [this program][ex] will show off the abort. [ex]: https://gist.github.com/alexcrichton/56300b87af6fa554e52d The semantics of the `rt::at_exit` function have been modified as such: * It is now legal to call `rt::at_exit` at any time. The return value now indicates whether the closure was successfully registered or not. Callers must now decide what to do with this information. * The `rt::at_exit` handlers will now be run for a fixed number of iterations. Common cases (such as the example shown) may end up registering a new handler while others are running perhaps once or twice, so this common condition is covered by re-running the handlers a fixed number of times, after which new registrations are forbidden. Some usage of `rt::at_exit` was updated to handle these new semantics, but deprecated or unstable libraries calling `rt::at_exit` were not updated. --- src/liblog/lib.rs | 2 +- src/libstd/io/lazy.rs | 24 +++++++---- src/libstd/old_io/stdio.rs | 2 +- src/libstd/rt/at_exit_imp.rs | 59 ++++++++++++++++---------- src/libstd/rt/mod.rs | 22 +++++----- src/libstd/sys/common/helper_thread.rs | 2 +- 6 files changed, 65 insertions(+), 46 deletions(-) diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4537fc763c95..df94a6ac80fb 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -443,7 +443,7 @@ fn init() { DIRECTIVES = boxed::into_raw(box directives); // Schedule the cleanup for the globals for when the runtime exits. - rt::at_exit(move || { + let _ = rt::at_exit(move || { let _g = LOCK.lock(); assert!(!DIRECTIVES.is_null()); let _directives = Box::from_raw(DIRECTIVES); diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index c9b105f72a53..df280dab37d4 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -35,25 +35,33 @@ impl Lazy { pub fn get(&'static self) -> Option> { let _g = self.lock.lock(); unsafe { - let mut ptr = *self.ptr.get(); + let ptr = *self.ptr.get(); if ptr.is_null() { - ptr = boxed::into_raw(self.init()); - *self.ptr.get() = ptr; + Some(self.init()) } else if ptr as usize == 1 { - return None + None + } else { + Some((*ptr).clone()) } - Some((*ptr).clone()) } } - fn init(&'static self) -> Box> { - rt::at_exit(move || unsafe { + unsafe fn init(&'static self) -> Arc { + // If we successfully register an at exit handler, then we cache the + // `Arc` allocation in our own internal box (it will get deallocated by + // the at exit handler). Otherwise we just return the freshly allocated + // `Arc`. + let registered = rt::at_exit(move || { let g = self.lock.lock(); let ptr = *self.ptr.get(); *self.ptr.get() = 1 as *mut _; drop(g); drop(Box::from_raw(ptr)) }); - Box::new((self.init)()) + let ret = (self.init)(); + if registered.is_ok() { + *self.ptr.get() = boxed::into_raw(Box::new(ret.clone())); + } + return ret } } diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs index a1c8630e0ec3..a48758366f34 100644 --- a/src/libstd/old_io/stdio.rs +++ b/src/libstd/old_io/stdio.rs @@ -238,7 +238,7 @@ pub fn stdin() -> StdinReader { STDIN = boxed::into_raw(box stdin); // Make sure to free it at exit - rt::at_exit(|| { + let _ = rt::at_exit(|| { Box::from_raw(STDIN); STDIN = ptr::null_mut(); }); diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 9fa12b1ef302..9079c0aaffb7 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -12,6 +12,10 @@ //! //! Documentation can be found on the `rt::at_exit` function. +// FIXME: switch this to use atexit. Currently this +// segfaults (the queue's memory is mysteriously gone), so +// instead the cleanup is tied to the `std::rt` entry point. + use boxed; use boxed::Box; use vec::Vec; @@ -27,47 +31,56 @@ type Queue = Vec>; static LOCK: Mutex = MUTEX_INIT; static mut QUEUE: *mut Queue = 0 as *mut Queue; -unsafe fn init() { +// The maximum number of times the cleanup routines will be run. While running +// the at_exit closures new ones may be registered, and this count is the number +// of times the new closures will be allowed to register successfully. After +// this number of iterations all new registrations will return `false`. +const ITERS: usize = 10; + +unsafe fn init() -> bool { if QUEUE.is_null() { let state: Box = box Vec::new(); QUEUE = boxed::into_raw(state); - } else { + } else if QUEUE as usize == 1 { // can't re-init after a cleanup - rtassert!(QUEUE as uint != 1); + return false } - // FIXME: switch this to use atexit as below. Currently this - // segfaults (the queue's memory is mysteriously gone), so - // instead the cleanup is tied to the `std::rt` entry point. - // - // ::libc::atexit(cleanup); + return true } pub fn cleanup() { - unsafe { - LOCK.lock(); - let queue = QUEUE; - QUEUE = 1 as *mut _; - LOCK.unlock(); + for i in 0..ITERS { + unsafe { + LOCK.lock(); + let queue = QUEUE; + QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; + LOCK.unlock(); - // make sure we're not recursively cleaning up - rtassert!(queue as uint != 1); + // make sure we're not recursively cleaning up + rtassert!(queue as usize != 1); - // If we never called init, not need to cleanup! - if queue as uint != 0 { - let queue: Box = Box::from_raw(queue); - for to_run in *queue { - to_run.invoke(()); + // If we never called init, not need to cleanup! + if queue as usize != 0 { + let queue: Box = Box::from_raw(queue); + for to_run in *queue { + to_run.invoke(()); + } } } } } -pub fn push(f: Thunk<'static>) { +pub fn push(f: Thunk<'static>) -> bool { + let mut ret = true; unsafe { LOCK.lock(); - init(); - (*QUEUE).push(f); + if init() { + (*QUEUE).push(f); + } else { + ret = false; + } LOCK.unlock(); } + return ret } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index e52e68dad23f..43aa4155629e 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -17,14 +17,9 @@ //! time being. #![unstable(feature = "std_misc")] - -// FIXME: this should not be here. #![allow(missing_docs)] -#![allow(dead_code)] - -use marker::Send; -use ops::FnOnce; +use prelude::v1::*; use sys; use thunk::Thunk; use usize; @@ -149,13 +144,16 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { /// Enqueues a procedure to run when the main thread exits. /// -/// It is forbidden for procedures to register more `at_exit` handlers when they -/// are running, and doing so will lead to a process abort. +/// Currently these closures are only run once the main *Rust* thread exits. +/// Once the `at_exit` handlers begin running, more may be enqueued, but not +/// infinitely so. Eventually a handler registration will be forced to fail. /// -/// Note that other threads may still be running when `at_exit` routines start -/// running. -pub fn at_exit(f: F) { - at_exit_imp::push(Thunk::new(f)); +/// Returns `Ok` if the handler was successfully registered, meaning that the +/// closure will be run once the main thread exits. Returns `Err` to indicate +/// that the closure could not be registered, meaning that it is not scheduled +/// to be rune. +pub fn at_exit(f: F) -> Result<(), ()> { + if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())} } /// One-time runtime cleanup. diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 2a852fbcd57e..53f18a573255 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -112,7 +112,7 @@ impl Helper { self.cond.notify_one() }); - rt::at_exit(move || { self.shutdown() }); + let _ = rt::at_exit(move || { self.shutdown() }); *self.initialized.get() = true; } else if *self.chan.get() as uint == 1 { panic!("cannot continue usage after shutdown"); From 558c427cd3baac76d98c4c73cea15c4073ef5e93 Mon Sep 17 00:00:00 2001 From: Liam Monahan Date: Sun, 22 Mar 2015 23:54:59 -0400 Subject: [PATCH 02/32] Fix a typo in the Rust Book ownership page. --- src/doc/trpl/ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 6aced23ede08..9a2eb458bc63 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -513,8 +513,8 @@ Otherwise, it is an error to elide an output lifetime. ### Examples -Here are some examples of functions with elided lifetimes, and the version of -what the elided lifetimes are expand to: +Here are some examples of functions with elided lifetimes, along with versions +of what the elided lifetimes expand to: ```{rust,ignore} fn print(s: &str); // elided From 37601131a0ffc49e93b8797020429a980520171c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 15 Feb 2015 15:09:26 -0500 Subject: [PATCH 03/32] Make the `Fn` traits inherit from one another and remove the bridging impls. This requires: 1. modifying trait selection a bit so that when we synthesize impls for fn pointers and closures; 2. adding code to trans so that we can synthesize a `FnMut`/`FnOnce` impl for a `Fn` closure and so forth. --- src/libcore/ops.rs | 24 +++ src/libcore/str/mod.rs | 29 ++- src/librustc/middle/traits/project.rs | 5 +- src/librustc/middle/traits/select.rs | 8 +- src/librustc/middle/ty.rs | 19 +- src/librustc_trans/trans/callee.rs | 31 ++- src/librustc_trans/trans/closure.rs | 204 +++++++++++++++++- src/librustc_trans/trans/meth.rs | 38 ++-- src/librustc_typeck/astconv.rs | 243 ++++++++++++---------- src/librustc_typeck/check/closure.rs | 66 +++--- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/collect.rs | 28 +-- 12 files changed, 495 insertions(+), 202 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 6324e8fa8744..fc3f4b426d86 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { #[lang="fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[cfg(stage0)] pub trait Fn { /// The returned type after the call operator is used. type Output; @@ -1144,10 +1145,21 @@ pub trait Fn { extern "rust-call" fn call(&self, args: Args) -> Self::Output; } +/// A version of the call operator that takes an immutable receiver. +#[lang="fn"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[cfg(not(stage0))] +pub trait Fn : FnMut { + /// This is called when the call operator is used. + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[cfg(stage0)] pub trait FnMut { /// The returned type after the call operator is used. type Output; @@ -1156,6 +1168,16 @@ pub trait FnMut { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } +/// A version of the call operator that takes a mutable receiver. +#[lang="fn_mut"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[cfg(not(stage0))] +pub trait FnMut : FnOnce { + /// This is called when the call operator is used. + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + /// A version of the call operator that takes a by-value receiver. #[lang="fn_once"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1168,6 +1190,7 @@ pub trait FnOnce { extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } +#[cfg(stage0)] impl FnMut for F where F : Fn { @@ -1178,6 +1201,7 @@ impl FnMut for F } } +#[cfg(stage0)] impl FnOnce for F where F : FnMut { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e8181395b5c1..dd7144636dfb 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; use marker::Sized; use mem; use num::Int; -use ops::{Fn, FnMut}; +use ops::{Fn, FnMut, FnOnce}; use option::Option::{self, None, Some}; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; @@ -524,6 +524,7 @@ delegate_iter!{exact u8 : Bytes<'a>} #[derive(Copy, Clone)] struct BytesDeref; +#[cfg(stage0)] impl<'a> Fn<(&'a u8,)> for BytesDeref { type Output = u8; @@ -533,6 +534,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref { } } +#[cfg(not(stage0))] +impl<'a> Fn<(&'a u8,)> for BytesDeref { + #[inline] + extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { + *ptr + } +} + +#[cfg(not(stage0))] +impl<'a> FnMut<(&'a u8,)> for BytesDeref { + #[inline] + extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 { + Fn::call(&*self, (ptr,)) + } +} + +#[cfg(not(stage0))] +impl<'a> FnOnce<(&'a u8,)> for BytesDeref { + type Output = u8; + + #[inline] + extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 { + Fn::call(&self, (ptr,)) + } +} + /// An iterator over the substrings of a string, separated by `sep`. struct CharSplits<'a, P: Pattern<'a>> { /// The slice remaining to be iterated diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 6b66d7227d30..b4f21492ca10 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>( obligation.repr(tcx), fn_sig.repr(tcx)); + // the `Output` associated type is declared on `FnOnce` + let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap(); + // Note: we unwrap the binder here but re-create it below (1) let ty::Binder((trait_ref, ret_type)) = util::closure_trait_ref_and_return_type(tcx, - obligation.predicate.trait_ref.def_id, + fn_once_def_id, obligation.predicate.trait_ref.self_ty(), fn_sig, flag); diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 7dfbccea0dcc..764e342a0c5a 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.closure_typer.closure_kind(closure_def_id) { Some(closure_kind) => { debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind == kind { + if closure_kind.extends(kind) { candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone())); } } @@ -1090,10 +1090,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - // We provide a `Fn` impl for fn pointers. There is no need to provide - // the other traits (e.g. `FnMut`) since those are provided by blanket - // impls. - if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() { + // We provide impl of all fn traits for fn pointers. + if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() { return Ok(()); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 99c35c6e5425..4b8c4ee88c05 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> { pub substs: Substs<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] pub enum ClosureKind { + // Warning: Ordering is significant here! The ordering is chosen + // because the trait Fn is a subtrait of FnMut and so in turn, and + // hence we order it so that Fn < FnMut < FnOnce. FnClosureKind, FnMutClosureKind, FnOnceClosureKind, @@ -2484,6 +2487,20 @@ impl ClosureKind { Err(err) => cx.sess.fatal(&err[..]), } } + + /// True if this a type that impls this closure kind + /// must also implement `other`. + pub fn extends(self, other: ty::ClosureKind) -> bool { + match (self, other) { + (FnClosureKind, FnClosureKind) => true, + (FnClosureKind, FnMutClosureKind) => true, + (FnClosureKind, FnOnceClosureKind) => true, + (FnMutClosureKind, FnMutClosureKind) => true, + (FnMutClosureKind, FnOnceClosureKind) => true, + (FnOnceClosureKind, FnOnceClosureKind) => true, + _ => false, + } + } } pub trait ClosureTyper<'tcx> { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index cf36ec1f3ed9..07c94097e2df 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -264,14 +264,29 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// but for the bare function type given. pub fn trans_fn_pointer_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, + closure_kind: ty::ClosureKind, bare_fn_ty: Ty<'tcx>) -> ValueRef { let _icx = push_ctxt("trans_fn_pointer_shim"); let tcx = ccx.tcx(); + // Normalize the type for better caching. let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty); - match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) { + + // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`. + let is_by_ref = match closure_kind { + ty::FnClosureKind | ty::FnMutClosureKind => true, + ty::FnOnceClosureKind => false, + }; + let bare_fn_ty_maybe_ref = if is_by_ref { + ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty) + } else { + bare_fn_ty + }; + + // Check if we already trans'd this shim. + match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) { Some(&llval) => { return llval; } None => { } } @@ -279,9 +294,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("trans_fn_pointer_shim(bare_fn_ty={})", bare_fn_ty.repr(tcx)); - // This is an impl of `Fn` trait, so receiver is `&self`. - let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty); - // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`, // which is the fn pointer, and `args`, which is the arguments tuple. let (opt_def_id, sig) = @@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( unsafety: ast::Unsafety::Normal, abi: synabi::RustCall, sig: ty::Binder(ty::FnSig { - inputs: vec![bare_fn_ty_ref, + inputs: vec![bare_fn_ty_maybe_ref, tuple_input_ty], output: sig.output, variadic: false @@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let mut bcx = init_function(&fcx, false, sig.output); // the first argument (`self`) will be ptr to the the fn pointer - let llfnpointer = - Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)); + let llfnpointer = if is_by_ref { + Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)) + } else { + get_param(fcx.llfn, fcx.arg_pos(0) as u32) + }; // the remaining arguments will be the untupled values let llargs: Vec<_> = @@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( finish_fn(&fcx, bcx, sig.output, DebugLoc::None); - ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn); + ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn); llfn } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1bc7219ad82..5a48b8e4bce1 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -8,24 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::link::mangle_internal_name_by_path_and_seq; -use llvm::ValueRef; +use arena::TypedArena; +use back::link::{self, mangle_internal_name_by_path_and_seq}; +use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; use trans::base::*; use trans::build::*; -use trans::cleanup::{CleanupMethods, ScopeId}; +use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; +use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; -use trans::datum::{Datum, rvalue_scratch_datum}; -use trans::datum::{Rvalue, ByValue}; -use trans::debuginfo; +use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; +use trans::debuginfo::{self, DebugLoc}; use trans::expr; use trans::monomorphize::{self, MonoId}; use trans::type_of::*; use middle::ty::{self, ClosureTyper}; use middle::subst::{Substs}; use session::config::FullDebugInfo; +use util::ppaux::Repr; +use syntax::abi::RustCall; use syntax::ast; use syntax::ast_util; @@ -239,11 +242,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // Create the closure. for (i, freevar) in freevars.iter().enumerate() { let datum = expr::trans_local_var(bcx, freevar.def); - let upvar_slot_dest = adt::trans_field_ptr(bcx, - &*repr, - dest_addr, - 0, - i); + let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i); let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(), closure_expr_id: id }; match tcx.upvar_capture(upvar_id).unwrap() { @@ -259,3 +258,186 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, Some(bcx) } + +pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + node: ExprOrMethodCall, + param_substs: &'tcx Substs<'tcx>, + trait_closure_kind: ty::ClosureKind) + -> ValueRef +{ + // The substitutions should have no type parameters remaining + // after passing through fulfill_obligation + let llfn = callee::trans_fn_ref_with_substs(ccx, + closure_def_id, + node, + param_substs, + substs.clone()).val; + + // If the closure is a Fn closure, but a FnOnce is needed (etc), + // then adapt the self type + let closure_kind = ccx.tcx().closure_kind(closure_def_id); + trans_closure_adapter_shim(ccx, + closure_def_id, + substs, + closure_kind, + trait_closure_kind, + llfn) +} + +fn trans_closure_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + llfn_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind, + llfn: ValueRef) + -> ValueRef +{ + let _icx = push_ctxt("trans_closure_adapter_shim"); + let tcx = ccx.tcx(); + + debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ + trait_closure_kind={:?}, \ + llfn={})", + llfn_closure_kind, + trait_closure_kind, + ccx.tn().val_to_string(llfn)); + + match (llfn_closure_kind, trait_closure_kind) { + (ty::FnClosureKind, ty::FnClosureKind) | + (ty::FnMutClosureKind, ty::FnMutClosureKind) | + (ty::FnOnceClosureKind, ty::FnOnceClosureKind) => { + // No adapter needed. + llfn + } + (ty::FnClosureKind, ty::FnMutClosureKind) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + llfn + } + (ty::FnClosureKind, ty::FnOnceClosureKind) | + (ty::FnMutClosureKind, ty::FnOnceClosureKind) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn) + } + _ => { + tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", + llfn_closure_kind, + trait_closure_kind)); + } + } +} + +fn trans_fn_once_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + llreffn: ValueRef) + -> ValueRef +{ + debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})", + closure_def_id.repr(ccx.tcx()), + substs.repr(ccx.tcx()), + ccx.tn().val_to_string(llreffn)); + + let tcx = ccx.tcx(); + let typer = NormalizingClosureTyper::new(tcx); + + // Find a version of the closure type. Substitute static for the + // region since it doesn't really matter. + let substs = tcx.mk_substs(substs); + let closure_ty = ty::mk_closure(tcx, closure_def_id, substs); + let ref_closure_ty = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), closure_ty); + + // Make a version with the type of by-ref closure. + let ty::ClosureTy { unsafety, abi, mut sig } = typer.closure_type(closure_def_id, substs); + sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, + abi: abi, + sig: sig.clone() }); + let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty); + debug!("trans_fn_once_adapter_shim: llref_fn_ty={}", + llref_fn_ty.repr(tcx)); + + // Make a version of the closure type with the same arguments, but + // with argument #0 being by value. + assert_eq!(abi, RustCall); + sig.0.inputs[0] = closure_ty; + let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, + abi: abi, + sig: sig }); + let llonce_fn_ty = ty::mk_bare_fn(tcx, None, llonce_bare_fn_ty); + + // Create the by-value helper. + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); + let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name); + + let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); + let (block_arena, fcx): (TypedArena<_>, FunctionContext); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, + lloncefn, + ast::DUMMY_NODE_ID, + false, + sig.output, + substs, + None, + &block_arena); + let mut bcx = init_function(&fcx, false, sig.output); + + // the first argument (`self`) will be the (by value) closure env. + let self_scope = fcx.push_custom_cleanup_scope(); + let self_scope_id = CustomScope(self_scope); + let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty); + let llself = get_param(lloncefn, fcx.arg_pos(0) as u32); + let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode)); + let env_datum = unpack_datum!(bcx, + env_datum.to_lvalue_datum_in_scope(bcx, "self", + self_scope_id)); + + debug!("trans_fn_once_adapter_shim: env_datum={}", + bcx.val_to_string(env_datum.val)); + + // the remaining arguments will be packed up in a tuple. + let input_tys = match sig.inputs[1].sty { + ty::ty_tup(ref tys) => &**tys, + _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \ + closure_def_id={}", + closure_def_id.repr(tcx))) + }; + let llargs: Vec<_> = + input_tys.iter() + .enumerate() + .map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32)) + .collect(); + + let dest = + fcx.llretslotptr.get().map( + |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); + + let callee_data = TraitItem(MethodData { llfn: llreffn, + llself: env_datum.val }); + + bcx = callee::trans_call_inner(bcx, + DebugLoc::None, + llref_fn_ty, + |bcx, _| Callee { bcx: bcx, data: callee_data }, + ArgVals(&llargs), + dest).bcx; + + fcx.pop_custom_cleanup_scope(self_scope); + + finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + + lloncefn +} diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 4da17972c55f..aa038f8ddca3 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -17,11 +17,13 @@ use middle::subst::Substs; use middle::subst::VecPerParamSpace; use middle::subst; use middle::traits; +use middle::ty::ClosureTyper; use trans::base::*; use trans::build::*; use trans::callee::*; use trans::callee; use trans::cleanup; +use trans::closure; use trans::common::*; use trans::consts; use trans::datum::*; @@ -358,19 +360,21 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, traits::VtableClosure(closure_def_id, substs) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let llfn = trans_fn_ref_with_substs(bcx.ccx(), - closure_def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs, - substs).val; - + let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = closure::trans_closure_method(bcx.ccx(), + closure_def_id, + substs, + MethodCallKey(method_call), + bcx.fcx.param_substs, + trait_closure_kind); Callee { bcx: bcx, data: Fn(llfn), } } traits::VtableFnPointer(fn_ty) => { - let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty); + let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableObject(ref data) => { @@ -645,9 +649,6 @@ pub fn trans_object_shim<'a, 'tcx>( assert!(!fcx.needs_ret_allocas); - let sig = - ty::erase_late_bound_regions(bcx.tcx(), &fty.sig); - let dest = fcx.llretslotptr.get().map( |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); @@ -714,17 +715,18 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, emit_vtable_methods(ccx, id, substs, param_substs).into_iter() } traits::VtableClosure(closure_def_id, substs) => { - let llfn = trans_fn_ref_with_substs( - ccx, - closure_def_id, - ExprId(0), - param_substs, - substs).val; - + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); + let llfn = closure::trans_closure_method(ccx, + closure_def_id, + substs, + ExprId(0), + param_substs, + trait_closure_kind); vec![llfn].into_iter() } traits::VtableFnPointer(bare_fn_ty) => { - vec![trans_fn_pointer_shim(ccx, bare_fn_ty)].into_iter() + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); + vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter() } traits::VtableObject(ref data) => { // this would imply that the Self type being erased is diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 28e7027b2124..4f06346fb45c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, RegionEscape, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; @@ -608,24 +608,16 @@ pub fn instantiate_poly_trait_ref<'tcx>( poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - let mut projections = Vec::new(); - - // The trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = ShiftedRscope::new(rscope); - - let trait_ref = instantiate_trait_ref(this, &shifted_rscope, - &ast_trait_ref.trait_ref, - None, self_ty, Some(&mut projections)); - - for projection in projections { - poly_projections.push(ty::Binder(projection)); - } - - ty::Binder(trait_ref) + let trait_ref = &ast_trait_ref.trait_ref; + let trait_def_id = trait_def_id(this, trait_ref); + ast_path_to_poly_trait_ref(this, + rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap(), + poly_projections) } /// Instantiates the path for the given trait reference, assuming that it's @@ -634,31 +626,27 @@ pub fn instantiate_poly_trait_ref<'tcx>( /// /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. -pub fn instantiate_trait_ref<'tcx>( +pub fn instantiate_mono_trait_ref<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, trait_ref: &ast::TraitRef, - impl_id: Option, - self_ty: Option>, - projections: Option<&mut Vec>>) + self_ty: Option>) -> Rc> { + let trait_def_id = trait_def_id(this, trait_ref); + ast_path_to_mono_trait_ref(this, + rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap()) +} + +fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId { let path = &trait_ref.path; match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) { - def::DefTrait(trait_def_id) => { - let trait_ref = ast_path_to_trait_ref(this, - rscope, - path.span, - PathParamMode::Explicit, - trait_def_id, - self_ty, - path.segments.last().unwrap(), - projections); - if let Some(id) = impl_id { - this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone()); - } - trait_ref - } + def::DefTrait(trait_def_id) => trait_def_id, _ => { span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait", path.user_string(this.tcx())); @@ -676,24 +664,17 @@ fn object_path_to_poly_trait_ref<'a,'tcx>( mut projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - // we are introducing a binder here, so shift the - // anonymous regions depth to account for that - let shifted_rscope = ShiftedRscope::new(rscope); - - let mut tmp = Vec::new(); - let trait_ref = ty::Binder(ast_path_to_trait_ref(this, - &shifted_rscope, - span, - param_mode, - trait_def_id, - None, - trait_segment, - Some(&mut tmp))); - projections.extend(tmp.into_iter().map(ty::Binder)); - trait_ref + ast_path_to_poly_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + None, + trait_segment, + projections) } -fn ast_path_to_trait_ref<'a,'tcx>( +fn ast_path_to_poly_trait_ref<'a,'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, span: Span, @@ -701,10 +682,78 @@ fn ast_path_to_trait_ref<'a,'tcx>( trait_def_id: ast::DefId, self_ty: Option>, trait_segment: &ast::PathSegment, - mut projections: Option<&mut Vec>>) - -> Rc> + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> { - debug!("ast_path_to_trait_ref {:?}", trait_segment); + // The trait reference introduces a binding level here, so + // we need to shift the `rscope`. It'd be nice if we could + // do away with this rscope stuff and work this knowledge + // into resolve_lifetimes, as we do with non-omitted + // lifetimes. Oh well, not there yet. + let shifted_rscope = &ShiftedRscope::new(rscope); + + let (substs, assoc_bindings) = + create_substs_for_ast_trait_ref(this, + shifted_rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + let poly_trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_def_id, substs))); + + { + let converted_bindings = + assoc_bindings + .iter() + .filter_map(|binding| { + // specify type to assert that error was already reported in Err case: + let predicate: Result<_, ErrorReported> = + ast_type_binding_to_poly_projection_predicate(this, + poly_trait_ref.clone(), + self_ty, + binding); + predicate.ok() // ok to ignore Err() because ErrorReported (see above) + }); + poly_projections.extend(converted_bindings); + } + + poly_trait_ref +} + +fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: ast::DefId, + self_ty: Option>, + trait_segment: &ast::PathSegment) + -> Rc> +{ + let (substs, assoc_bindings) = + create_substs_for_ast_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + prohibit_projections(this.tcx(), &assoc_bindings); + Rc::new(ty::TraitRef::new(trait_def_id, substs)) +} + +fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: ast::DefId, + self_ty: Option>, + trait_segment: &ast::PathSegment) + -> (&'tcx Substs<'tcx>, Vec>) +{ + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", + trait_segment); + let trait_def = match this.get_trait_def(span, trait_def_id) { Ok(trait_def) => trait_def, Err(ErrorReported) => { @@ -752,34 +801,16 @@ fn ast_path_to_trait_ref<'a,'tcx>( self_ty, types, regions); - let substs = this.tcx().mk_substs(substs); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); - - match projections { - None => { - prohibit_projections(this.tcx(), &assoc_bindings); - } - Some(ref mut v) => { - for binding in &assoc_bindings { - match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), - self_ty, binding) { - Ok(pp) => { v.push(pp); } - Err(ErrorReported) => { } - } - } - } - } - - trait_ref + (this.tcx().mk_substs(substs), assoc_bindings) } -fn ast_type_binding_to_projection_predicate<'tcx>( +fn ast_type_binding_to_poly_projection_predicate<'tcx>( this: &AstConv<'tcx>, - mut trait_ref: Rc>, + mut trait_ref: ty::PolyTraitRef<'tcx>, self_ty: Option>, binding: &ConvertedBinding<'tcx>) - -> Result, ErrorReported> + -> Result, ErrorReported> { let tcx = this.tcx(); @@ -800,14 +831,14 @@ fn ast_type_binding_to_projection_predicate<'tcx>( // We want to produce `>::T == foo`. // Simple case: X is defined in the current trait. - if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) { - return Ok(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, + if this.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { + return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+ item_name: binding.item_name, }, ty: binding.ty, - }); + })); } // Otherwise, we have to walk through the supertraits to find @@ -820,17 +851,17 @@ fn ast_type_binding_to_projection_predicate<'tcx>( let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); if self_ty.is_none() { // if converting for an object type - let mut dummy_substs = trait_ref.substs.clone(); - assert!(dummy_substs.self_ty().is_none()); - dummy_substs.types.push(SelfSpace, dummy_self_ty); - trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id, - tcx.mk_substs(dummy_substs))); + let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ + assert!(dummy_substs.self_ty().is_none()); // | + dummy_substs.types.push(SelfSpace, dummy_self_ty); // | + trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_ref.def_id(), // <------------+ + tcx.mk_substs(dummy_substs)))); } - try!(this.ensure_super_predicates(binding.span, trait_ref.def_id)); + try!(this.ensure_super_predicates(binding.span, trait_ref.def_id())); let mut candidates: Vec = - traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) + traits::supertraits(tcx, trait_ref.clone()) .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .collect(); @@ -865,21 +896,13 @@ fn ast_type_binding_to_projection_predicate<'tcx>( } }; - if ty::binds_late_bound_regions(tcx, &candidate) { - span_err!(tcx.sess, binding.span, E0219, - "associated type `{}` defined in higher-ranked supertrait `{}`", - token::get_name(binding.item_name), - candidate.user_string(tcx)); - return Err(ErrorReported); - } - - Ok(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: candidate.0, + Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+ item_name: binding.item_name, }, ty: binding.ty, - }) + })) } fn ast_path_to_ty<'tcx>( @@ -1134,14 +1157,14 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); - let trait_ref = ast_path_to_trait_ref(this, - rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment, - None); + let trait_ref = + ast_path_to_mono_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 32f91a175f3c..d2a06fcf9909 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -16,6 +16,7 @@ use astconv; use middle::region; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; +use std::cmp; use syntax::abi; use syntax::ast; use syntax::ast_util; @@ -109,15 +110,11 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( ty::ty_trait(ref object_type) => { let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(), fcx.tcx().types.err); - let expectations = - proj_bounds.iter() - .filter_map(|pb| deduce_expectations_from_projection(fcx, pb)) - .next(); - - match expectations { - Some((sig, kind)) => (Some(sig), Some(kind)), - None => (None, None) - } + let sig = proj_bounds.iter() + .filter_map(|pb| deduce_sig_from_projection(fcx, pb)) + .next(); + let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id()); + (sig, kind) } ty::ty_infer(ty::TyVar(vid)) => { deduce_expectations_from_obligations(fcx, vid) @@ -136,7 +133,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. - let expected_sig_and_kind = + let expected_sig = fulfillment_cx .pending_obligations() .iter() @@ -150,7 +147,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::Projection(ref proj_predicate) => { let trait_ref = proj_predicate.to_poly_trait_ref(); self_type_matches_expected_vid(fcx, trait_ref, expected_vid) - .and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate)) + .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate)) } _ => { None @@ -159,14 +156,10 @@ fn deduce_expectations_from_obligations<'a,'tcx>( }) .next(); - match expected_sig_and_kind { - Some((sig, kind)) => { return (Some(sig), Some(kind)); } - None => { } - } - // Even if we can't infer the full signature, we may be able to // infer the kind. This can occur if there is a trait-reference - // like `F : Fn`. + // like `F : Fn`. Note that due to subtyping we could encounter + // many viable options, so pick the most restrictive. let expected_kind = fulfillment_cx .pending_obligations() @@ -183,54 +176,61 @@ fn deduce_expectations_from_obligations<'a,'tcx>( .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid)) .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id())) }) - .next(); + .fold(None, pick_most_restrictive_closure_kind); - (None, expected_kind) + (expected_sig, expected_kind) +} + +fn pick_most_restrictive_closure_kind(best: Option, + cur: ty::ClosureKind) + -> Option +{ + match best { + None => Some(cur), + Some(best) => Some(cmp::min(best, cur)) + } } /// Given a projection like "::Result == Y", we can deduce /// everything we need to know about a closure. -fn deduce_expectations_from_projection<'a,'tcx>( +fn deduce_sig_from_projection<'a,'tcx>( fcx: &FnCtxt<'a,'tcx>, projection: &ty::PolyProjectionPredicate<'tcx>) - -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)> + -> Option> { let tcx = fcx.tcx(); - debug!("deduce_expectations_from_projection({})", + debug!("deduce_sig_from_projection({})", projection.repr(tcx)); let trait_ref = projection.to_poly_trait_ref(); - let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) { - Some(k) => k, - None => { return None; } - }; - - debug!("found object type {:?}", kind); + if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { + return None; + } let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); - debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); + debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { ty::ty_tup(ref tys) => { (*tys).clone() } _ => { return None; } }; - debug!("input_tys {}", input_tys.repr(tcx)); + debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx)); let ret_param_ty = projection.0.ty; let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); - debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); + debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { inputs: input_tys, output: ty::FnConverging(ret_param_ty), variadic: false }; - debug!("fn_sig {}", fn_sig.repr(tcx)); + debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx)); - return Some((fn_sig, kind)); + Some(fn_sig) } fn self_type_matches_expected_vid<'a,'tcx>( diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index bc581a6af415..b95e0ce8cb3c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -725,7 +725,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }; // this closure doesn't implement the right kind of `Fn` trait - if closure_kind != kind { + if !closure_kind.extends(kind) { continue; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 97cc3ac7c48a..8744df0e2024 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -784,14 +784,15 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { - let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()), - &ExplicitRscope, - ast_trait_ref, - Some(it.id), - None, - None); + let trait_ref = + astconv::instantiate_mono_trait_ref(&ccx.icx(&()), + &ExplicitRscope, + ast_trait_ref, + None); ty::record_trait_has_default_impl(tcx, trait_ref.def_id); + + tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref); } ast::ItemImpl(_, _, ref generics, @@ -890,13 +891,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } } - if let Some(ref trait_ref) = *opt_trait_ref { - astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, - trait_ref, - Some(it.id), - Some(selfty), - None); + if let Some(ref ast_trait_ref) = *opt_trait_ref { + let trait_ref = + astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), + &ExplicitRscope, + ast_trait_ref, + Some(selfty)); + + tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref); } enforce_impl_ty_params_are_constrained(tcx, From 9330bae4bde720dbdf8d379bd5529a1bb7a6f1e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Mar 2015 10:08:33 -0400 Subject: [PATCH 04/32] Fallout from changing fn traits to use inheritance rather than bridge impls. This is a [breaking-change] (for gated code) in that when you implement `Fn` (`FnMut`) you must also implement `FnOnce`. This commit demonstrates how to fix it. --- src/libcollectionstest/btree/set.rs | 10 +++++++-- .../compile-fail/borrowck-overloaded-call.rs | 18 +++++++++++---- .../compile-fail/coerce-unsafe-to-closure.rs | 3 ++- .../compile-fail/extern-wrong-value-type.rs | 2 +- ...ture-gate-unboxed-closures-manual-impls.rs | 13 +++-------- src/test/compile-fail/fn-trait-formatting.rs | 2 +- src/test/compile-fail/fn-variance-1.rs | 8 +++++-- src/test/compile-fail/issue-15094.rs | 7 +++--- src/test/compile-fail/issue-20225.rs | 14 ++++++++++-- src/test/compile-fail/overloaded-calls-bad.rs | 9 ++++++-- .../compile-fail/overloaded-calls-nontuple.rs | 6 ++++- .../unboxed-closures-fnmut-as-fn.rs | 9 +++++--- ...oxed-closures-recursive-fn-using-fn-mut.rs | 9 ++++++-- .../unboxed-closures-unsafe-extern-fn.rs | 8 +++++-- .../unboxed-closures-wrong-abi.rs | 8 +++++-- ...boxed-closures-wrong-arg-type-extern-fn.rs | 8 +++++-- src/test/run-pass/issue-13655.rs | 15 ++++++++++++- src/test/run-pass/issue-14958.rs | 10 ++++++++- src/test/run-pass/issue-14959.rs | 14 +++++++++++- src/test/run-pass/issue-16739.rs | 22 ++++++++++++++++--- src/test/run-pass/issue-19982.rs | 12 ++++++++-- .../overloaded-calls-param-vtables.rs | 11 ++++++++-- src/test/run-pass/overloaded-calls-simple.rs | 18 +++++++++++++-- .../run-pass/overloaded-calls-zero-args.rs | 6 ++++- ...unboxed-closures-fn-as-fnmut-and-fnonce.rs | 10 ++++++++- .../unboxed-closures-fnmut-as-fnonce.rs | 8 +++++-- .../unboxed-closures-infer-recursive-fn.rs | 11 ++++++++-- .../run-pass/unboxed-closures-manual-impl.rs | 8 +++++-- 28 files changed, 218 insertions(+), 61 deletions(-) diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index 488f0d756d32..234cd6e0fd21 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -43,8 +43,6 @@ struct Counter<'a, 'b> { } impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { - type Output = bool; - extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool { assert_eq!(x, self.expected[*self.i]); *self.i += 1; @@ -52,6 +50,14 @@ impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { } } +impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> { + type Output = bool; + + extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool { + self.call_mut(args) + } +} + fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where // FIXME Replace Counter with `Box _>` F: FnOnce(&BTreeSet, &BTreeSet, Counter) -> bool, diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs index 673c025e8634..93c37524bf56 100644 --- a/src/test/compile-fail/borrowck-overloaded-call.rs +++ b/src/test/compile-fail/borrowck-overloaded-call.rs @@ -18,26 +18,36 @@ struct SFn { } impl Fn<(isize,)> for SFn { - type Output = isize; - extern "rust-call" fn call(&self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnMut<(isize,)> for SFn { + extern "rust-call" fn call_mut(&mut self, args: (isize,)) -> isize { self.call(args) } +} + +impl FnOnce<(isize,)> for SFn { + type Output = isize; + extern "rust-call" fn call_once(self, args: (isize,)) -> isize { self.call(args) } +} + struct SFnMut { x: isize, y: isize, } impl FnMut<(isize,)> for SFnMut { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnOnce<(isize,)> for SFnMut { + type Output = isize; + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + struct SFnOnce { x: String, } diff --git a/src/test/compile-fail/coerce-unsafe-to-closure.rs b/src/test/compile-fail/coerce-unsafe-to-closure.rs index fe7635f065cd..27b4a04054f0 100644 --- a/src/test/compile-fail/coerce-unsafe-to-closure.rs +++ b/src/test/compile-fail/coerce-unsafe-to-closure.rs @@ -10,5 +10,6 @@ fn main() { let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); - //~^ ERROR: is not implemented for the type + //~^ ERROR E0277 + //~| ERROR E0277 } diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index db3373ea0277..d1abed9b2627 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -18,5 +18,5 @@ fn main() { let _x: extern "C" fn() = f; // OK is_fn(f); //~^ ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn() - //~| ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn() + //~| ERROR the trait `core::ops::FnOnce<()>` is not implemented for the type `extern "C" fn() } diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs index e5e5ddadafcc..d86c5d211dc5 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs @@ -18,28 +18,21 @@ struct Foo; impl Fn<()> for Foo { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - - extern "rust-call" fn call(&self, args: ()) -> () {} + extern "rust-call" fn call(self, args: ()) -> () {} } struct Foo1; -impl Fn() for Foo1 { +impl FnOnce() for Foo1 { //~^ ERROR associated type bindings are not allowed here - - extern "rust-call" fn call(&self, args: ()) -> () {} + extern "rust-call" fn call_once(self, args: ()) -> () {} } struct Bar; impl FnMut<()> for Bar { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - extern "rust-call" fn call_mut(&self, args: ()) -> () {} } struct Baz; impl FnOnce<()> for Baz { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - extern "rust-call" fn call_once(&self, args: ()) -> () {} } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index 35c551931366..6433255bd4d2 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -35,5 +35,5 @@ fn main() { needs_fn(1); //~^ ERROR `core::ops::Fn<(isize,)>` - //~| ERROR `core::ops::Fn<(isize,)>` + //~| ERROR `core::ops::FnOnce<(isize,)>` } diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs index 838e65e1d057..8e1e88a92e45 100644 --- a/src/test/compile-fail/fn-variance-1.rs +++ b/src/test/compile-fail/fn-variance-1.rs @@ -17,9 +17,13 @@ fn apply(t: T, f: F) where F: FnOnce(T) { } fn main() { - apply(&3, takes_mut); //~ ERROR (values differ in mutability) apply(&3, takes_imm); + apply(&3, takes_mut); + //~^ ERROR (values differ in mutability) + //~| ERROR (values differ in mutability) apply(&mut 3, takes_mut); - apply(&mut 3, takes_imm); //~ ERROR (values differ in mutability) + apply(&mut 3, takes_imm); + //~^ ERROR (values differ in mutability) + //~| ERROR (values differ in mutability) } diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 8f79022405eb..3853434e128e 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -16,11 +16,10 @@ struct Debuger { x: T } -impl ops::Fn<(),> for Debuger { +impl ops::FnOnce<(),> for Debuger { type Output = (); - - fn call(&self, _args: ()) { -//~^ ERROR `call` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn + fn call_once(self, _args: ()) { +//~^ ERROR `call_once` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn println!("{:?}", self.x); } } diff --git a/src/test/compile-fail/issue-20225.rs b/src/test/compile-fail/issue-20225.rs index e4bedbbb7e1e..fe427e02451a 100644 --- a/src/test/compile-fail/issue-20225.rs +++ b/src/test/compile-fail/issue-20225.rs @@ -13,10 +13,20 @@ struct Foo; impl<'a, T> Fn<(&'a T,)> for Foo { - type Output = (); - extern "rust-call" fn call(&self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait: expected &-ptr } +impl<'a, T> FnMut<(&'a T,)> for Foo { + extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} + //~^ ERROR: has an incompatible type for trait: expected &-ptr +} + +impl<'a, T> FnOnce<(&'a T,)> for Foo { + type Output = (); + + extern "rust-call" fn call_once(self, (_,): (T,)) {} + //~^ ERROR: has an incompatible type for trait: expected &-ptr +} + fn main() {} diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 61752e62abde..77ac97bc8b89 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -18,13 +18,18 @@ struct S { } impl FnMut<(isize,)> for S { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnOnce<(isize,)> for S { + type Output = isize; + extern "rust-call" fn call_once(mut self, (z,): (isize,)) -> isize { + self.call_mut((z,)) + } +} + fn main() { let mut s = S { x: 3, diff --git a/src/test/compile-fail/overloaded-calls-nontuple.rs b/src/test/compile-fail/overloaded-calls-nontuple.rs index c4019fa22097..ea47d6764120 100644 --- a/src/test/compile-fail/overloaded-calls-nontuple.rs +++ b/src/test/compile-fail/overloaded-calls-nontuple.rs @@ -18,12 +18,16 @@ struct S { } impl FnMut for S { - type Output = isize; extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { self.x + self.y + z } } +impl FnOnce for S { + type Output = isize; + extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) } +} + fn main() { let mut s = S { x: 1, diff --git a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs index 92e6affa4c20..93498ac7f835 100644 --- a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs +++ b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs @@ -19,13 +19,17 @@ use std::ops::{Fn,FnMut,FnOnce}; struct S; impl FnMut<(isize,)> for S { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (x,): (isize,)) -> isize { x * x } } +impl FnOnce<(isize,)> for S { + type Output = isize; + + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + fn call_itisize>(f: &F, x: isize) -> isize { f.call((x,)) } @@ -33,5 +37,4 @@ fn call_itisize>(f: &F, x: isize) -> isize { fn main() { let x = call_it(&S, 22); //~^ ERROR not implemented - //~| ERROR not implemented } diff --git a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs index 713b64b1349f..2dcd7a97d897 100644 --- a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs +++ b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs @@ -28,14 +28,19 @@ impl YCombinator { } impl R, A) -> R> FnMut<(A,)> for YCombinator { - type Output = R; - extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> R { (self.func)(self, arg) //~^ ERROR cannot borrow `*self` as mutable more than once at a time } } +impl R, A) -> R> FnOnce<(A,)> for YCombinator { + type Output = R; + extern "rust-call" fn call_once(mut self, args: (A,)) -> R { + self.call_mut(args) + } +} + fn main() { let mut counter = 0; let factorial = |recur: &mut FnMut(u32) -> u32, arg: u32| -> u32 { diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index 23f7ee2b0101..dc7c70ba649d 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -27,11 +27,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 40655f8a3cec..cdcb435b65a6 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -27,11 +27,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index ebcbdbbc006d..150bf36dcc28 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -28,11 +28,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/run-pass/issue-13655.rs b/src/test/run-pass/issue-13655.rs index 81a8b29461c7..6c0e5edae72a 100644 --- a/src/test/run-pass/issue-13655.rs +++ b/src/test/run-pass/issue-13655.rs @@ -14,7 +14,6 @@ use std::ops::Fn; struct Foo(T); impl Fn<()> for Foo { - type Output = T; extern "rust-call" fn call(&self, _: ()) -> T { match *self { Foo(t) => t @@ -22,6 +21,20 @@ impl Fn<()> for Foo { } } +impl FnMut<()> for Foo { + extern "rust-call" fn call_mut(&mut self, _: ()) -> T { + self.call(()) + } +} + +impl FnOnce<()> for Foo { + type Output = T; + + extern "rust-call" fn call_once(self, _: ()) -> T { + self.call(()) + } +} + fn main() { let t: u8 = 1; println!("{}", Foo(t)()); diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index 6335f79be6c7..ab5a2f03ece8 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -15,10 +15,18 @@ trait Foo { fn dummy(&self) { }} struct Bar; impl<'a> std::ops::Fn<(&'a (Foo+'a),)> for Bar { - type Output = (); extern "rust-call" fn call(&self, _: (&'a Foo,)) {} } +impl<'a> std::ops::FnMut<(&'a (Foo+'a),)> for Bar { + extern "rust-call" fn call_mut(&mut self, a: (&'a Foo,)) { self.call(a) } +} + +impl<'a> std::ops::FnOnce<(&'a (Foo+'a),)> for Bar { + type Output = (); + extern "rust-call" fn call_once(self, a: (&'a Foo,)) { self.call(a) } +} + struct Baz; impl Foo for Baz {} diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index 53d0f7dae057..91ad7e03623f 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -34,9 +34,21 @@ impl Alloy { } impl<'b> Fn<(&'b mut (Response+'b),)> for SendFile { + extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {} +} + +impl<'b> FnMut<(&'b mut (Response+'b),)> for SendFile { + extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut (Response+'b),)) { + self.call((_res,)) + } +} + +impl<'b> FnOnce<(&'b mut (Response+'b),)> for SendFile { type Output = (); - extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {} + extern "rust-call" fn call_once(self, (_res,): (&'b mut (Response+'b),)) { + self.call((_res,)) + } } impl Ingot for HelloWorld { diff --git a/src/test/run-pass/issue-16739.rs b/src/test/run-pass/issue-16739.rs index 389baecafd14..fda35d3e7f46 100644 --- a/src/test/run-pass/issue-16739.rs +++ b/src/test/run-pass/issue-16739.rs @@ -18,20 +18,36 @@ struct Foo { foo: u32 } impl FnMut<()> for Foo { - type Output = u32; extern "rust-call" fn call_mut(&mut self, _: ()) -> u32 { self.foo } } -impl FnMut<(u32,)> for Foo { +impl FnOnce<()> for Foo { type Output = u32; + extern "rust-call" fn call_once(mut self, _: ()) -> u32 { self.call_mut(()) } +} + +///////////////////////////////////////////////////////////////////////// + +impl FnMut<(u32,)> for Foo { extern "rust-call" fn call_mut(&mut self, (x,): (u32,)) -> u32 { self.foo + x } } -impl FnMut<(u32,u32)> for Foo { +impl FnOnce<(u32,)> for Foo { type Output = u32; + extern "rust-call" fn call_once(mut self, args: (u32,)) -> u32 { self.call_mut(args) } +} + +///////////////////////////////////////////////////////////////////////// + +impl FnMut<(u32,u32)> for Foo { extern "rust-call" fn call_mut(&mut self, (x, y): (u32, u32)) -> u32 { self.foo + x + y } } +impl FnOnce<(u32,u32)> for Foo { + type Output = u32; + extern "rust-call" fn call_once(mut self, args: (u32,u32)) -> u32 { self.call_mut(args) } +} + fn main() { let mut f = box Foo { foo: 42 } as Box u32>; assert_eq!(f.call_mut(()), 42); diff --git a/src/test/run-pass/issue-19982.rs b/src/test/run-pass/issue-19982.rs index 3082fc27a7de..9a476f563eda 100644 --- a/src/test/run-pass/issue-19982.rs +++ b/src/test/run-pass/issue-19982.rs @@ -14,9 +14,17 @@ struct Foo; impl<'a> Fn<(&'a (),)> for Foo { - type Output = (); - extern "rust-call" fn call(&self, (_,): (&(),)) {} } +impl<'a> FnMut<(&'a (),)> for Foo { + extern "rust-call" fn call_mut(&mut self, (_,): (&(),)) {} +} + +impl<'a> FnOnce<(&'a (),)> for Foo { + type Output = (); + + extern "rust-call" fn call_once(self, (_,): (&(),)) {} +} + fn main() {} diff --git a/src/test/run-pass/overloaded-calls-param-vtables.rs b/src/test/run-pass/overloaded-calls-param-vtables.rs index 0ac9c97532bf..081e1417d5f4 100644 --- a/src/test/run-pass/overloaded-calls-param-vtables.rs +++ b/src/test/run-pass/overloaded-calls-param-vtables.rs @@ -19,13 +19,20 @@ use std::ops::Add; struct G(PhantomData); impl<'a, A: Add> Fn<(A,)> for G { - type Output = i32; - extern "rust-call" fn call(&self, (arg,): (A,)) -> i32 { arg.add(1) } } +impl<'a, A: Add> FnMut<(A,)> for G { + extern "rust-call" fn call_mut(&mut self, args: (A,)) -> i32 { self.call(args) } +} + +impl<'a, A: Add> FnOnce<(A,)> for G { + type Output = i32; + extern "rust-call" fn call_once(self, args: (A,)) -> i32 { self.call(args) } +} + fn main() { // ICE trigger (G(PhantomData))(1); diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index d18a91c54528..b20c80dc4c94 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -18,24 +18,38 @@ struct S1 { } impl FnMut<(i32,)> for S1 { - type Output = i32; extern "rust-call" fn call_mut(&mut self, (z,): (i32,)) -> i32 { self.x * self.y * z } } +impl FnOnce<(i32,)> for S1 { + type Output = i32; + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { + self.call_mut(args) + } +} + struct S2 { x: i32, y: i32, } impl Fn<(i32,)> for S2 { - type Output = i32; extern "rust-call" fn call(&self, (z,): (i32,)) -> i32 { self.x * self.y * z } } +impl FnMut<(i32,)> for S2 { + extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) } +} + +impl FnOnce<(i32,)> for S2 { + type Output = i32; + extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) } +} + struct S3 { x: i32, y: i32, diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index 78e84b9d55bc..245ff6df6145 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -18,12 +18,16 @@ struct S { } impl FnMut<()> for S { - type Output = i32; extern "rust-call" fn call_mut(&mut self, (): ()) -> i32 { self.x * self.y } } +impl FnOnce<()> for S { + type Output = i32; + extern "rust-call" fn call_once(mut self, args: ()) -> i32 { self.call_mut(args) } +} + fn main() { let mut s = S { x: 3, diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 0aab5be2877e..aad190d0236c 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -19,12 +19,20 @@ use std::ops::{Fn,FnMut,FnOnce}; struct S; impl Fn<(i32,)> for S { - type Output = i32; extern "rust-call" fn call(&self, (x,): (i32,)) -> i32 { x * x } } +impl FnMut<(i32,)> for S { + extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) } +} + +impl FnOnce<(i32,)> for S { + type Output = i32; + extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) } +} + fn call_iti32>(f: &F, x: i32) -> i32 { f(x) } diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index a8bb09189327..94be64063671 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -19,13 +19,17 @@ use std::ops::{FnMut,FnOnce}; struct S; impl FnMut<(i32,)> for S { - type Output = i32; - extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { x * x } } +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + fn call_it_muti32>(f: &mut F, x: i32) -> i32 { f(x) } diff --git a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs index 2d1ba7f39b27..a2ab06049d63 100644 --- a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs @@ -30,13 +30,20 @@ impl YCombinator { } impl R, A) -> R> Fn<(A,)> for YCombinator { - type Output = R; - extern "rust-call" fn call(&self, (arg,): (A,)) -> R { (self.func)(self, arg) } } +impl R, A) -> R> FnMut<(A,)> for YCombinator { + extern "rust-call" fn call_mut(&mut self, args: (A,)) -> R { self.call(args) } +} + +impl R, A) -> R> FnOnce<(A,)> for YCombinator { + type Output = R; + extern "rust-call" fn call_once(self, args: (A,)) -> R { self.call(args) } +} + fn main() { let factorial = |recur: &Fn(u32) -> u32, arg: u32| -> u32 { if arg == 0 {1} else {arg * recur(arg-1)} diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs index f1b79a1829ea..439ec4af9ebf 100644 --- a/src/test/run-pass/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures-manual-impl.rs @@ -15,13 +15,17 @@ use std::ops::FnMut; struct S; impl FnMut<(i32,)> for S { - type Output = i32; - extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { x * x } } +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + fn call_iti32>(mut f: F, x: i32) -> i32 { f(x) + 3 } From 37dc801fe630214e7b27899eb89626c8611ce5ff Mon Sep 17 00:00:00 2001 From: Liam Monahan Date: Mon, 23 Mar 2015 21:19:54 -0400 Subject: [PATCH 05/32] Improve the wording of the example section description on the ownership page to make it more clear. --- src/doc/trpl/ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 9a2eb458bc63..b851f19d22dc 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -513,8 +513,8 @@ Otherwise, it is an error to elide an output lifetime. ### Examples -Here are some examples of functions with elided lifetimes, along with versions -of what the elided lifetimes expand to: +Here are some examples of functions with elided lifetimes. We've paired each +example of an elided lifetime with its expanded form. ```{rust,ignore} fn print(s: &str); // elided From a9b31969dcf52f7d3092036be5e0bbe77a9ff7e4 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Tue, 24 Mar 2015 03:25:48 -0700 Subject: [PATCH 06/32] Add the other S_I(RWX)(GRP/OTH) for posix `creat` --- src/etc/libc.c | 10 ++++++++++ src/liblibc/lib.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/etc/libc.c b/src/etc/libc.c index 2bf919d7e2cc..249b5d22b6b2 100644 --- a/src/etc/libc.c +++ b/src/etc/libc.c @@ -165,6 +165,16 @@ void posix88_consts() { put_const(S_IWUSR, int); put_const(S_IRUSR, int); + put_const(S_IRWXG, int); + put_const(S_IXGRP, int); + put_const(S_IWGRP, int); + put_const(S_IRGRP, int); + + put_const(S_IRWXO, int); + put_const(S_IXOTH, int); + put_const(S_IWOTH, int); + put_const(S_IROTH, int); + #ifdef F_OK put_const(F_OK, int); #endif diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 893781e62209..16570086d43c 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -2461,6 +2461,14 @@ pub mod consts { pub const S_IXUSR : c_int = 64; pub const S_IWUSR : c_int = 128; pub const S_IRUSR : c_int = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; @@ -2797,6 +2805,14 @@ pub mod consts { pub const S_IXUSR : mode_t = 64; pub const S_IWUSR : mode_t = 128; pub const S_IRUSR : mode_t = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; @@ -3010,6 +3026,14 @@ pub mod consts { pub const S_IXUSR : mode_t = 64; pub const S_IWUSR : mode_t = 128; pub const S_IRUSR : mode_t = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; @@ -3710,6 +3734,14 @@ pub mod consts { pub const S_IXUSR : mode_t = 64; pub const S_IWUSR : mode_t = 128; pub const S_IRUSR : mode_t = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; @@ -4142,6 +4174,14 @@ pub mod consts { pub const S_IXUSR : mode_t = 64; pub const S_IWUSR : mode_t = 128; pub const S_IRUSR : mode_t = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; @@ -4540,6 +4580,14 @@ pub mod consts { pub const S_IXUSR : mode_t = 64; pub const S_IWUSR : mode_t = 128; pub const S_IRUSR : mode_t = 256; + pub const S_IRWXG : mode_t = 56; + pub const S_IXGRP : mode_t = 8; + pub const S_IWGRP : mode_t = 16; + pub const S_IRGRP : mode_t = 32; + pub const S_IRWXO : mode_t = 7; + pub const S_IXOTH : mode_t = 1; + pub const S_IWOTH : mode_t = 2; + pub const S_IROTH : mode_t = 4; pub const F_OK : c_int = 0; pub const R_OK : c_int = 4; pub const W_OK : c_int = 2; From a34e87f3ab29f6643679d2e430f21724cdcc26b6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 23 Mar 2015 15:40:43 -0400 Subject: [PATCH 07/32] Add Examples for File This is pretty basic, but it's nice to have something. --- src/libstd/fs/mod.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index 7df6d6887a25..72f4fbb116c5 100644 --- a/src/libstd/fs/mod.rs +++ b/src/libstd/fs/mod.rs @@ -128,6 +128,17 @@ impl File { /// /// This function will return an error if `path` does not already exist. /// Other errors may also be returned according to `OpenOptions::open`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn open(path: P) -> io::Result { OpenOptions::new().read(true).open(path) @@ -139,6 +150,17 @@ impl File { /// and will truncate it if it does. /// /// See the `OpenOptions::open` function for more details. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create(path: P) -> io::Result { OpenOptions::new().write(true).create(true).truncate(true).open(path) @@ -156,6 +178,20 @@ impl File { /// /// This function will attempt to ensure that all in-core data reaches the /// filesystem before returning. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// try!(f.write_all(b"Hello, world!")); + /// + /// try!(f.sync_all()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_all(&self) -> io::Result<()> { self.inner.fsync() @@ -170,6 +206,20 @@ impl File { /// /// Note that some platforms may simply implement this in terms of /// `sync_all`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// try!(f.write_all(b"Hello, world!")); + /// + /// try!(f.sync_data()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_data(&self) -> io::Result<()> { self.inner.datasync() @@ -182,12 +232,36 @@ impl File { /// be shrunk. If it is greater than the current file's size, then the file /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// try!(f.set_len(0)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_len(&self, size: u64) -> io::Result<()> { self.inner.truncate(size) } /// Queries metadata about the underlying file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let metadata = try!(f.metadata()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata(&self) -> io::Result { self.inner.file_attr().map(Metadata) From f2996c0c0eaad9e2f589844ba2ee401f1196d347 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 20 Mar 2015 22:09:57 -0400 Subject: [PATCH 08/32] Add basic information about associated types --- src/doc/trpl/SUMMARY.md | 1 + src/doc/trpl/associated-types.md | 202 +++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 src/doc/trpl/associated-types.md diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 6ff51e8d1b92..69d49f67941d 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -22,6 +22,7 @@ * [More Strings](more-strings.md) * [Patterns](patterns.md) * [Method Syntax](method-syntax.md) + * [Associated Types](associated-types.md) * [Closures](closures.md) * [Iterators](iterators.md) * [Generics](generics.md) diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md new file mode 100644 index 000000000000..f36c2c56b6a7 --- /dev/null +++ b/src/doc/trpl/associated-types.md @@ -0,0 +1,202 @@ +% Associated Types + +Associated types are a powerful part of Rust's type system. They're related to +the idea of a 'type family', in other words, grouping multiple types together. That +description is a bit abstract, so let's dive right into an example. If you want +to write a `Graph` trait, you have two types to be generic over: the node type +and the edge type. So you might write a trait, `Graph`, that looks like +this: + +```rust +trait Graph { + fn has_edge(&self, &N, &N) -> bool; + fn edges(&self, &N) -> Vec; + // etc +} +``` + +While this sort of works, it ends up being awkward. For example, any function +that wants to take a `Graph` as a parameter now _also_ needs to be generic over +the `N`ode and `E`dge types too: + +```rust,ignore +fn distance>(graph: &G, start: &N, end: &N) -> u32 { ... } +``` + +Our distance calculation works regardless of our `Edge` type, so the `E` stuff in +this signature is just a distraction. + +What we really want to say is that a certain `E`dge and `N`ode type come together +to form each kind of `Graph`. We can do that with associated types: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; + // etc +} +``` + +Now, our clients can be abstract over a given `Graph`: + +```rust,ignore +fn distance(graph: &G, start: &G::N, end: &G::N) -> uint { ... } +``` + +No need to deal with the `E`dge type here! + +Let's go over all this in more detail. + +## Defining associated types + +Let's build that `Graph` trait. Here's the definition: + +```rust +trait Graph { + type N; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; +} +``` + +Simple enough. Associated types use the `type` keyword, and go inside the body +of the trait, with the functions. + +These `type` declarations can have all the same thing as functions do. For example, +if we wanted our `N` type to implement `Display`, so we can print the nodes out, +we could do this: + +```rust +use std::fmt; + +trait Graph { + type N: fmt::Display; + type E; + + fn has_edge(&self, &Self::N, &Self::N) -> bool; + fn edges(&self, &Self::N) -> Vec; +} +``` + +## Implementing associated types + +Just like any trait, traits that use associated types use the `impl` keyword to +provide implementations. Here's a simple implementation of Graph: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +struct Node; + +struct Edge; + +struct MyGraph; + +impl Graph for MyGraph { + type N = Node; + type E = Edge; + + fn has_edge(&self, n1: &Node, n2: &Node) -> bool { + true + } + + fn edges(&self, n: &Node) -> Vec { + Vec::new() + } +} +``` + +This silly implementation always returns `true` and an empty `Vec`, but it +gives you an idea of how to implement this kind of thing. We first need three +`struct`s, one for the graph, one for the node, and one for the edge. If it made +more sense to use a different type, that would work as well, we're just going to +use `struct`s for all three here. + +Next is the `impl` line, which is just like implementing any other trait. + +From here, we use `=` to define our associated types. The name the trait uses +goes on the left of the `=`, and the concrete type we're `impl`ementing this +for goes on the right. Finally, we use the concrete types in our function +declarations. + +## Trait objects with associated types + +There’s one more bit of syntax we should talk about: trait objects. If you +try to create a trait object from an associated type, like this: + +```rust,ignore +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box; +``` + +You’ll get two errors: + +```text +error: the value of the associated type `E` (from the trait `main::Graph`) must +be specified [E0191] +let obj = Box::new(graph) as Box; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +24:44 error: the value of the associated type `N` (from the trait +`main::Graph`) must be specified [E0191] +let obj = Box::new(graph) as Box; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``` + +We can’t create a trait object like this, becuase we don’t know the associated +types. Instead, we can write this: + +```rust +# trait Graph { +# type N; +# type E; +# fn has_edge(&self, &Self::N, &Self::N) -> bool; +# fn edges(&self, &Self::N) -> Vec; +# } +# struct Node; +# struct Edge; +# struct MyGraph; +# impl Graph for MyGraph { +# type N = Node; +# type E = Edge; +# fn has_edge(&self, n1: &Node, n2: &Node) -> bool { +# true +# } +# fn edges(&self, n: &Node) -> Vec { +# Vec::new() +# } +# } +let graph = MyGraph; +let obj = Box::new(graph) as Box>; +``` + +The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` +type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we +couldn’t be sure which `impl` to match this trait object to. From 0031d57a2107546d3763a0cfd867189a64fac77b Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 12:15:49 -0400 Subject: [PATCH 09/32] Clean up Any's title line http://www.reddit.com/r/rust/comments/304q00/type_information_in_rust/cpp43lu --- src/libcore/any.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 3938a610668b..c94d8e2ed0c8 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -82,11 +82,11 @@ use marker::Sized; // Any trait /////////////////////////////////////////////////////////////////////////////// -/// The `Any` trait is implemented by all `'static` types, and can be used for -/// dynamic typing +/// A type to emulate dynamic typing. See the [module-level documentation][mod] for more details. /// -/// Every type with no non-`'static` references implements `Any`, so `Any` can -/// be used as a trait object to emulate the effects dynamic typing. +/// Every type with no non-`'static` references implements `Any`. +/// +/// [mod]: ../index.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Any: 'static { /// Get the `TypeId` of `self` From f2e0810cb8a3aacea93193ec70c882d3b6b4971c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 12:41:22 -0400 Subject: [PATCH 10/32] correct reference wrt shifts Fixes #23421 --- src/doc/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 415ec4e4fbf0..6e6c56d3df20 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1264,7 +1264,7 @@ be undesired. * Sending signals * Accessing/modifying the file system * Unsigned integer overflow (well-defined as wrapping) -* Signed integer overflow (well-defined as two's complement representation +* Signed integer overflow (well-defined as two’s complement representation wrapping) #### Diverging functions @@ -2959,10 +2959,10 @@ meaning of the operators on standard types is given here. : Exclusive or. Calls the `bitxor` method of the `std::ops::BitXor` trait. * `<<` - : Logical left shift. + : Left shift. Calls the `shl` method of the `std::ops::Shl` trait. * `>>` - : Logical right shift. + : Right shift. Calls the `shr` method of the `std::ops::Shr` trait. #### Lazy boolean operators From 4ccf374b4a2ef24862d365783b70217bbfbf3bc7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 11:14:35 -0700 Subject: [PATCH 11/32] std: Zero memory when calling `read_to_end()` This commit alters the behavior of the `Read::read_to_end()` method to zero all memory instead of passing an uninitialized buffer to `read`. This change is motivated by the [discussion on the internals forum][discuss] where the conclusion has been that the standard library will not expose uninitialized memory. [discuss]: http://internals.rust-lang.org/t/uninitialized-memory/1652 Closes #20314 --- src/libstd/io/mod.rs | 44 ++++++++++++++------------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 237435d6dfbf..33c4156fc0ce 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -16,13 +16,12 @@ use cmp; use unicode::str as core_str; use error as std_error; use fmt; -use iter::Iterator; +use iter::{self, Iterator, IteratorExt, Extend}; use marker::Sized; use ops::{Drop, FnOnce}; use option::Option::{self, Some, None}; use result::Result::{Ok, Err}; use result; -use slice; use string::String; use str; use vec::Vec; @@ -50,41 +49,26 @@ mod stdio; const DEFAULT_BUF_SIZE: usize = 64 * 1024; // Acquires a slice of the vector `v` from its length to its capacity -// (uninitialized data), reads into it, and then updates the length. +// (after initializing the data), reads into it, and then updates the length. // // This function is leveraged to efficiently read some bytes into a destination // vector without extra copying and taking advantage of the space that's already // in `v`. -// -// The buffer we're passing down, however, is pointing at uninitialized data -// (the end of a `Vec`), and many operations will be *much* faster if we don't -// have to zero it out. In order to prevent LLVM from generating an `undef` -// value when reads happen from this uninitialized memory, we force LLVM to -// think it's initialized by sending it through a black box. This should prevent -// actual undefined behavior after optimizations. fn with_end_to_cap(v: &mut Vec, f: F) -> Result where F: FnOnce(&mut [u8]) -> Result { - unsafe { - let n = try!(f({ - let base = v.as_mut_ptr().offset(v.len() as isize); - black_box(slice::from_raw_parts_mut(base, - v.capacity() - v.len())) - })); - - // If the closure (typically a `read` implementation) reported that it - // read a larger number of bytes than the vector actually has, we need - // to be sure to clamp the vector to at most its capacity. - let new_len = cmp::min(v.capacity(), v.len() + n); - v.set_len(new_len); - return Ok(n); - } - - // Semi-hack used to prevent LLVM from retaining any assumptions about - // `dummy` over this function call - unsafe fn black_box(mut dummy: T) -> T { - asm!("" :: "r"(&mut dummy) : "memory"); - dummy + let len = v.len(); + let new_area = v.capacity() - len; + v.extend(iter::repeat(0).take(new_area)); + match f(&mut v[len..]) { + Ok(n) => { + v.truncate(len + n); + Ok(n) + } + Err(e) => { + v.truncate(len); + Err(e) + } } } From 406524682bc54e821b78dc0ef5a30e6294d9997d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 16:58:08 -0400 Subject: [PATCH 12/32] An example for clone --- src/libcore/clone.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 058eff121e63..85e5bde48598 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -27,6 +27,14 @@ use marker::Sized; #[stable(feature = "rust1", since = "1.0.0")] pub trait Clone : Sized { /// Returns a copy of the value. + /// + /// # Examples + /// + /// ``` + /// let hello = "Hello"; // &str implements Clone + /// + /// assert_eq!("Hello", hello.clone()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn clone(&self) -> Self; From 95602a759d9190cad92279aa5929d30166f2255c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 20 Mar 2015 17:15:27 +1300 Subject: [PATCH 13/32] 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; ``` --- src/libarena/lib.rs | 3 +- src/libcollections/lib.rs | 2 + src/libcollections/vec.rs | 4 +- src/libcore/cell.rs | 6 +- src/libcore/fmt/mod.rs | 6 + src/libcore/fmt/num.rs | 1 + src/libcore/hash/mod.rs | 2 + src/libcore/mem.rs | 2 + src/libcore/num/i16.rs | 1 + src/libcore/num/i32.rs | 1 + src/libcore/num/i64.rs | 1 + src/libcore/num/i8.rs | 1 + src/libcore/num/int_macros.rs | 1 + src/libcore/num/isize.rs | 1 + src/libcore/num/mod.rs | 1 + src/libcore/num/u16.rs | 1 + src/libcore/num/u32.rs | 1 + src/libcore/num/u64.rs | 1 + src/libcore/num/u8.rs | 1 + src/libcore/num/uint_macros.rs | 1 + src/libcore/num/usize.rs | 1 + src/libcore/ptr.rs | 2 +- src/libcore/str/mod.rs | 2 +- src/libcoretest/mem.rs | 2 +- src/libcoretest/ptr.rs | 14 +- src/liblog/lib.rs | 4 +- src/librand/distributions/range.rs | 2 + src/librand/isaac.rs | 1 + src/librbml/lib.rs | 4 +- src/librustc/lib.rs | 3 + src/librustc/lint/builtin.rs | 15 +- src/librustc/middle/ty.rs | 33 +--- src/librustc_lint/builtin.rs | 3 + src/librustc_lint/lib.rs | 8 +- src/librustc_llvm/lib.rs | 2 + src/librustc_trans/lib.rs | 3 + src/librustc_trans/trans/datum.rs | 9 -- src/librustc_trans/trans/expr.rs | 24 +-- src/librustc_trans/trans/meth.rs | 40 +---- src/librustc_typeck/check/coercion.rs | 12 +- src/librustc_typeck/check/demand.rs | 8 +- src/librustc_typeck/check/mod.rs | 150 ++++++++++-------- src/librustc_typeck/check/vtable.rs | 78 --------- src/librustdoc/html/markdown.rs | 14 +- src/libserialize/json.rs | 10 +- src/libstd/lib.rs | 2 + src/libstd/old_io/stdio.rs | 4 +- src/libstd/rt/mod.rs | 2 +- src/libsyntax/codemap.rs | 6 +- src/libsyntax/ext/base.rs | 6 +- src/libsyntax/ext/quote.rs | 1 + src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 4 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/libterm/lib.rs | 12 +- src/libterm/terminfo/mod.rs | 4 +- src/libterm/terminfo/parser/compiled.rs | 2 +- src/libtest/lib.rs | 2 +- src/rustbook/subcommand.rs | 10 +- src/test/auxiliary/issue-11224.rs | 2 +- src/test/compile-fail/issue-14845.rs | 4 +- src/test/compile-fail/issue-16538.rs | 3 +- src/test/compile-fail/issue-5543.rs | 19 --- .../compile-fail/kindck-impl-type-params.rs | 1 + src/test/compile-fail/lint-dead-code-3.rs | 2 +- .../compile-fail/lint-unnecessary-casts.rs | 24 --- src/test/compile-fail/liveness-unused.rs | 2 +- .../object-safety-by-value-self.rs | 1 + .../regions-close-object-into-object-5.rs | 1 + .../regions-close-over-type-parameter-1.rs | 2 + ...rameter-defaults-referencing-Self-ppaux.rs | 2 +- .../compile-fail/vector-cast-weirdness.rs | 6 +- src/test/debuginfo/type-names.rs | 12 +- src/test/pretty/path-type-bounds.rs | 2 +- .../run-make/symbols-are-reasonable/lib.rs | 2 +- .../run-pass/autoderef-method-on-trait.rs | 2 +- src/test/run-pass/cast-region-to-uint.rs | 2 +- .../infer-container-across-object-cast.rs | 61 ------- src/test/run-pass/issue-15763.rs | 8 +- src/test/run-pass/issue-5708.rs | 2 +- src/test/run-pass/issue-9719.rs | 6 +- ...o-traits-distinguished-via-where-clause.rs | 2 +- .../run-pass/object-one-type-two-traits.rs | 2 +- .../objects-coerce-freeze-borrored.rs | 2 +- .../regions-early-bound-trait-param.rs | 5 +- src/test/run-pass/stable-addr-of.rs | 2 +- src/test/run-pass/task-spawn-move-and-copy.rs | 2 +- .../run-pass/typeck_type_placeholder_1.rs | 10 +- .../run-pass/zero_sized_subslice_match.rs | 2 +- 90 files changed, 287 insertions(+), 449 deletions(-) delete mode 100644 src/test/compile-fail/issue-5543.rs delete mode 100644 src/test/compile-fail/lint-unnecessary-casts.rs delete mode 100644 src/test/run-pass/infer-container-across-object-cast.rs diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 1b0356b88b08..7843be0b483e 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -429,7 +429,8 @@ impl TypedArenaChunk { // Destroy the next chunk. let next = self.next; let size = calculate_size::(self.capacity); - deallocate(self as *mut TypedArenaChunk as *mut u8, size, + let self_ptr: *mut TypedArenaChunk = self; + deallocate(self_ptr as *mut u8, size, mem::min_align_of::>()); if !next.is_null() { let capacity = (*next).capacity; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index da2c61b6fd39..0a61eeb6e1c6 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -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)] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 59819d01bc60..af2daabc2d02 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1199,8 +1199,8 @@ impl Vec { // 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); diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index a9c5de23d948..f5db3e63c7ad 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -713,7 +713,11 @@ impl UnsafeCell { /// ``` #[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 /// diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index cf427c16588d..e00cdc9de88d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -833,6 +833,8 @@ impl Pointer for *const T { #[stable(feature = "rust1", since = "1.0.0")] impl 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 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) } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 49da99b97cb2..d01d240e5b5f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -13,6 +13,7 @@ // FIXME: #6220 Implement floating point formatting #![allow(unsigned_negation)] +#![allow(trivial_numeric_cast)] use fmt; use iter::IteratorExt; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 1d5e174a8dc9..ccc1d32eab35 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -182,6 +182,8 @@ mod impls { } fn hash_slice(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) }) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 551f97ead12d..0bc41eb2c6ea 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -313,6 +313,8 @@ pub fn drop(_x: T) { } #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn transmute_copy(src: &T) -> U { + // FIXME(#23542) Replace with type ascription. + #![allow(trivial_cast)] ptr::read(src as *const T as *const U) } diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 5ea60d0d96d2..1557434a28a2 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i16")] +#![allow(trivial_numeric_cast)] int_module! { i16, 16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 7d9faa998c12..bdccab4cb9a9 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i32")] +#![allow(trivial_numeric_cast)] int_module! { i32, 32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 5a70911387b9..d8f5aa6e5483 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i64")] +#![allow(trivial_numeric_cast)] int_module! { i64, 64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 1d7d78ffa6c2..da2410a04cfe 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i8")] +#![allow(trivial_numeric_cast)] int_module! { i8, 8 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index fe0d6d13c4c0..5f697e02a994 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -9,6 +9,7 @@ // except according to those terms. #![doc(hidden)] +#![allow(trivial_numeric_cast)] macro_rules! int_module { ($T:ty, $bits:expr) => ( diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 0fd0d90b1250..838caa59e471 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -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 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9ca7b48fbe5e..7686a990acc9 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -14,6 +14,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#![allow(trivial_numeric_cast)] use self::wrapping::{OverflowingOps, WrappingOps}; diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 21635799a77a..9d91bbc7f901 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u16")] +#![allow(trivial_numeric_cast)] uint_module! { u16, i16, 16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 7d520770503d..2d5f163e093c 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u32")] +#![allow(trivial_numeric_cast)] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index f10822077dc7..26813aa281c6 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u64")] +#![allow(trivial_numeric_cast)] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 3d6922b07b19..7fb28f27d62a 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -12,5 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u8")] +#![allow(trivial_numeric_cast)] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index d0c4885ad00b..9f502e3ea431 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -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) => ( diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 602ef4fe45e7..be5acaac92ae 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -16,5 +16,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "usize")] +#![allow(trivial_numeric_cast)] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d92622eeb70e..9b3ee3ef5e0c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -529,7 +529,7 @@ impl Unique { /// Create a new `Unique`. #[unstable(feature = "unique")] pub unsafe fn new(ptr: *mut T) -> Unique { - Unique { pointer: NonZero::new(ptr as *const T), _marker: PhantomData } + Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } /// Dereference the content. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index b7285d30a730..035d070cd6d4 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -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; } diff --git a/src/libcoretest/mem.rs b/src/libcoretest/mem.rs index bf3e1cf03cbd..17d6b684c50e 100644 --- a/src/libcoretest/mem.rs +++ b/src/libcoretest/mem.rs @@ -95,7 +95,7 @@ fn test_transmute() { trait Foo { fn dummy(&self) { } } impl Foo for int {} - let a = box 100 as Box; + let a = box 100isize as Box; unsafe { let x: ::core::raw::TraitObject = transmute(a); assert!(*(x.data as *const int) == 100); diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index adc15b9fbc27..4f5f269d4375 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -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); } diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4537fc763c95..2c431e1e0508 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -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 = LOCAL_LOGGER.with(|s| { s.borrow_mut().take() }).unwrap_or_else(|| { - box DefaultLogger { handle: io::stderr() } as Box + box DefaultLogger { handle: io::stderr() } }); logger.log(&LogRecord { level: LogLevel(level), diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index e6f27a28ffa7..0001cb6e0caa 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -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}; diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 7ea62b7fd3f4..673246fe30dc 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -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(); diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 1a794f56f802..182b05acbb61 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -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 { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 793eff6a9da6..dd5f3cccea54 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -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; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 44718d1c5251..4f56f2441dc4 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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 ) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e5e89c3fbd4b..38a20c61d2e6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -968,7 +968,7 @@ impl<'tcx> Eq for TyS<'tcx> {} impl<'tcx> Hash for TyS<'tcx> { fn hash(&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>, }; 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, 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 } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e65fe904dd29..ef82a465ef4b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ef65acf8b13f..f2d2db18da4b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -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"); diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 506bf4a058fc..4d821df72a6e 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -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")] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index b9ec22b86f07..ef43b9c0de42 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -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; diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index e181df545e6f..15738d1e61ac 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -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, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index ceb9a29efa88..4d7431a20b70 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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); } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 4da17972c55f..d13076df6376 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -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`, etc) into an object -/// (`Box`, `&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) with an opaque pointer. pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) -> &'tcx ty::BareFnTy<'tcx> { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f731507ba906..920154bc916f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -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, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 6f2d0cb36674..cd6a1226e00c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -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), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c3f4937d26b0..4eddf8ae97a9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>>>, + + deferred_cast_checks: RefCell>>, } trait DeferredCallResolution<'tcx> { @@ -192,6 +194,15 @@ trait DeferredCallResolution<'tcx> { type DeferredCallResolutionHandler<'tcx> = Box+'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>> { + #![allow(trivial_numeric_cast)] use std::num::Int; let rty = ty::node_id_to_type(ccx.tcx, id); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 963be9aa2e2d..2858dc9b569f 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -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` - - // First, construct a fresh type that we can feed into `` - // within ` as ` 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 is cast to Ptr, 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 diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index cdd8457687ac..cfa84de5ca7c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -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(), diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index abbfc82319f5..17c414485407 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -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) + } })+ ) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 90eca6168f26..228b885b653c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -135,6 +135,8 @@ #![feature(no_std)] #![no_std] +#![allow(trivial_cast)] +#![allow(trivial_numeric_cast)] #![deny(missing_docs)] #[cfg(test)] extern crate test; diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs index ef811f832b39..b77c8d50997f 100644 --- a/src/libstd/old_io/stdio.rs +++ b/src/libstd/old_io/stdio.rs @@ -337,10 +337,10 @@ pub fn set_stderr(_stderr: Box) -> Option> { // }) // }) fn with_task_stdout(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> { - let mut my_stdout = LOCAL_STDOUT.with(|slot| { + let mut my_stdout: Box = LOCAL_STDOUT.with(|slot| { slot.borrow_mut().take() }).unwrap_or_else(|| { - box stdout() as Box + box stdout() }); let result = f(&mut *my_stdout); let mut var = Some(my_stdout); diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index e52e68dad23f..86b1d031f688 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -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 diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1abe8d0a3c1b..6a00fff18600 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -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} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 35449bde0b2e..b679456b3537 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -264,7 +264,7 @@ macro_rules! make_MacEager { box MacEager { $fld: Some(v), ..Default::default() - } as Box + } } )* } @@ -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 { - box DummyResult { expr_only: false, span: sp } as Box + 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 { - box DummyResult { expr_only: true, span: sp } as Box + box DummyResult { expr_only: true, span: sp } } /// A plain dummy expression. diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c11ffe66e6c3..1aceec310e1a 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -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)) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 5940b7918437..1e53db603014 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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 + } } Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e0953a8ace68..0843713681bb 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -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; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4ae5e0faa310..44097ffeb205 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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 { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 828d085fd432..5941f044a078 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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)) diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index c907b87bc3c6..41e066cc94a9 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -103,7 +103,7 @@ impl Write for WriterWrapper { /// opened. pub fn stdout() -> Option + Send>> { TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, + wrapped: box std::io::stdout(), }) } @@ -112,14 +112,14 @@ pub fn stdout() -> Option + Send>> { /// opened. pub fn stdout() -> Option + Send>> { let ti = TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, + wrapped: box std::io::stdout(), }); match ti { Some(t) => Some(t), None => { WinConsole::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, + wrapped: box std::io::stdout(), }) } } @@ -130,7 +130,7 @@ pub fn stdout() -> Option + Send>> { /// opened. pub fn stderr() -> Option + Send>> { TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, + wrapped: box std::io::stderr(), }) } @@ -139,14 +139,14 @@ pub fn stderr() -> Option + Send>> { /// opened. pub fn stderr() -> Option + Send>> { let ti = TerminfoTerminal::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, + wrapped: box std::io::stderr(), }); match ti { Some(t) => Some(t), None => { WinConsole::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, + wrapped: box std::io::stderr(), }) } } diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs index 309320b52ffe..1d6657d5932c 100644 --- a/src/libterm/terminfo/mod.rs +++ b/src/libterm/terminfo/mod.rs @@ -190,7 +190,7 @@ impl TerminfoTerminal { out: out, ti: msys_terminfo(), num_colors: 8, - } as Box+Send>) + }) }, _ => { debug!("error finding terminfo entry: {:?}", err); @@ -213,7 +213,7 @@ impl TerminfoTerminal { return Some(box TerminfoTerminal {out: out, ti: inf, - num_colors: nc} as Box+Send>); + num_colors: nc}); } fn dim_if_necessary(&self, color: color::Color) -> color::Color { diff --git a/src/libterm/terminfo/parser/compiled.rs b/src/libterm/terminfo/parser/compiled.rs index cc9a2880b5d0..8d0a9e6e9717 100644 --- a/src/libterm/terminfo/parser/compiled.rs +++ b/src/libterm/terminfo/parser/compiled.rs @@ -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; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 402774321bfc..c48c7e413d03 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1021,7 +1021,7 @@ impl MetricMap { let MetricMap(ref mm) = *self; let v : Vec = mm.iter() .map(|(k,v)| format!("{}: {} (+/- {})", *k, - v.value as f64, v.noise as f64)) + v.value, v.noise)) .collect(); v.connect(", ") } diff --git a/src/rustbook/subcommand.rs b/src/rustbook/subcommand.rs index 473739c919d6..44af43be7877 100644 --- a/src/rustbook/subcommand.rs +++ b/src/rustbook/subcommand.rs @@ -32,11 +32,11 @@ pub trait Subcommand { /// Create a Subcommand object based on its name. pub fn parse_name(name: &str) -> Option> { - for parser in [ - help::parse_cmd as fn(&str) -> Option>, - build::parse_cmd as fn(&str) -> Option>, - serve::parse_cmd as fn(&str) -> Option>, - test::parse_cmd as fn(&str) -> Option>].iter() { + let cmds: [fn(&str) -> Option>; 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 } } diff --git a/src/test/auxiliary/issue-11224.rs b/src/test/auxiliary/issue-11224.rs index 560844332a12..d66cfe9bf636 100644 --- a/src/test/auxiliary/issue-11224.rs +++ b/src/test/auxiliary/issue-11224.rs @@ -21,6 +21,6 @@ mod inner { } pub fn foo() { - let a = &1 as &inner::Trait; + let a = &1i as &inner::Trait; a.f(); } diff --git a/src/test/compile-fail/issue-14845.rs b/src/test/compile-fail/issue-14845.rs index d7bb806999c7..3f994102a173 100644 --- a/src/test/compile-fail/issue-14845.rs +++ b/src/test/compile-fail/issue-14845.rs @@ -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 } diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs index 6d2cfcab04e3..a4e0f69b63b3 100644 --- a/src/test/compile-fail/issue-16538.rs +++ b/src/test/compile-fail/issue-16538.rs @@ -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() {} diff --git a/src/test/compile-fail/issue-5543.rs b/src/test/compile-fail/issue-5543.rs deleted file mode 100644 index c27362eea3e3..000000000000 --- a/src/test/compile-fail/issue-5543.rs +++ /dev/null @@ -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 or the MIT license -// , 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 = Box::new(5); - let _m: Box = r as Box; - //~^ ERROR `core::marker::Sized` is not implemented for the type `Foo` -} diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index dffc8fa2abd7..71494fd5f38d 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -28,6 +28,7 @@ fn f(val: T) { let a = &t as &Gettable; //~^ 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(val: T) { diff --git a/src/test/compile-fail/lint-dead-code-3.rs b/src/test/compile-fail/lint-dead-code-3.rs index 13ee3f163616..ba1b7f03b0f4 100644 --- a/src/test/compile-fail/lint-dead-code-3.rs +++ b/src/test/compile-fail/lint-dead-code-3.rs @@ -86,6 +86,6 @@ mod inner { } pub fn foo() { - let a = &1 as &inner::Trait; + let a: &inner::Trait = &1_isize; a.f(); } diff --git a/src/test/compile-fail/lint-unnecessary-casts.rs b/src/test/compile-fail/lint-unnecessary-casts.rs deleted file mode 100644 index b3cf8257b8f6..000000000000 --- a/src/test/compile-fail/lint-unnecessary-casts.rs +++ /dev/null @@ -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 or the MIT license -// , 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 -} diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index ac4b8a5f3090..addeba03ab87 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -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` diff --git a/src/test/compile-fail/object-safety-by-value-self.rs b/src/test/compile-fail/object-safety-by-value-self.rs index 976717249e8e..3b0e5786f3db 100644 --- a/src/test/compile-fail/object-safety-by-value-self.rs +++ b/src/test/compile-fail/object-safety-by-value-self.rs @@ -12,6 +12,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] +#![allow(trivial_cast)] trait Bar { fn bar(self); diff --git a/src/test/compile-fail/regions-close-object-into-object-5.rs b/src/test/compile-fail/regions-close-object-into-object-5.rs index f3b5ccabe79e..253132e5f07d 100644 --- a/src/test/compile-fail/regions-close-object-into-object-5.rs +++ b/src/test/compile-fail/regions-close-object-into-object-5.rs @@ -24,6 +24,7 @@ impl<'a, T> X for B<'a, T> {} fn f<'a, T, U>(v: Box+'static>) -> Box { box B(&*v) as Box //~ ERROR the parameter type `T` may not live long enough + //~^ ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/compile-fail/regions-close-over-type-parameter-1.rs b/src/test/compile-fail/regions-close-over-type-parameter-1.rs index fc18095fc833..924044647d84 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-1.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-1.rs @@ -19,6 +19,7 @@ trait SomeTrait { fn get(&self) -> isize; } fn make_object1(v: A) -> Box { box v as Box //~^ 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 { @@ -28,6 +29,7 @@ fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { box v as Box //~^ ERROR the parameter type `A` may not live long enough + //~^^ ERROR the parameter type `A` may not live long enough } fn main() { } diff --git a/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs index 8ff514e04e36..8cc531625d17 100644 --- a/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs +++ b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs @@ -20,7 +20,7 @@ impl MyAdd for i32 { } fn main() { - let x = 5; + let x: i32 = 5; let y = x as MyAdd; //~^ ERROR as `MyAdd` } diff --git a/src/test/compile-fail/vector-cast-weirdness.rs b/src/test/compile-fail/vector-cast-weirdness.rs index 97e67cd2eae2..cac52306d6ae 100644 --- a/src/test/compile-fail/vector-cast-weirdness.rs +++ b/src/test/compile-fail/vector-cast-weirdness.rs @@ -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]; diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index bf26fc23d3c1..d4cbd255e34c 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -291,15 +291,15 @@ fn main() { let slice2 = &*vec2; // Trait Objects - let box_trait = (box 0) as Box; - let ref_trait = &0 as &Trait1; - let mut mut_int1 = 0; + let box_trait = (box 0_isize) as Box; + 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>; - let generic_ref_trait = (&0) as &Trait2; + let generic_box_trait = (box 0_isize) as Box>; + let generic_ref_trait = (&0_isize) as &Trait2; - 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>; diff --git a/src/test/pretty/path-type-bounds.rs b/src/test/pretty/path-type-bounds.rs index 0a20300e4f4d..42b2fe806e95 100644 --- a/src/test/pretty/path-type-bounds.rs +++ b/src/test/pretty/path-type-bounds.rs @@ -21,5 +21,5 @@ fn foo<'a>(x: Box) -> Box { x } fn main() { let x: Box; - Box::new(1) as Box; + Box::new(1isize) as Box; } diff --git a/src/test/run-make/symbols-are-reasonable/lib.rs b/src/test/run-make/symbols-are-reasonable/lib.rs index f81d4803f8fa..474a6782b616 100644 --- a/src/test/run-make/symbols-are-reasonable/lib.rs +++ b/src/test/run-make/symbols-are-reasonable/lib.rs @@ -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; } diff --git a/src/test/run-pass/autoderef-method-on-trait.rs b/src/test/run-pass/autoderef-method-on-trait.rs index 6a038927f4a4..0bec3af4273a 100644 --- a/src/test/run-pass/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoderef-method-on-trait.rs @@ -22,6 +22,6 @@ impl double for uint { } pub fn main() { - let x: Box<_> = box() (box 3 as Box); + let x: Box<_> = box() (box 3u as Box); assert_eq!(x.double(), 6); } diff --git a/src/test/run-pass/cast-region-to-uint.rs b/src/test/run-pass/cast-region-to-uint.rs index a298a08a1b7a..deb0c0d0dc0d 100644 --- a/src/test/run-pass/cast-region-to-uint.rs +++ b/src/test/run-pass/cast-region-to-uint.rs @@ -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)); } diff --git a/src/test/run-pass/infer-container-across-object-cast.rs b/src/test/run-pass/infer-container-across-object-cast.rs deleted file mode 100644 index 7347ded99e7c..000000000000 --- a/src/test/run-pass/infer-container-across-object-cast.rs +++ /dev/null @@ -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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Given ` as Box`, 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 { 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; - 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(); -} diff --git a/src/test/run-pass/issue-15763.rs b/src/test/run-pass/issue-15763.rs index 7bfd8e0ab718..f30991a19635 100644 --- a/src/test/run-pass/issue-15763.rs +++ b/src/test/run-pass/issue-15763.rs @@ -87,12 +87,12 @@ fn main() { assert_eq!(cc().unwrap(), 3); assert_eq!(dd().unwrap(), 3); - let i = box 32 as Box; + let i = box 32i as Box; assert_eq!(i.aaa(), 3); - let i = box 32 as Box; + let i = box 32i as Box; assert_eq!(i.bbb(), 3); - let i = box 32 as Box; + let i = box 32i as Box; assert_eq!(i.ccc().unwrap(), 3); - let i = box 32 as Box; + let i = box 32i as Box; assert_eq!(i.ddd().unwrap(), 3); } diff --git a/src/test/run-pass/issue-5708.rs b/src/test/run-pass/issue-5708.rs index 59bca87bed0b..54773d71cbec 100644 --- a/src/test/run-pass/issue-5708.rs +++ b/src/test/run-pass/issue-5708.rs @@ -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(); } diff --git a/src/test/run-pass/issue-9719.rs b/src/test/run-pass/issue-9719.rs index 669a5cdfe304..6e88379f9a41 100644 --- a/src/test/run-pass/issue-9719.rs +++ b/src/test/run-pass/issue-9719.rs @@ -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() {} diff --git a/src/test/run-pass/method-two-traits-distinguished-via-where-clause.rs b/src/test/run-pass/method-two-traits-distinguished-via-where-clause.rs index c8da4852ad35..de8d116255ba 100644 --- a/src/test/run-pass/method-two-traits-distinguished-via-where-clause.rs +++ b/src/test/run-pass/method-two-traits-distinguished-via-where-clause.rs @@ -33,6 +33,6 @@ impl 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(); } diff --git a/src/test/run-pass/object-one-type-two-traits.rs b/src/test/run-pass/object-one-type-two-traits.rs index f8a3ce7cda01..baf8c6e4c979 100644 --- a/src/test/run-pass/object-one-type-two-traits.rs +++ b/src/test/run-pass/object-one-type-two-traits.rs @@ -35,7 +35,7 @@ fn is(x: &Any) -> bool { } fn main() { - let x = box 22 as Box; + let x = box 22isize as Box; println!("x={}", x.get()); let y = x.wrap(); } diff --git a/src/test/run-pass/objects-coerce-freeze-borrored.rs b/src/test/run-pass/objects-coerce-freeze-borrored.rs index efdd42c382c1..368842ed1b03 100644 --- a/src/test/run-pass/objects-coerce-freeze-borrored.rs +++ b/src/test/run-pass/objects-coerce-freeze-borrored.rs @@ -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); diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 63fb18a8ba2c..c87c79ca24ed 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -83,7 +83,10 @@ impl<'s> Trait<'s> for (int,int) { } impl<'t> MakerTrait for Box+'static> { - fn mk() -> Box+'static> { box() (4,5) as Box } + fn mk() -> Box+'static> { + let tup: Box<(int, int)> = box() (4,5); + tup as Box + } } enum List<'l> { diff --git a/src/test/run-pass/stable-addr-of.rs b/src/test/run-pass/stable-addr-of.rs index 152fb5dc9610..920cd9e03ab6 100644 --- a/src/test/run-pass/stable-addr-of.rs +++ b/src/test/run-pass/stable-addr-of.rs @@ -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); } diff --git a/src/test/run-pass/task-spawn-move-and-copy.rs b/src/test/run-pass/task-spawn-move-and-copy.rs index a6c6db1a1273..5c0d0fe9a63d 100644 --- a/src/test/run-pass/task-spawn-move-and-copy.rs +++ b/src/test/run-pass/task-spawn-move-and-copy.rs @@ -19,7 +19,7 @@ use std::sync::mpsc::channel; pub fn main() { let (tx, rx) = channel::(); - let x: Box<_> = box 1; + let x: Box = box 1; let x_in_parent = &(*x) as *const int as uint; let _t = Thread::spawn(move || { diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index f4c0992ae1a5..53e78db68b19 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -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::>(); @@ -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); } diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs index 4cb7e40a4fbd..ba1259974706 100644 --- a/src/test/run-pass/zero_sized_subslice_match.rs +++ b/src/test/run-pass/zero_sized_subslice_match.rs @@ -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 ()) } } From 9374c216f6040189301aeb043d317c12ffb17a0b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 15:26:51 +1300 Subject: [PATCH 14/32] Minor refactoring in coercion.rs --- src/librustc_typeck/check/coercion.rs | 308 ++++++++++++++------------ 1 file changed, 162 insertions(+), 146 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 920154bc916f..8ad11e19b347 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -258,70 +258,64 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match (&a.sty, &b.sty) { (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => { - self.unpack_actual_value(t_a, |a| { - match self.unsize_ty(t_a, a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let coercion = Coercion(self.trace.clone()); - let r_borrow = self.fcx.infcx().next_region_var(coercion); - let ty = ty::mk_rptr(self.tcx(), - self.tcx().mk_region(r_borrow), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) + match self.unsize_ty(t_a, mt_b.ty) { + Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); } - _ => Err(ty::terr_mismatch) + + let coercion = Coercion(self.trace.clone()); + let r_borrow = self.fcx.infcx().next_region_var(coercion); + let ty = ty::mk_rptr(self.tcx(), + self.tcx().mk_region(r_borrow), + ty::mt{ty: ty, mutbl: mt_b.mutbl}); + try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoPtr(AutoUnsize({:?})))", kind); + Ok(Some(AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, + Some(box AutoUnsize(kind)))) + }))) } - }) + _ => Err(ty::terr_mismatch) + } } (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => { - self.unpack_actual_value(t_a, |a| { - match self.unsize_ty(t_a, a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let ty = ty::mk_ptr(self.tcx(), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) + match self.unsize_ty(t_a, mt_b.ty) { + Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); } - _ => Err(ty::terr_mismatch) + + let ty = ty::mk_ptr(self.tcx(), + ty::mt{ty: ty, mutbl: mt_b.mutbl}); + try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoPtr(AutoUnsize({:?})))", kind); + Ok(Some(AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsafe(mt_b.mutbl, + Some(box AutoUnsize(kind)))) + }))) } - }) + _ => Err(ty::terr_mismatch) + } } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - self.unpack_actual_value(t_a, |a| { - match self.unsize_ty(t_a, a, t_b) { - Some((ty, kind)) => { - let ty = ty::mk_uniq(self.tcx(), ty); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoUnsizeUniq({:?}))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsizeUniq(kind)) - }))) - } - _ => Err(ty::terr_mismatch) + match self.unsize_ty(t_a, t_b) { + Some((ty, kind)) => { + let ty = ty::mk_uniq(self.tcx(), ty); + try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoUnsizeUniq({:?}))", kind); + Ok(Some(AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsizeUniq(kind)) + }))) } - }) + _ => Err(ty::terr_mismatch) + } } _ => Err(ty::terr_mismatch) } @@ -332,112 +326,134 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` fn unsize_ty(&self, ty_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>)> { let tcx = self.tcx(); - self.unpack_actual_value(ty_b, |b| { - debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); - match (&a.sty, &b.sty) { - (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => { - let ty = ty::mk_vec(tcx, t_a, None); - Some((ty, ty::UnsizeLength(len))) - } - (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { - // Upcasts permit two things: - // - // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` - // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { - // construct a type `a1` which is a version of - // `a` using the upcast bounds from `b` - let bounds_a1 = ty::ExistentialBounds { - // From type b - region_bound: data_b.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - - // From type a - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); - - // relate `a1` to `b` - let result = self.fcx.infcx().try(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(data_a.bounds.region_bound, - data_b.bounds.region_bound)); - self.subtype(ty_a1, ty_b) - }); - - // if that was successful, we have a coercion - match result { - Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), - Err(_) => None, - } - } else { - None + self.unpack_actual_value(ty_a, |a| { + self.unpack_actual_value(ty_b, |b| { + debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); + match (&a.sty, &b.sty) { + (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => { + let ty = ty::mk_vec(tcx, t_a, None); + Some((ty, ty::UnsizeLength(len))) } - } - (_, &ty::ty_trait(ref data)) => { - Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(), - bounds: data.bounds.clone() }, - ty_a))) - } - (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) - if did_a == did_b => { - debug!("unsizing a struct"); - // Try unsizing each type param in turn to see if we end up with ty_b. - let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); - let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); - assert!(ty_substs_a.len() == ty_substs_b.len()); + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // Upcasts permit two things: + // + // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` + // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { + // construct a type `a1` which is a version of + // `a` using the upcast bounds from `b` + let bounds_a1 = ty::ExistentialBounds { + // From type b + region_bound: data_b.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, - let mut result = None; - let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); - for (i, (tp_a, tp_b)) in tps { - if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { - continue; + // From type a + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); + + // relate `a1` to `b` + let result = self.fcx.infcx().try(|_| { + // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b + try!(self.outlives(data_a.bounds.region_bound, + data_b.bounds.region_bound)); + self.subtype(ty_a1, ty_b) + }); + + // if that was successful, we have a coercion + match result { + Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), + Err(_) => None, + } + } else { + None } - match - self.unpack_actual_value( - *tp_a, - |tp| self.unsize_ty(*tp_a, tp, *tp_b)) + } + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // For now, we only support upcasts from + // `Foo+Send` to `Foo` (really, any time there are + // fewer builtin bounds then before). These are + // convenient because they don't require any sort + // of change to the vtable at runtime. + if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds && + data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { - Some((new_tp, k)) => { - // Check that the whole types match. - let mut new_substs = substs_a.clone(); - new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; - let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); - if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { - debug!("Unsized type parameter '{}', but still \ - could not match types {} and {}", - ppaux::ty_to_string(tcx, *tp_a), - ppaux::ty_to_string(tcx, ty), - ppaux::ty_to_string(tcx, ty_b)); - // We can only unsize a single type parameter, so - // if we unsize one and it doesn't give us the - // type we want, then we won't succeed later. + let bounds_a1 = ty::ExistentialBounds { + region_bound: data_a.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); + match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) { + Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), + Err(_) => None, + } + } else { + None + } + } + (_, &ty::ty_trait(ref data)) => { + Some((ty_b, ty::UnsizeVtable(ty::TyTrait { + principal: data.principal.clone(), + bounds: data.bounds.clone() + }, + ty_a))) + } + (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) + if did_a == did_b => { + debug!("unsizing a struct"); + // Try unsizing each type param in turn to see if we end up with ty_b. + let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); + let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); + assert!(ty_substs_a.len() == ty_substs_b.len()); + + let mut result = None; + let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); + for (i, (tp_a, tp_b)) in tps { + if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { + continue; + } + match self.unsize_ty(*tp_a, *tp_b) { + Some((new_tp, k)) => { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; + let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); + if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { + debug!("Unsized type parameter '{}', but still \ + could not match types {} and {}", + ppaux::ty_to_string(tcx, *tp_a), + ppaux::ty_to_string(tcx, ty), + ppaux::ty_to_string(tcx, ty_b)); + // We can only unsize a single type parameter, so + // if we unsize one and it doesn't give us the + // type we want, then we won't succeed later. + break; + } + + result = Some((ty, ty::UnsizeStruct(box k, i))); break; } - - result = Some((ty, ty::UnsizeStruct(box k, i))); - break; + None => {} } - None => {} } + result } - result + _ => None } - _ => None - } + }) }) } From 088cd566ea87c90a9c765a113a2310d60849e7c1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 15:50:32 +1300 Subject: [PATCH 15/32] Remove the UnusedCasts lint --- src/librustc_lint/builtin.rs | 24 ------------------------ src/librustc_lint/lib.rs | 1 - 2 files changed, 25 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ef82a465ef4b..395460aca9fe 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -84,30 +84,6 @@ impl LintPass for WhileTrue { } } -declare_lint! { - UNUSED_TYPECASTS, - Allow, - "detects unnecessary type casts that can be removed" -} - -#[derive(Copy)] -pub struct UnusedCasts; - -impl LintPass for UnusedCasts { - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_TYPECASTS) - } - - fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { - if let ast::ExprCast(ref expr, ref ty) = e.node { - let t_t = ty::expr_ty(cx.tcx, e); - if ty::expr_ty(cx.tcx, &**expr) == t_t { - cx.span_lint(UNUSED_TYPECASTS, ty.span, "unnecessary type cast"); - } - } - } -} - declare_lint! { UNSIGNED_NEGATION, Warn, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index f2d2db18da4b..e158541cd1cf 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -89,7 +89,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { add_builtin!(sess, HardwiredLints, WhileTrue, - UnusedCasts, ImproperCTypes, BoxPointers, UnusedAttributes, From dc206a91c8b641b4eccd51541f59d96fabea877d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 17:28:57 +1300 Subject: [PATCH 16/32] Add tests --- src/librustc_typeck/check/mod.rs | 4 +- src/test/compile-fail/trivial_casts.rs | 94 ++++++++++++++++++++++++++ src/test/run-pass/trivial_casts.rs | 71 +++++++++++++++++++ 3 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/trivial_casts.rs create mode 100644 src/test/run-pass/trivial_casts.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4eddf8ae97a9..c8c7fb046b17 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1091,14 +1091,14 @@ fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CAST, e.id, span, - format!("trivial numeric cast: {} as {}", + 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 {}", + format!("trivial cast: `{}` as `{}`", fcx.infcx().ty_to_string(t_e), fcx.infcx().ty_to_string(t_1))); } diff --git a/src/test/compile-fail/trivial_casts.rs b/src/test/compile-fail/trivial_casts.rs new file mode 100644 index 000000000000..05c7747d5b92 --- /dev/null +++ b/src/test/compile-fail/trivial_casts.rs @@ -0,0 +1,94 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test the trivial_cast and trivial_numeric_cast lints. For each error we also +// check that the cast can be done using just coercion. + +#![deny(trivial_cast, trivial_numeric_cast)] + +trait Foo { + fn foo(&self) {} +} + +pub struct Bar; + +impl Foo for Bar {} + +pub fn main() { + // Numeric + let _ = 42_i32 as i32; //~ ERROR trivial numeric cast: `i32` as `i32` + let _: i32 = 42_i32; + + let _ = 42_u8 as u8; //~ ERROR trivial numeric cast: `u8` as `u8` + let _: u8 = 42_u8; + + // & to * pointers + let x: &u32 = &42; + let _ = x as *const u32; //~ERROR trivial cast: `&u32` as `*const u32` + let _: *const u32 = x; + + let x: &mut u32 = &mut 42; + let _ = x as *mut u32; //~ERROR trivial cast: `&mut u32` as `*mut u32` + let _: *mut u32 = x; + + // unsize array + let x: &[u32; 3] = &[42, 43, 44]; + let _ = x as &[u32]; //~ERROR trivial cast: `&[u32; 3]` as `&[u32]` + let _ = x as *const [u32]; //~ERROR trivial cast: `&[u32; 3]` as `*const [u32]` + let _: &[u32] = x; + let _: *const [u32] = x; + + let x: &mut [u32; 3] = &mut [42, 43, 44]; + let _ = x as &mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `&mut [u32]` + let _ = x as *mut [u32]; //~ERROR trivial cast: `&mut [u32; 3]` as `*mut [u32]` + let _: &mut [u32] = x; + let _: *mut [u32] = x; + + let x: Box<[u32; 3]> = Box::new([42, 43, 44]); + let _ = x as Box<[u32]>; //~ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` + let x: Box<[u32; 3]> = Box::new([42, 43, 44]); + let _: Box<[u32]> = x; + + // unsize trait + let x: &Bar = &Bar; + let _ = x as &Foo; //~ERROR trivial cast: `&Bar` as `&Foo` + let _ = x as *const Foo; //~ERROR trivial cast: `&Bar` as `*const Foo` + let _: &Foo = x; + let _: *const Foo = x; + + let x: &mut Bar = &mut Bar; + let _ = x as &mut Foo; //~ERROR trivial cast: `&mut Bar` as `&mut Foo` + let _ = x as *mut Foo; //~ERROR trivial cast: `&mut Bar` as `*mut Foo` + let _: &mut Foo = x; + let _: *mut Foo = x; + + let x: Box = Box::new(Bar); + let _ = x as Box; //~ERROR trivial cast: `Box` as `Box` + let x: Box = Box::new(Bar); + let _: Box = x; + + // functions + fn baz(_x: i32) {} + let _ = &baz as &Fn(i32); //~ERROR trivial cast: `&fn(i32) {main::baz}` as `&core::ops::Fn(i32)` + let _: &Fn(i32) = &baz; + let x = |_x: i32| {}; + let _ = &x as &Fn(i32); //~ERROR trivial cast + let _: &Fn(i32) = &x; +} + +// subtyping +pub fn test_subtyping<'a, 'b: 'a>(a: &'a Bar, b: &'b Bar) { + let _ = a as &'a Bar; //~ERROR trivial cast + let _: &'a Bar = a; + let _ = b as &'a Bar; //~ERROR trivial cast + let _: &'a Bar = b; + let _ = b as &'b Bar; //~ERROR trivial cast + let _: &'b Bar = b; +} diff --git a/src/test/run-pass/trivial_casts.rs b/src/test/run-pass/trivial_casts.rs new file mode 100644 index 000000000000..4b145f1079be --- /dev/null +++ b/src/test/run-pass/trivial_casts.rs @@ -0,0 +1,71 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that all coercions can actually be done using casts (modulo the lints). + +#![allow(trivial_cast, trivial_numeric_cast)] + +trait Foo { + fn foo(&self) {} +} + +pub struct Bar; + +impl Foo for Bar {} + +pub fn main() { + // Numeric + let _ = 42_i32 as i32; + let _ = 42_u8 as u8; + + // & to * pointers + let x: &u32 = &42; + let _ = x as *const u32; + + let x: &mut u32 = &mut 42; + let _ = x as *mut u32; + + // unsize array + let x: &[u32; 3] = &[42, 43, 44]; + let _ = x as &[u32]; + let _ = x as *const [u32]; + + let x: &mut [u32; 3] = &mut [42, 43, 44]; + let _ = x as &mut [u32]; + let _ = x as *mut [u32]; + + let x: Box<[u32; 3]> = Box::new([42, 43, 44]); + let _ = x as Box<[u32]>; + + // unsize trait + let x: &Bar = &Bar; + let _ = x as &Foo; + let _ = x as *const Foo; + + let x: &mut Bar = &mut Bar; + let _ = x as &mut Foo; + let _ = x as *mut Foo; + + let x: Box = Box::new(Bar); + let _ = x as Box; + + // functions + fn baz(_x: i32) {} + let _ = &baz as &Fn(i32); + let x = |_x: i32| {}; + let _ = &x as &Fn(i32); +} + +// subtyping +pub fn test_subtyping<'a, 'b: 'a>(a: &'a Bar, b: &'b Bar) { + let _ = a as &'a Bar; + let _ = b as &'a Bar; + let _ = b as &'b Bar; +} From e7122a5a09d06aedd1d27d14c3ac38c40b0a7425 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 24 Mar 2015 11:23:34 +1300 Subject: [PATCH 17/32] Change lint names to plurals --- src/libcollections/lib.rs | 4 ++-- src/libcore/cell.rs | 2 +- src/libcore/fmt/mod.rs | 6 +++--- src/libcore/fmt/num.rs | 2 +- src/libcore/hash/mod.rs | 2 +- src/libcore/mem.rs | 2 +- src/libcore/num/i16.rs | 2 +- src/libcore/num/i32.rs | 2 +- src/libcore/num/i64.rs | 2 +- src/libcore/num/i8.rs | 2 +- src/libcore/num/int_macros.rs | 2 +- src/libcore/num/isize.rs | 2 +- src/libcore/num/mod.rs | 2 +- src/libcore/num/u16.rs | 2 +- src/libcore/num/u32.rs | 2 +- src/libcore/num/u64.rs | 2 +- src/libcore/num/u8.rs | 2 +- src/libcore/num/uint_macros.rs | 2 +- src/libcore/num/usize.rs | 2 +- src/librand/distributions/range.rs | 2 +- src/librand/isaac.rs | 2 +- src/librustc/lib.rs | 4 ++-- src/librustc/lint/builtin.rs | 8 ++++---- src/librustc_lint/builtin.rs | 2 +- src/librustc_llvm/lib.rs | 4 ++-- src/librustc_trans/lib.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 8 ++++---- src/libserialize/json.rs | 4 ++-- src/libstd/lib.rs | 4 ++-- src/libsyntax/ext/quote.rs | 2 +- src/test/compile-fail/liveness-unused.rs | 2 +- src/test/compile-fail/object-safety-by-value-self.rs | 2 +- src/test/compile-fail/trivial_casts.rs | 4 ++-- src/test/run-pass/trivial_casts.rs | 2 +- 34 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 0a61eeb6e1c6..6a65c991c950 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -24,8 +24,8 @@ html_playground_url = "http://play.rust-lang.org/")] #![doc(test(no_crate_inject))] -#![allow(trivial_cast)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_casts)] +#![allow(trivial_numeric_casts)] #![feature(alloc)] #![feature(box_syntax)] #![feature(box_patterns)] diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index f5db3e63c7ad..9e6dbce03259 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -715,7 +715,7 @@ impl UnsafeCell { #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> *mut T { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] &self.value as *const T as *mut T } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e00cdc9de88d..aa0d0a1539a3 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -834,7 +834,7 @@ impl Pointer for *const T { impl Pointer for *mut T { fn fmt(&self, f: &mut Formatter) -> Result { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] Pointer::fmt(&(*self as *const T), f) } } @@ -843,7 +843,7 @@ impl Pointer for *mut T { impl<'a, T> Pointer for &'a T { fn fmt(&self, f: &mut Formatter) -> Result { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] Pointer::fmt(&(*self as *const T), f) } } @@ -852,7 +852,7 @@ impl<'a, T> Pointer for &'a T { impl<'a, T> Pointer for &'a mut T { fn fmt(&self, f: &mut Formatter) -> Result { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] Pointer::fmt(&(&**self as *const T), f) } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index d01d240e5b5f..56d2eabc095a 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -13,7 +13,7 @@ // FIXME: #6220 Implement floating point formatting #![allow(unsigned_negation)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] use fmt; use iter::IteratorExt; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index ccc1d32eab35..2feb2f8b1e36 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -183,7 +183,7 @@ mod impls { fn hash_slice(data: &[$ty], state: &mut H) { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] let newlen = data.len() * ::$ty::BYTES as usize; let ptr = data.as_ptr() as *const u8; state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 0bc41eb2c6ea..1e6fb51a8a52 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -314,7 +314,7 @@ pub fn drop(_x: T) { } #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn transmute_copy(src: &T) -> U { // FIXME(#23542) Replace with type ascription. - #![allow(trivial_cast)] + #![allow(trivial_casts)] ptr::read(src as *const T as *const U) } diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 1557434a28a2..efafce3fdefb 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i16")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] int_module! { i16, 16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index bdccab4cb9a9..72b0236a8d2a 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i32")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] int_module! { i32, 32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index d8f5aa6e5483..a64a4febd5a9 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i64")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] int_module! { i64, 64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index da2410a04cfe..459814875ee0 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i8")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] int_module! { i8, 8 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 5f697e02a994..675f568a9609 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -9,7 +9,7 @@ // except according to those terms. #![doc(hidden)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] macro_rules! int_module { ($T:ty, $bits:expr) => ( diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 838caa59e471..9af51a367482 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -16,7 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "isize")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] #[cfg(target_pointer_width = "32")] int_module! { isize, 32 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7686a990acc9..0eec875afc3b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -14,7 +14,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] use self::wrapping::{OverflowingOps, WrappingOps}; diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 9d91bbc7f901..289c5dbd08ea 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u16")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] uint_module! { u16, i16, 16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 2d5f163e093c..6d0b6b0e5eaf 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u32")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index 26813aa281c6..bf8747fdb6e2 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u64")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 7fb28f27d62a..05199735d4ac 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -12,6 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u8")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 9f502e3ea431..c22f31cc57ea 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -9,7 +9,7 @@ // except according to those terms. #![doc(hidden)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => ( diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index be5acaac92ae..82dd3312782c 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -16,6 +16,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "usize")] -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 0001cb6e0caa..a682fa858417 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -10,7 +10,7 @@ //! Generating numbers between two others. -#![allow(trivial_numeric_cast)] +#![allow(trivial_numeric_casts)] // this is surprisingly complicated to be both generic & correct diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 673246fe30dc..14bebe0cd915 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -447,7 +447,7 @@ impl Rng for Isaac64Rng { #[inline] fn next_u64(&mut self) -> u64 { - #![allow(trivial_numeric_cast)] + #![allow(trivial_numeric_casts)] if self.cnt == 0 { // make some more numbers self.isaac64(); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index dd5f3cccea54..e8af07e43815 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -47,8 +47,8 @@ #![feature(into_cow)] #![cfg_attr(test, feature(test))] -#![allow(trivial_cast)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_casts)] +#![allow(trivial_numeric_casts)] extern crate arena; extern crate flate; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4f56f2441dc4..2cc47f258f07 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -101,13 +101,13 @@ declare_lint! { } declare_lint! { - pub TRIVIAL_CAST, + pub TRIVIAL_CASTS, Warn, "detects trivial casts which could be removed" } declare_lint! { - pub TRIVIAL_NUMERIC_CAST, + pub TRIVIAL_NUMERIC_CASTS, Warn, "detects trivial casts of numeric types which could be removed" } @@ -133,8 +133,8 @@ impl LintPass for HardwiredLints { UNKNOWN_CRATE_TYPES, VARIANT_SIZE_DIFFERENCES, FAT_PTR_TRANSMUTES, - TRIVIAL_CAST, - TRIVIAL_NUMERIC_CAST + TRIVIAL_CASTS, + TRIVIAL_NUMERIC_CASTS ) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 395460aca9fe..8b57a48f3ce7 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1781,7 +1781,7 @@ 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)] + #![allow(trivial_casts)] type F = for<'tcx> fn(&ty::ctxt<'tcx>, ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4d821df72a6e..9d564fa56f54 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -14,8 +14,8 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![allow(trivial_cast)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_casts)] +#![allow(trivial_numeric_casts)] #![crate_name = "rustc_llvm"] #![unstable(feature = "rustc_private")] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index ef43b9c0de42..99a64156d667 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -43,8 +43,8 @@ #![feature(convert)] #![feature(path_relative_from)] -#![allow(trivial_cast)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_casts)] +#![allow(trivial_numeric_casts)] extern crate arena; extern crate flate; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c8c7fb046b17..47aafa2251d9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1088,14 +1088,14 @@ fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { 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, + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, e.id, span, format!("trivial numeric cast: `{}` as `{}`", fcx.infcx().ty_to_string(t_e), fcx.infcx().ty_to_string(t_1))); } else { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CAST, + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, e.id, span, format!("trivial cast: `{}` as `{}`", @@ -4581,7 +4581,7 @@ 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)] + #![allow(trivial_numeric_casts)] match ty { ast::TyU8 => disr as u8 as Disr == disr, @@ -4611,7 +4611,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, id: ast::NodeId, hint: attr::ReprAttr) -> Vec>> { - #![allow(trivial_numeric_cast)] + #![allow(trivial_numeric_casts)] use std::num::Int; let rty = ty::node_id_to_type(ccx.tcx, id); diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 17c414485407..0d6ed91d5298 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2430,7 +2430,7 @@ macro_rules! to_json_impl_i64 { ($($t:ty), +) => ( $(impl ToJson for $t { fn to_json(&self) -> Json { - #![allow(trivial_numeric_cast)] + #![allow(trivial_numeric_casts)] Json::I64(*self as i64) } })+ @@ -2443,7 +2443,7 @@ macro_rules! to_json_impl_u64 { ($($t:ty), +) => ( $(impl ToJson for $t { fn to_json(&self) -> Json { - #![allow(trivial_numeric_cast)] + #![allow(trivial_numeric_casts)] Json::U64(*self as u64) } })+ diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 228b885b653c..cca6bb747d43 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -135,8 +135,8 @@ #![feature(no_std)] #![no_std] -#![allow(trivial_cast)] -#![allow(trivial_numeric_cast)] +#![allow(trivial_casts)] +#![allow(trivial_numeric_casts)] #![deny(missing_docs)] #[cfg(test)] extern crate test; diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 1aceec310e1a..a25a6451918d 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -262,7 +262,7 @@ pub mod rt { (unsigned, $t:ty, $tag:expr) => ( impl ToSource for $t { fn to_source(&self) -> String { - #![allow(trivial_numeric_cast)] + #![allow(trivial_numeric_casts)] let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag)); pprust::lit_to_string(&dummy_spanned(lit)) } diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index addeba03ab87..0fee48a8c6c6 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -10,7 +10,7 @@ #![deny(unused_variables)] #![deny(unused_assignments)] -#![allow(dead_code, non_camel_case_types, trivial_numeric_cast)] +#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] fn f1(x: isize) { //~^ ERROR unused variable: `x` diff --git a/src/test/compile-fail/object-safety-by-value-self.rs b/src/test/compile-fail/object-safety-by-value-self.rs index 3b0e5786f3db..5a8772d61425 100644 --- a/src/test/compile-fail/object-safety-by-value-self.rs +++ b/src/test/compile-fail/object-safety-by-value-self.rs @@ -12,7 +12,7 @@ #![feature(rustc_attrs)] #![allow(dead_code)] -#![allow(trivial_cast)] +#![allow(trivial_casts)] trait Bar { fn bar(self); diff --git a/src/test/compile-fail/trivial_casts.rs b/src/test/compile-fail/trivial_casts.rs index 05c7747d5b92..3119b865488e 100644 --- a/src/test/compile-fail/trivial_casts.rs +++ b/src/test/compile-fail/trivial_casts.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test the trivial_cast and trivial_numeric_cast lints. For each error we also +// Test the trivial_casts and trivial_numeric_casts lints. For each error we also // check that the cast can be done using just coercion. -#![deny(trivial_cast, trivial_numeric_cast)] +#![deny(trivial_casts, trivial_numeric_casts)] trait Foo { fn foo(&self) {} diff --git a/src/test/run-pass/trivial_casts.rs b/src/test/run-pass/trivial_casts.rs index 4b145f1079be..3da1ba0f0451 100644 --- a/src/test/run-pass/trivial_casts.rs +++ b/src/test/run-pass/trivial_casts.rs @@ -10,7 +10,7 @@ // Test that all coercions can actually be done using casts (modulo the lints). -#![allow(trivial_cast, trivial_numeric_cast)] +#![allow(trivial_casts, trivial_numeric_casts)] trait Foo { fn foo(&self) {} From 5fa4b4c4af14e391d7f16b4968aa25cca7c617c6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:13:07 +0100 Subject: [PATCH 18/32] Remove unnecessary bounds from Drop impl for `Arc` and `arc::Weak` and one of the helper method impls. --- src/liballoc/arc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index c9bbc0d74cdd..b5d16d292728 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -321,7 +321,7 @@ impl Arc { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Arc { +impl Drop for Arc { /// Drops the `Arc`. /// /// This will decrement the strong reference count. If the strong reference @@ -388,7 +388,7 @@ impl Drop for Arc { #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Weak { +impl Weak { /// Upgrades a weak reference to a strong reference. /// /// Upgrades the `Weak` reference to an `Arc`, if possible. @@ -454,7 +454,7 @@ impl Clone for Weak { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Weak { +impl Drop for Weak { /// Drops the `Weak`. /// /// This will decrement the weak reference count. From 0adab507bbb0b04fe389a00af19fc17753b76343 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:14:28 +0100 Subject: [PATCH 19/32] Added `T:Send` bound to `sync::mpsc::Receiver` and `sync::mpsc::Sender`. This was necessary to avoid specialized `Drop` impls for the two structs. --- src/libstd/sync/mpsc/mod.rs | 14 +++++++------- src/libstd/sync/mpsc/oneshot.rs | 8 ++++---- src/libstd/sync/mpsc/select.rs | 2 +- src/libstd/sync/mpsc/stream.rs | 8 ++++---- src/libstd/sys/common/helper_thread.rs | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 7adfd9154acf..48629beafc8c 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -342,7 +342,7 @@ mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by /// one task #[stable(feature = "rust1", since = "1.0.0")] -pub struct Receiver { +pub struct Receiver { inner: UnsafeCell>, } @@ -354,14 +354,14 @@ unsafe impl Send for Receiver { } /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T:'a> { +pub struct Iter<'a, T:Send+'a> { rx: &'a Receiver } /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Sender { +pub struct Sender { inner: UnsafeCell>, } @@ -433,7 +433,7 @@ pub enum TrySendError { Disconnected(T), } -enum Flavor { +enum Flavor { Oneshot(Arc>>), Stream(Arc>>), Shared(Arc>>), @@ -441,7 +441,7 @@ enum Flavor { } #[doc(hidden)] -trait UnsafeFlavor { +trait UnsafeFlavor { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell>; unsafe fn inner_mut<'a>(&'a self) -> &'a mut Flavor { &mut *self.inner_unsafe().get() @@ -450,12 +450,12 @@ trait UnsafeFlavor { &*self.inner_unsafe().get() } } -impl UnsafeFlavor for Sender { +impl UnsafeFlavor for Sender { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { &self.inner } } -impl UnsafeFlavor for Receiver { +impl UnsafeFlavor for Receiver { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { &self.inner } diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index f287712d9d45..13578ce05179 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -54,7 +54,7 @@ const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded // moves *from* a pointer, ownership of the token is transferred to // whoever changed the state. -pub struct Packet { +pub struct Packet { // Internal state of the chan/port pair (stores the blocked task as well) state: AtomicUsize, // One-shot data slot location @@ -64,7 +64,7 @@ pub struct Packet { upgrade: MyUpgrade, } -pub enum Failure { +pub enum Failure { Empty, Disconnected, Upgraded(Receiver), @@ -76,13 +76,13 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { +pub enum SelectionResult { SelCanceled, SelUpgraded(SignalToken, Receiver), SelSuccess, } -enum MyUpgrade { +enum MyUpgrade { NothingSent, SendUsed, GoUp(Receiver), diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 0f936641cdc7..b509b3472ee4 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -80,7 +80,7 @@ impl !marker::Send for Select {} /// A handle to a receiver which is currently a member of a `Select` set of /// receivers. This handle is used to keep the receiver in the set as well as /// interact with the underlying receiver. -pub struct Handle<'rx, T:'rx> { +pub struct Handle<'rx, T:Send+'rx> { /// The ID of this handle, used to compare against the return value of /// `Select::wait()` id: usize, diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 5a1e05f9c156..a5a73314a6db 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -39,7 +39,7 @@ const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; -pub struct Packet { +pub struct Packet { queue: spsc::Queue>, // internal queue for all message cnt: AtomicIsize, // How many items are on this channel @@ -49,7 +49,7 @@ pub struct Packet { port_dropped: AtomicBool, // flag if the channel has been destroyed. } -pub enum Failure { +pub enum Failure { Empty, Disconnected, Upgraded(Receiver), @@ -61,7 +61,7 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { +pub enum SelectionResult { SelSuccess, SelCanceled, SelUpgraded(SignalToken, Receiver), @@ -69,7 +69,7 @@ pub enum SelectionResult { // Any message could contain an "upgrade request" to a new shared port, so the // internal queue it's a queue of T, but rather Message -enum Message { +enum Message { Data(T), GoUp(Receiver), } diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index 2a852fbcd57e..e8bec66d9875 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -38,7 +38,7 @@ use thread; /// /// The fields of this helper are all public, but they should not be used, this /// is for static initialization. -pub struct Helper { +pub struct Helper { /// Internal lock which protects the remaining fields pub lock: StaticMutex, pub cond: StaticCondvar, From 26a79e3c204496f55b8c6ff9db741672554f1705 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:20:12 +0100 Subject: [PATCH 20/32] Added `Write` bounds to avoid a specialized Drop impl for `BufWriter`. --- src/libstd/io/buffered.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4def601f1c0e..2a1294f23b20 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -120,7 +120,7 @@ impl fmt::Debug for BufReader where R: fmt::Debug { /// /// The buffer will be written out when the writer is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter { +pub struct BufWriter { inner: Option, buf: Vec, } @@ -220,7 +220,7 @@ impl Write for BufWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufWriter where W: fmt::Debug { +impl fmt::Debug for BufWriter where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity()) @@ -276,7 +276,7 @@ impl fmt::Display for IntoInnerError { /// /// The buffer will be written out when the writer is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter { +pub struct LineWriter { inner: BufWriter, } @@ -335,7 +335,7 @@ impl Write for LineWriter { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineWriter where W: fmt::Debug { +impl fmt::Debug for LineWriter where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.inner, self.inner.buf.len(), @@ -343,16 +343,16 @@ impl fmt::Debug for LineWriter where W: fmt::Debug { } } -struct InternalBufWriter(BufWriter); +struct InternalBufWriter(BufWriter); -impl InternalBufWriter { +impl InternalBufWriter { fn get_mut(&mut self) -> &mut BufWriter { let InternalBufWriter(ref mut w) = *self; return w; } } -impl Read for InternalBufWriter { +impl Read for InternalBufWriter { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.get_mut().inner.as_mut().unwrap().read(buf) } @@ -367,7 +367,7 @@ impl Read for InternalBufWriter { /// /// The output buffer will be written out when this stream is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufStream { +pub struct BufStream { inner: BufReader> } @@ -448,7 +448,7 @@ impl Write for BufStream { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufStream where S: fmt::Debug { +impl fmt::Debug for BufStream where S: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let reader = &self.inner; let writer = &self.inner.inner.0; From 1249e6089180211c18fdc381a464274ec95edb25 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:22:21 +0100 Subject: [PATCH 21/32] Added `T:Send` bound to `Queue` to avoid specialized Drop impl. --- src/libstd/sync/mpsc/mpsc_queue.rs | 2 +- src/libstd/sync/mpsc/shared.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 14ed253d8e27..1be8b0dd8628 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -72,7 +72,7 @@ struct Node { /// The multi-producer single-consumer structure. This is not cloneable, but it /// may be safely shared so long as it is guaranteed that there is only one /// popper at a time (many pushers are allowed). -pub struct Queue { +pub struct Queue { head: AtomicPtr>, tail: UnsafeCell<*mut Node>, } diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 8d14824d37fe..f3930a8a5d63 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -40,7 +40,7 @@ const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; -pub struct Packet { +pub struct Packet { queue: mpsc::Queue, cnt: AtomicIsize, // How many items are on this channel steals: isize, // How many times has a port received without blocking? From 1e71d2e71c037b0008ce9f65a61cf814abd52b68 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:28:20 +0100 Subject: [PATCH 22/32] Added `W: Writer` bound to `BufferedWriter` to avoid specialized `Drop` impl. --- src/libstd/old_io/buffered.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libstd/old_io/buffered.rs b/src/libstd/old_io/buffered.rs index cb67d709a143..9a9d421dfe1f 100644 --- a/src/libstd/old_io/buffered.rs +++ b/src/libstd/old_io/buffered.rs @@ -148,14 +148,14 @@ impl Reader for BufferedReader { /// writer.write_str("hello, world").unwrap(); /// writer.flush().unwrap(); /// ``` -pub struct BufferedWriter { +pub struct BufferedWriter { inner: Option, buf: Vec, pos: uint } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedWriter where W: fmt::Debug { +impl fmt::Debug for BufferedWriter where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "BufferedWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.as_ref().unwrap(), self.pos, self.buf.len()) @@ -250,12 +250,12 @@ impl Drop for BufferedWriter { /// `'\n'`) is detected. /// /// This writer will be flushed when it is dropped. -pub struct LineBufferedWriter { +pub struct LineBufferedWriter { inner: BufferedWriter, } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineBufferedWriter where W: fmt::Debug { +impl fmt::Debug for LineBufferedWriter where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "LineBufferedWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.inner, self.inner.pos, self.inner.buf.len()) @@ -299,16 +299,16 @@ impl Writer for LineBufferedWriter { fn flush(&mut self) -> IoResult<()> { self.inner.flush() } } -struct InternalBufferedWriter(BufferedWriter); +struct InternalBufferedWriter(BufferedWriter); -impl InternalBufferedWriter { +impl InternalBufferedWriter { fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter { let InternalBufferedWriter(ref mut w) = *self; return w; } } -impl Reader for InternalBufferedWriter { +impl Reader for InternalBufferedWriter { fn read(&mut self, buf: &mut [u8]) -> IoResult { self.get_mut().inner.as_mut().unwrap().read(buf) } @@ -343,12 +343,12 @@ impl Reader for InternalBufferedWriter { /// Err(e) => println!("error reading: {}", e) /// } /// ``` -pub struct BufferedStream { +pub struct BufferedStream { inner: BufferedReader> } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedStream where S: fmt::Debug { +impl fmt::Debug for BufferedStream where S: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let reader = &self.inner; let writer = &self.inner.inner.0; From 018eeb76f0e7384f760afa2a97a07110eef05145 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:30:26 +0100 Subject: [PATCH 23/32] added `T:Send` bound to `Mutex` to avoid specialized Drop impl. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 2bf75cf1d376..6c1cda783b7e 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -112,7 +112,7 @@ use fmt; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex { +pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never // change (it can't be moved). This mutex type can be safely moved at any From 123b5c124e12ba08bd351c414753902aae9eb045 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:31:58 +0100 Subject: [PATCH 24/32] Added `T:Send` bound to `Packet` to avoid specialized `Drop` impl. --- src/libstd/sync/mpsc/mod.rs | 2 +- src/libstd/sync/mpsc/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 48629beafc8c..eb421fe55a4d 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -372,7 +372,7 @@ unsafe impl Send for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. #[stable(feature = "rust1", since = "1.0.0")] -pub struct SyncSender { +pub struct SyncSender { inner: Arc>>, } diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 33c1614e1b29..71236269487e 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -47,7 +47,7 @@ use sync::mpsc::blocking::{self, WaitToken, SignalToken}; use sync::mpsc::select::StartResult::{self, Installed, Abort}; use sync::{Mutex, MutexGuard}; -pub struct Packet { +pub struct Packet { /// Only field outside of the mutex. Just done for kicks, but mainly because /// the other shared channel already had the code implemented channels: AtomicUsize, From 5f57fd591d890cbf9cfc94123071c1a30d809b9e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:33:12 +0100 Subject: [PATCH 25/32] Added `T:Send` bound to `Queue` to avoid specialized `Drop` impl. --- src/libstd/sync/mpsc/spsc_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 3fb13739aa75..cd6d1ee05c78 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -57,7 +57,7 @@ struct Node { /// but it can be safely shared in an Arc if it is guaranteed that there /// is only one popper and one pusher touching the queue at any one point in /// time. -pub struct Queue { +pub struct Queue { // consumer fields tail: UnsafeCell<*mut Node>, // where to pop from tail_prev: AtomicPtr>, // where to pop from From 290c8de0a6f233b1d30c8a97cb41614fce989d30 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:34:33 +0100 Subject: [PATCH 26/32] Added `T:Send` bound to `JoinGuard` to avoid specialized `Drop` impl. --- src/libstd/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 57baeb1fb748..27b50fc9aaa6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -698,7 +698,7 @@ impl Drop for JoinHandle { /// permission. #[must_use = "thread will be immediately joined if `JoinGuard` is not used"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinGuard<'a, T: 'a> { +pub struct JoinGuard<'a, T: Send + 'a> { inner: JoinInner, _marker: PhantomData<&'a T>, } From 5b2e8693e42dee545d336c0364773b3fbded93a5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:12:08 +0100 Subject: [PATCH 27/32] Reject specialized Drop impls. See Issue 8142 for discussion. This makes it illegal for a Drop impl to be more specialized than the original item. So for example, all of the following are now rejected (when they would have been blindly accepted before): ```rust struct S { ... }; impl Drop for S { ... } // error: specialized to concrete type struct T<'a> { ... }; impl Drop for T<'static> { ... } // error: specialized to concrete region struct U { ... }; impl Drop for U { ... } // error: added extra type requirement struct V<'a,'b>; impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement ``` Due to examples like the above, this is a [breaking-change]. (The fix is to either remove the specialization from the `Drop` impl, or to transcribe the requirements into the struct/enum definition; examples of both are shown in the PR's fixed to `libstd`.) ---- This is likely to be the last thing blocking the removal of the `#[unsafe_destructor]` attribute. Includes two new error codes for the new dropck check. Update run-pass tests to accommodate new dropck pass. Update tests and docs to reflect new destructor restriction. ---- Implementation notes: We identify Drop impl specialization by not being as parametric as the struct/enum definition via unification. More specifically: 1. Attempt unification of a skolemized instance of the struct/enum with an instance of the Drop impl's type expression where all of the impl's generics (i.e. the free variables of the type expression) have been replaced with unification variables. 2. If unification fails, then reject Drop impl as specialized. 3. If unification succeeds, check if any of the skolemized variables "leaked" into the constraint set for the inference context; if so, then reject Drop impl as specialized. 4. Otherwise, unification succeeded without leaking skolemized variables: accept the Drop impl. We identify whether a Drop impl is injecting new predicates by simply looking whether the predicate, after an appropriate substitution, appears on the struct/enum definition. --- src/doc/trpl/unsafe.md | 17 +- .../middle/infer/higher_ranked/mod.rs | 58 +++++ src/librustc/middle/infer/mod.rs | 9 + src/librustc/middle/ty.rs | 3 + src/librustc_typeck/check/dropck.rs | 240 +++++++++++++++++- src/librustc_typeck/check/mod.rs | 14 + src/librustc_typeck/diagnostics.rs | 4 +- src/libstd/sync/mutex.rs | 2 +- src/test/auxiliary/issue-2526.rs | 2 +- src/test/run-pass/issue-15858.rs | 2 +- src/test/run-pass/issue-15924.rs | 2 +- src/test/run-pass/issue-2718.rs | 4 +- src/test/run-pass/issue-4252.rs | 2 +- 13 files changed, 341 insertions(+), 18 deletions(-) diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 2116976d55a4..dbf0cae6f4ba 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -197,15 +197,16 @@ use std::ptr; // Define a wrapper around the handle returned by the foreign code. // Unique has the same semantics as Box -pub struct Unique { +// +// NB: For simplicity and correctness, we require that T has kind Send +// (owned boxes relax this restriction). +pub struct Unique { // It contains a single raw, mutable pointer to the object in question. ptr: *mut T } // Implement methods for creating and using the values in the box. -// NB: For simplicity and correctness, we require that T has kind Send -// (owned boxes relax this restriction). impl Unique { pub fn new(value: T) -> Unique { unsafe { @@ -239,11 +240,11 @@ impl Unique { // Unique, making the struct manage the raw pointer: when the // struct goes out of scope, it will automatically free the raw pointer. // -// NB: This is an unsafe destructor, because rustc will not normally -// allow destructors to be associated with parameterized types, due to -// bad interaction with managed boxes. (With the Send restriction, -// we don't have this problem.) Note that the `#[unsafe_destructor]` -// feature gate is required to use unsafe destructors. +// NB: This is an unsafe destructor; rustc will not normally allow +// destructors to be associated with parameterized types (due to +// historically failing to check them soundly). Note that the +// `#[unsafe_destructor]` feature gate is currently required to use +// unsafe destructors. #[unsafe_destructor] impl Drop for Unique { fn drop(&mut self) { diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 7d789bedc50b..16b387330b9e 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -14,6 +14,7 @@ use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; use super::combine::{Combine, Combineable}; +use middle::subst; use middle::ty::{self, Binder}; use middle::ty_fold::{self, TypeFoldable}; use syntax::codemap::Span; @@ -455,6 +456,63 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> { } } +/// Constructs and returns a substitution that, for a given type +/// scheme parameterized by `generics`, will replace every generic +/// parmeter in the type with a skolemized type/region (which one can +/// think of as a "fresh constant", except at the type/region level of +/// reasoning). +/// +/// Since we currently represent bound/free type parameters in the +/// same way, this only has an effect on regions. +/// +/// (Note that unlike a substitution from `ty::construct_free_substs`, +/// this inserts skolemized regions rather than free regions; this +/// allows one to use `fn leak_check` to catch attmepts to unify the +/// skolemized regions with e.g. the `'static` lifetime) +pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + generics: &ty::Generics<'tcx>, + snapshot: &CombinedSnapshot) + -> (subst::Substs<'tcx>, SkolemizationMap) +{ + let mut map = FnvHashMap(); + + // map T => T + let mut types = subst::VecPerParamSpace::empty(); + push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice()); + + // map early- or late-bound 'a => fresh 'a + let mut regions = subst::VecPerParamSpace::empty(); + push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot); + + let substs = subst::Substs { types: types, + regions: subst::NonerasedRegions(regions) }; + return (substs, map); + + fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + map: &mut SkolemizationMap, + regions: &mut subst::VecPerParamSpace, + region_params: &[ty::RegionParameterDef], + snapshot: &CombinedSnapshot) + { + for r in region_params { + let br = r.to_bound_region(); + let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot); + let sanity_check = map.insert(br, skol_var); + assert!(sanity_check.is_none()); + regions.push(r.space, skol_var); + } + } + + fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>, + types: &mut subst::VecPerParamSpace>, + defs: &[ty::TypeParameterDef<'tcx>]) { + for def in defs { + let ty = ty::mk_param_from_def(tcx, def); + types.push(def.space, ty); + } + } +} + pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, binder: &ty::Binder, snapshot: &CombinedSnapshot) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 835964828d41..a38adabee915 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -726,6 +726,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + pub fn construct_skolemized_subst(&self, + generics: &ty::Generics<'tcx>, + snapshot: &CombinedSnapshot) + -> (subst::Substs<'tcx>, SkolemizationMap) { + /*! See `higher_ranked::construct_skolemized_subst` */ + + higher_ranked::construct_skolemized_substs(self, generics, snapshot) + } + pub fn skolemize_late_bound_regions(&self, value: &ty::Binder, snapshot: &CombinedSnapshot) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e5e89c3fbd4b..71c4962d526e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1793,6 +1793,9 @@ impl RegionParameterDef { pub fn to_early_bound_region(&self) -> ty::Region { ty::ReEarlyBound(self.def_id.node, self.space, self.index, self.name) } + pub fn to_bound_region(&self) -> ty::BoundRegion { + ty::BoundRegion::BrNamed(self.def_id, self.name) + } } /// Information about the formal type/lifetime parameters associated diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 9c48ac43ee46..c48033cab897 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -12,13 +12,249 @@ use check::regionck::{self, Rcx}; use middle::infer; use middle::region; -use middle::subst; +use middle::subst::{self, Subst}; use middle::ty::{self, Ty}; use util::ppaux::{Repr, UserString}; use syntax::ast; -use syntax::codemap::Span; +use syntax::codemap::{self, Span}; +/// check_drop_impl confirms that the Drop implementation identfied by +/// `drop_impl_did` is not any more specialized than the type it is +/// attached to (Issue #8142). +/// +/// This means: +/// +/// 1. The self type must be nominal (this is already checked during +/// coherence), +/// +/// 2. The generic region/type parameters of the impl's self-type must +/// all be parameters of the Drop impl itself (i.e. no +/// specialization like `impl Drop for Foo`), and, +/// +/// 3. Any bounds on the generic parameters must be reflected in the +/// struct/enum definition for the nominal type itself (i.e. +/// cannot do `struct S; impl Drop for S { ... }`). +/// +pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> { + let ty::TypeScheme { generics: ref dtor_generics, + ty: ref dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did); + let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did); + match dtor_self_type.sty { + ty::ty_enum(self_type_did, self_to_impl_substs) | + ty::ty_struct(self_type_did, self_to_impl_substs) | + ty::ty_closure(self_type_did, self_to_impl_substs) => { + try!(ensure_drop_params_and_item_params_correspond(tcx, + drop_impl_did, + dtor_generics, + dtor_self_type, + self_type_did)); + + ensure_drop_predicates_are_implied_by_item_defn(tcx, + drop_impl_did, + &dtor_predicates, + self_type_did, + self_to_impl_substs) + } + _ => { + // Destructors only work on nominal types. This was + // already checked by coherence, so we can panic here. + let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); + tcx.sess.span_bug( + span, &format!("should have been rejected by coherence check: {}", + dtor_self_type.repr(tcx))); + } + } +} + +fn ensure_drop_params_and_item_params_correspond<'tcx>( + tcx: &ty::ctxt<'tcx>, + drop_impl_did: ast::DefId, + drop_impl_generics: &ty::Generics<'tcx>, + drop_impl_ty: &ty::Ty<'tcx>, + self_type_did: ast::DefId) -> Result<(), ()> +{ + // New strategy based on review suggestion from nikomatsakis. + // + // (In the text and code below, "named" denotes "struct/enum", and + // "generic params" denotes "type and region params") + // + // 1. Create fresh skolemized type/region "constants" for each of + // the named type's generic params. Instantiate the named type + // with the fresh constants, yielding `named_skolem`. + // + // 2. Create unification variables for each of the Drop impl's + // generic params. Instantiate the impl's Self's type with the + // unification-vars, yielding `drop_unifier`. + // + // 3. Attempt to unify Self_unif with Type_skolem. If unification + // succeeds, continue (i.e. with the predicate checks). + + let ty::TypeScheme { generics: ref named_type_generics, + ty: named_type } = + ty::lookup_item_type(tcx, self_type_did); + + let infcx = infer::new_infer_ctxt(tcx); + infcx.try(|snapshot| { + let (named_type_to_skolem, skol_map) = + infcx.construct_skolemized_subst(named_type_generics, snapshot); + let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem); + + let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); + let drop_to_unifier = + infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics); + let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier); + + if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span), + named_type_skolem, drop_unifier) { + // Even if we did manage to equate the types, the process + // may have just gathered unsolvable region constraints + // like `R == 'static` (represented as a pair of subregion + // constraints) for some skolemization constant R. + // + // However, the leak_check method allows us to confirm + // that no skolemized regions escaped (i.e. were related + // to other regions in the constraint graph). + if let Ok(()) = infcx.leak_check(&skol_map, snapshot) { + return Ok(()) + } + } + + span_err!(tcx.sess, drop_impl_span, E0366, + "Implementations of Drop cannot be specialized"); + let item_span = tcx.map.span(self_type_did.node); + tcx.sess.span_note(item_span, + "Use same sequence of generic type and region \ + parameters that is on the struct/enum definition"); + return Err(()); + }) +} + +/// Confirms that every predicate imposed by dtor_predicates is +/// implied by assuming the predicates attached to self_type_did. +fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( + tcx: &ty::ctxt<'tcx>, + drop_impl_did: ast::DefId, + dtor_predicates: &ty::GenericPredicates<'tcx>, + self_type_did: ast::DefId, + self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> { + + // Here is an example, analogous to that from + // `compare_impl_method`. + // + // Consider a struct type: + // + // struct Type<'c, 'b:'c, 'a> { + // x: &'a Contents // (contents are irrelevant; + // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.) + // } + // + // and a Drop impl: + // + // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> { + // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y) + // } + // + // We start out with self_to_impl_substs, that maps the generic + // parameters of Type to that of the Drop impl. + // + // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x} + // + // Applying this to the predicates (i.e. assumptions) provided by the item + // definition yields the instantiated assumptions: + // + // ['y : 'z] + // + // We then check all of the predicates of the Drop impl: + // + // ['y:'z, 'x:'y] + // + // and ensure each is in the list of instantiated + // assumptions. Here, `'y:'z` is present, but `'x:'y` is + // absent. So we report an error that the Drop impl injected a + // predicate that is not present on the struct definition. + + assert_eq!(self_type_did.krate, ast::LOCAL_CRATE); + + let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); + + // We can assume the predicates attached to struct/enum definition + // hold. + let generic_assumptions = ty::lookup_predicates(tcx, self_type_did); + + let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); + assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace)); + assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace)); + let assumptions_in_impl_context = + assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace); + + // An earlier version of this code attempted to do this checking + // via the traits::fulfill machinery. However, it ran into trouble + // since the fulfill machinery merely turns outlives-predicates + // 'a:'b and T:'b into region inference constraints. It is simpler + // just to look for all the predicates directly. + + assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace)); + assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace)); + let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace); + for predicate in predicates { + // (We do not need to worry about deep analysis of type + // expressions etc because the Drop impls are already forced + // to take on a structure that is roughly a alpha-renaming of + // the generic parameters of the item definition.) + + // This path now just checks *all* predicates via the direct + // lookup, rather than using fulfill machinery. + // + // However, it may be more efficient in the future to batch + // the analysis together via the fulfill , rather than the + // repeated `contains` calls. + + if !assumptions_in_impl_context.contains(&predicate) { + let item_span = tcx.map.span(self_type_did.node); + let req = predicate.user_string(tcx); + span_err!(tcx.sess, drop_impl_span, E0367, + "The requirement `{}` is added only by the Drop impl.", req); + tcx.sess.span_note(item_span, + "The same requirement must be part of \ + the struct/enum definition"); + } + } + + if tcx.sess.has_errors() { + return Err(()); + } + Ok(()) +} + +/// check_safety_of_destructor_if_necessary confirms that the type +/// expression `typ` conforms to the "Drop Check Rule" from the Sound +/// Generic Drop (RFC 769). +/// +/// ---- +/// +/// The Drop Check Rule is the following: +/// +/// Let `v` be some value (either temporary or named) and 'a be some +/// lifetime (scope). If the type of `v` owns data of type `D`, where +/// +/// (1.) `D` has a lifetime- or type-parametric Drop implementation, and +/// (2.) the structure of `D` can reach a reference of type `&'a _`, and +/// (3.) either: +/// +/// (A.) the Drop impl for `D` instantiates `D` at 'a directly, +/// i.e. `D<'a>`, or, +/// +/// (B.) the Drop impl for `D` has some type parameter with a +/// trait bound `T` where `T` is a trait that has at least +/// one method, +/// +/// then 'a must strictly outlive the scope of v. +/// +/// ---- +/// +/// This function is meant to by applied to the type for every +/// expression in the program. pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, typ: ty::Ty<'tcx>, span: Span, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c3f4937d26b0..04ea7961f502 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -478,6 +478,20 @@ pub fn check_item_types(ccx: &CrateCtxt) { visit::walk_crate(&mut visit, krate); ccx.tcx.sess.abort_if_errors(); + + for drop_method_did in ccx.tcx.destructors.borrow().iter() { + if drop_method_did.krate == ast::LOCAL_CRATE { + let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node); + match dropck::check_drop_impl(ccx.tcx, drop_impl_did) { + Ok(()) => {} + Err(()) => { + assert!(ccx.tcx.sess.has_errors()); + } + } + } + } + + ccx.tcx.sess.abort_if_errors(); } fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 396d060de9e9..95e06879fb22 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -177,7 +177,9 @@ register_diagnostics! { E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck E0321, // extended coherence rules for defaulted traits violated - E0322 // cannot implement Sized explicitly + E0322, // cannot implement Sized explicitly + E0366, // dropck forbid specialization to concrete type or region + E0367 // dropck forbid specialization to predicate not in struct/enum } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 6c1cda783b7e..b24cfbb6899a 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -366,7 +366,7 @@ mod test { use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar}; use thread; - struct Packet(Arc<(Mutex, Condvar)>); + struct Packet(Arc<(Mutex, Condvar)>); unsafe impl Send for Packet {} unsafe impl Sync for Packet {} diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index 89b3b56121a1..832665abdc2d 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -15,7 +15,7 @@ use std::marker; -struct arc_destruct { +struct arc_destruct { _data: int, _marker: marker::PhantomData } diff --git a/src/test/run-pass/issue-15858.rs b/src/test/run-pass/issue-15858.rs index 9b300deaa497..265db3fe1336 100644 --- a/src/test/run-pass/issue-15858.rs +++ b/src/test/run-pass/issue-15858.rs @@ -25,7 +25,7 @@ impl Bar for BarImpl { } -struct Foo(B); +struct Foo(B); #[unsafe_destructor] impl Drop for Foo { diff --git a/src/test/run-pass/issue-15924.rs b/src/test/run-pass/issue-15924.rs index 6af07c422ef5..e544585745de 100644 --- a/src/test/run-pass/issue-15924.rs +++ b/src/test/run-pass/issue-15924.rs @@ -18,7 +18,7 @@ use std::fmt; use serialize::{Encoder, Encodable}; use serialize::json; -struct Foo { +struct Foo { v: T, } diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index 8d0e06549335..7ca0ee01015b 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -162,7 +162,7 @@ pub mod pipes { } } - pub struct send_packet { + pub struct send_packet { p: Option<*const packet>, } @@ -192,7 +192,7 @@ pub mod pipes { } } - pub struct recv_packet { + pub struct recv_packet { p: Option<*const packet>, } diff --git a/src/test/run-pass/issue-4252.rs b/src/test/run-pass/issue-4252.rs index 9d5f8576c633..08ee955cabba 100644 --- a/src/test/run-pass/issue-4252.rs +++ b/src/test/run-pass/issue-4252.rs @@ -21,7 +21,7 @@ trait X { struct Y(int); #[derive(Debug)] -struct Z { +struct Z { x: T } From 1955e052675d4457432da85a00db0ae55be64e83 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 Mar 2015 10:46:40 +0100 Subject: [PATCH 28/32] Unit tests for Issue 8142, collected into one file. --- .../reject-specialized-drops-8142.rs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/test/compile-fail/reject-specialized-drops-8142.rs diff --git a/src/test/compile-fail/reject-specialized-drops-8142.rs b/src/test/compile-fail/reject-specialized-drops-8142.rs new file mode 100644 index 000000000000..30264c9f218a --- /dev/null +++ b/src/test/compile-fail/reject-specialized-drops-8142.rs @@ -0,0 +1,79 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue 8142: Test that Drop impls cannot be specialized beyond the +// predicates attached to the struct/enum definition itself. + +#![feature(unsafe_destructor)] + +trait Bound { fn foo(&self) { } } +struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } +struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 } +struct M<'m> { x: &'m i8 } +struct N<'n> { x: &'n i8 } +struct O { x: *const To } +struct P { x: *const Tp } +struct Q { x: *const Tq } +struct R { x: *const Tr } +struct S { x: *const Ts } +struct T<'t,Ts:'t> { x: &'t Ts } +struct U; +struct V { x: *const Tva, y: *const Tvb } +struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 } + +#[unsafe_destructor] +impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT + //~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl. + fn drop(&mut self) { } } + +#[unsafe_destructor] +impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT + //~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl. + fn drop(&mut self) { } } + +#[unsafe_destructor] +impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT + +#[unsafe_destructor] +impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT +//~^ ERROR Implementations of Drop cannot be specialized + +#[unsafe_destructor] +impl Drop for O { fn drop(&mut self) { } } // ACCEPT + +#[unsafe_destructor] +impl Drop for P { fn drop(&mut self) { } } // REJECT +//~^ ERROR Implementations of Drop cannot be specialized + +#[unsafe_destructor] +impl Drop for Q { fn drop(&mut self) { } } // REJECT +//~^ ERROR The requirement `Adds_bnd : Bound` is added only by the Drop impl. + +#[unsafe_destructor] +impl<'rbnd,Adds_rbnd:'rbnd> Drop for R { fn drop(&mut self) { } } // REJECT +//~^ ERROR The requirement `Adds_rbnd : 'rbnd` is added only by the Drop impl. + +#[unsafe_destructor] +impl Drop for S { fn drop(&mut self) { } } // ACCEPT + +#[unsafe_destructor] +impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT + +impl Drop for U { fn drop(&mut self) { } } // ACCEPT + +#[unsafe_destructor] +impl Drop for V { fn drop(&mut self) { } } // REJECT +//~^ERROR Implementations of Drop cannot be specialized + +#[unsafe_destructor] +impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT +//~^ERROR Implementations of Drop cannot be specialized + +pub fn main() { } From 7e3ee02006ec53ff176fc3490ba01eb2a9c823b8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 24 Mar 2015 13:50:14 +1300 Subject: [PATCH 29/32] Bug fixes --- src/librustc_typeck/check/coercion.rs | 23 ----------------------- src/libstd/sys/windows/os.rs | 2 +- src/libstd/thread/local.rs | 1 + src/libterm/win.rs | 2 +- 4 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8ad11e19b347..ae1dbbb1b00a 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -381,29 +381,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { None } } - (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { - // For now, we only support upcasts from - // `Foo+Send` to `Foo` (really, any time there are - // fewer builtin bounds then before). These are - // convenient because they don't require any sort - // of change to the vtable at runtime. - if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds && - data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) - { - let bounds_a1 = ty::ExistentialBounds { - region_bound: data_a.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); - match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) { - Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), - Err(_) => None, - } - } else { - None - } - } (_, &ty::ty_trait(ref data)) => { Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(), diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 83d063717344..167db1e8ac2d 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -109,7 +109,7 @@ impl Iterator for Env { if *self.cur == 0 { return None } let p = &*self.cur; let mut len = 0; - while *(p as *const _).offset(len) != 0 { + while *(p as *const u16).offset(len) != 0 { len += 1; } let p = p as *const u16; diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 1bf1b09681c4..a2b824bb016f 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -176,6 +176,7 @@ macro_rules! __thread_local_inner { } }; + #[allow(trivial_casts)] #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = { ::std::thread::__local::__impl::KeyInner { diff --git a/src/libterm/win.rs b/src/libterm/win.rs index e29e0e27394d..001313db6769 100644 --- a/src/libterm/win.rs +++ b/src/libterm/win.rs @@ -126,7 +126,7 @@ impl WinConsole { } Some(box WinConsole { buf: out, def_foreground: fg, def_background: bg, - foreground: fg, background: bg } as Box+Send>) + foreground: fg, background: bg }) } } From 492f07bbda5cfd521606d1c5540855a8789659ad Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 25 Mar 2015 00:39:29 +0200 Subject: [PATCH 30/32] Fix some fallout in librustdoc --- src/librustdoc/html/format.rs | 6 +++--- src/librustdoc/html/render.rs | 6 +++--- src/librustdoc/visit_ast.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index df6beab0f583..0e6e008c6165 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -290,7 +290,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path, if ast_util::is_local(did) || cache.inlined.contains(&did) { Some(repeat("../").take(loc.len()).collect::()) } else { - match cache.extern_locations[&did.krate] { + match cache.extern_locations[did.krate] { render::Remote(ref s) => Some(s.to_string()), render::Local => { Some(repeat("../").take(loc.len()).collect::()) @@ -404,11 +404,11 @@ fn primitive_link(f: &mut fmt::Formatter, needs_termination = true; } Some(&cnum) => { - let path = &m.paths[&ast::DefId { + let path = &m.paths[ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID, }]; - let loc = match m.extern_locations[&cnum] { + let loc = match m.extern_locations[cnum] { render::Remote(ref s) => Some(s.to_string()), render::Local => { let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d57739c40024..28dfe8dca7d3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1409,8 +1409,8 @@ impl<'a> Item<'a> { // located, then we return `None`. } else { let cache = cache(); - let path = &cache.external_paths[&self.item.def_id]; - let root = match cache.extern_locations[&self.item.def_id.krate] { + let path = &cache.external_paths[self.item.def_id]; + let root = match cache.extern_locations[self.item.def_id.krate] { Remote(ref s) => s.to_string(), Local => self.cx.root_path.clone(), Unknown => return None, @@ -1868,7 +1868,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, path = if ast_util::is_local(it.def_id) { cx.current.connect("/") } else { - let path = &cache.external_paths[&it.def_id]; + let path = &cache.external_paths[it.def_id]; path[..path.len() - 1].connect("/") }, ty = shortty(it).to_static_str(), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 11e10cc2aa7a..d53954b29b58 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Some(tcx) => tcx, None => return false }; - let def = tcx.def_map.borrow()[&id].def_id(); + let def = tcx.def_map.borrow()[id].def_id(); if !ast_util::is_local(def) { return false } let analysis = match self.analysis { Some(analysis) => analysis, None => return false From efaef2430484852fc761b08b0653b7d74a17becd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 16:48:50 -0700 Subject: [PATCH 31/32] Test fixes and rebase conflicts, round 1 --- src/libstd/fs/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index ab7675e4646c..c1253706832d 100644 --- a/src/libstd/fs/mod.rs +++ b/src/libstd/fs/mod.rs @@ -183,6 +183,7 @@ impl File { /// /// ```no_run /// use std::fs::File; + /// use std::io::prelude::*; /// /// # fn foo() -> std::io::Result<()> { /// let mut f = try!(File::create("foo.txt")); @@ -211,6 +212,7 @@ impl File { /// /// ```no_run /// use std::fs::File; + /// use std::io::prelude::*; /// /// # fn foo() -> std::io::Result<()> { /// let mut f = try!(File::create("foo.txt")); From 3021d4c56422e15331e38f4b7b04c7229e024fda Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 16:55:35 -0700 Subject: [PATCH 32/32] Test fixes and rebase conflicts, round 2 --- src/libcore/str/mod.rs | 1 + src/liblibc/lib.rs | 1 + src/librbml/lib.rs | 2 +- src/librustdoc/html/format.rs | 6 +++--- src/librustdoc/html/render.rs | 6 +++--- src/librustdoc/visit_ast.rs | 2 +- src/libstd/sys/windows/net.rs | 2 +- src/libstd/sys/windows/thread_local.rs | 8 ++++++-- 8 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 36c3eb33c77a..ea98f6f5f246 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -28,6 +28,7 @@ use iter::ExactSizeIterator; use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; use marker::Sized; use mem; +#[allow(deprecated)] use num::Int; use ops::{Fn, FnMut, FnOnce}; use option::Option::{self, None, Some}; diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 1cb1f956e266..89843979cd01 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -2439,6 +2439,7 @@ pub mod consts { } pub mod posix88 { use types::os::arch::c95::c_int; + use types::os::arch::posix88::mode_t; pub const O_RDONLY : c_int = 0; pub const O_WRONLY : c_int = 1; diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 182b05acbb61..1ffc6001af57 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -352,7 +352,7 @@ pub mod reader { let i = (val >> 28) as uint; let (shift, mask) = SHIFT_MASK_TABLE[i]; Ok(Res { - val: ((val >> shift) & mask) as uint, + val: ((val >> shift) & mask) as usize, next: start + ((32 - shift) >> 3), }) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0e6e008c6165..df6beab0f583 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -290,7 +290,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path, if ast_util::is_local(did) || cache.inlined.contains(&did) { Some(repeat("../").take(loc.len()).collect::()) } else { - match cache.extern_locations[did.krate] { + match cache.extern_locations[&did.krate] { render::Remote(ref s) => Some(s.to_string()), render::Local => { Some(repeat("../").take(loc.len()).collect::()) @@ -404,11 +404,11 @@ fn primitive_link(f: &mut fmt::Formatter, needs_termination = true; } Some(&cnum) => { - let path = &m.paths[ast::DefId { + let path = &m.paths[&ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID, }]; - let loc = match m.extern_locations[cnum] { + let loc = match m.extern_locations[&cnum] { render::Remote(ref s) => Some(s.to_string()), render::Local => { let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 28dfe8dca7d3..d57739c40024 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1409,8 +1409,8 @@ impl<'a> Item<'a> { // located, then we return `None`. } else { let cache = cache(); - let path = &cache.external_paths[self.item.def_id]; - let root = match cache.extern_locations[self.item.def_id.krate] { + let path = &cache.external_paths[&self.item.def_id]; + let root = match cache.extern_locations[&self.item.def_id.krate] { Remote(ref s) => s.to_string(), Local => self.cx.root_path.clone(), Unknown => return None, @@ -1868,7 +1868,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, path = if ast_util::is_local(it.def_id) { cx.current.connect("/") } else { - let path = &cache.external_paths[it.def_id]; + let path = &cache.external_paths[&it.def_id]; path[..path.len() - 1].connect("/") }, ty = shortty(it).to_static_str(), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 34f89bfb877f..3f813b30ecc1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Some(tcx) => tcx, None => return false }; - let def = tcx.def_map.borrow()[id].def_id(); + let def = tcx.def_map.borrow()[&id].def_id(); if !ast_util::is_local(def) { return false } let analysis = match self.analysis { Some(analysis) => analysis, None => return false diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index e092faf4935d..734268c70ac9 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -36,7 +36,7 @@ pub fn init() { &mut data); assert_eq!(ret, 0); - rt::at_exit(|| { c::WSACleanup(); }) + let _ = rt::at_exit(|| { c::WSACleanup(); }); }); } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 1359803070af..c908c791247d 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -133,9 +133,8 @@ unsafe fn init_dtors() { if !DTORS.is_null() { return } let dtors = box Vec::<(Key, Dtor)>::new(); - DTORS = boxed::into_raw(dtors); - rt::at_exit(move|| { + let res = rt::at_exit(move|| { DTOR_LOCK.lock(); let dtors = DTORS; DTORS = 1 as *mut _; @@ -143,6 +142,11 @@ unsafe fn init_dtors() { assert!(DTORS as uint == 1); // can't re-init after destructing DTOR_LOCK.unlock(); }); + if res.is_ok() { + DTORS = boxed::into_raw(dtors); + } else { + DTORS = 1 as *mut _; + } } unsafe fn register_dtor(key: Key, dtor: Dtor) {