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 4537fc763c953..df94a6ac80fbe 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 c9b105f72a539..df280dab37d46 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 a1c8630e0ec31..a48758366f347 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 9fa12b1ef3023..9079c0aaffb7d 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 e52e68dad23fa..43aa4155629ec 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 2a852fbcd57e3..53f18a5732555 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 6aced23ede08e..9a2eb458bc63d 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 6324e8fa87443..fc3f4b426d861 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 e8181395b5c1e..dd7144636dfb7 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 6b66d7227d300..b4f21492ca10b 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 7dfbccea0dccd..764e342a0c5af 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 99c35c6e54258..4b8c4ee88c05d 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 cf36ec1f3ed96..07c94097e2df8 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 c1bc7219ad825..5a48b8e4bce1d 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 4da17972c55fb..aa038f8ddca31 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 28e7027b2124a..4f06346fb45cc 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> +{ + // 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> { - debug!("ast_path_to_trait_ref {:?}", trait_segment); + 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 32f91a175f3c3..d2a06fcf99091 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); + + (expected_sig, expected_kind) +} - (None, 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 bc581a6af4154..b95e0ce8cb3c5 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 97cc3ac7c48a7..8744df0e20249 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 | 12 +++++++++- 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 | 10 ++++++++- .../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, 216 insertions(+), 59 deletions(-) diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index 488f0d756d329..234cd6e0fd21e 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 673c025e86345..93c37524bf565 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 fe7635f065cdc..27b4a04054f07 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 db3373ea02772..d1abed9b2627c 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 e5e5ddadafccf..d86c5d211dc5f 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 35c551931366d..6433255bd4d2f 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 838e65e1d0574..8e1e88a92e452 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 8f79022405ebe..3853434e128eb 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 e4bedbbb7e1e5..fe427e02451af 100644 --- a/src/test/compile-fail/issue-20225.rs +++ b/src/test/compile-fail/issue-20225.rs @@ -13,9 +13,19 @@ struct Foo; impl<'a, T> Fn<(&'a T,)> for Foo { + 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(&self, (_,): (T,)) {} + extern "rust-call" fn call_once(self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait: expected &-ptr } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 61752e62abdef..77ac97bc8b899 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 c4019fa22097a..ea47d67641209 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 92e6affa4c202..93498ac7f8351 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 713b64b1349fc..2dcd7a97d8977 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 23f7ee2b0101d..dc7c70ba649d8 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 40655f8a3cec4..cdcb435b65a6a 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 ebcbdbbc006df..150bf36dcc286 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 81a8b29461c78..6c0e5edae72a6 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 6335f79be6c7a..ab5a2f03ece8c 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 53d0f7dae0577..91ad7e03623fd 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 389baecafd144..fda35d3e7f463 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 3082fc27a7dec..9a476f563eda7 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 { + 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(&self, (_,): (&(),)) {} + 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 0ac9c97532bff..081e1417d5f45 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 d18a91c545280..b20c80dc4c944 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 78e84b9d55bca..245ff6df6145f 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 0aab5be2877e1..aad190d0236c9 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 a8bb091893271..94be640636718 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 2d1ba7f39b27b..a2ab06049d63d 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 f1b79a1829eab..439ec4af9ebfc 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 9a2eb458bc63d..b851f19d22dc3 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 2bf919d7e2cce..249b5d22b6b23 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 893781e622090..16570086d43c5 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 7df6d6887a258..72f4fbb116c56 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 6ff51e8d1b92c..69d49f67941d4 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 0000000000000..f36c2c56b6a76 --- /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 3938a610668b7..c94d8e2ed0c8d 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 415ec4e4fbf0a..6e6c56d3df20d 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 237435d6dfbfa..33c4156fc0ce7 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 058eff121e633..85e5bde48598e 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 1b0356b88b08d..7843be0b483eb 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 da2c61b6fd394..0a61eeb6e1c63 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 59819d01bc601..af2daabc2d02c 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 a9c5de23d948b..f5db3e63c7ad4 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 cf427c16588d9..e00cdc9de88da 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 49da99b97cb20..d01d240e5b5f1 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 1d5e174a8dc99..ccc1d32eab35b 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 551f97ead12d8..0bc41eb2c6eae 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 5ea60d0d96d29..1557434a28a27 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 7d9faa998c12e..bdccab4cb9a9f 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 5a70911387b9b..d8f5aa6e54836 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 1d7d78ffa6c23..da2410a04cfe4 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 fe0d6d13c4c06..5f697e02a9943 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 0fd0d90b12501..838caa59e4717 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 9ca7b48fbe5ef..7686a990acc9d 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 21635799a77a2..9d91bbc7f9019 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 7d520770503d4..2d5f163e093c7 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 f10822077dc75..26813aa281c66 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 3d6922b07b194..7fb28f27d62aa 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 d0c4885ad00b7..9f502e3ea4312 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 602ef4fe45e73..be5acaac92aea 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 d92622eeb70e3..9b3ee3ef5e0c2 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 b7285d30a7309..035d070cd6d43 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 bf3e1cf03cbdd..17d6b684c50e8 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 adc15b9fbc27f..4f5f269d4375d 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 4537fc763c953..2c431e1e05088 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 e6f27a28ffa7c..0001cb6e0caaf 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 7ea62b7fd3f41..673246fe30dc1 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 1a794f56f802c..182b05acbb618 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 793eff6a9da6f..dd5f3cccea544 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 44718d1c5251d..4f56f2441dc41 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 e5e89c3fbd4b9..38a20c61d2e63 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 e65fe904dd29a..ef82a465ef4bf 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 ef65acf8b13f4..f2d2db18da4b5 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 506bf4a058fc6..4d821df72a6e0 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 b9ec22b86f076..ef43b9c0de420 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 e181df545e6fc..15738d1e61ac1 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 ceb9a29efa887..4d7431a20b707 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 4da17972c55fb..d13076df63761 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 f731507ba906d..920154bc916f4 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 6f2d0cb366741..cd6a1226e00c9 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 c3f4937d26b04..4eddf8ae97a90 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 963be9aa2e2d2..2858dc9b569fe 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 cdd8457687ac6..cfa84de5ca7c9 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 abbfc82319f5b..17c414485407b 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 90eca6168f266..228b885b653c0 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 ef811f832b394..b77c8d50997f5 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 e52e68dad23fa..86b1d031f688b 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 1abe8d0a3c1b1..6a00fff186002 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 35449bde0b2e0..b679456b3537b 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 c11ffe66e6c39..1aceec310e1af 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 5940b79184379..1e53db6030143 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 e0953a8ace68d..0843713681bbd 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 4ae5e0faa3105..44097ffeb2059 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 828d085fd432e..5941f044a078a 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 c907b87bc3c66..41e066cc94a92 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 309320b52ffe4..1d6657d5932c0 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 cc9a2880b5d07..8d0a9e6e9717d 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 402774321bfcb..c48c7e413d03b 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 473739c919d64..44af43be78773 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 560844332a128..d66cfe9bf636b 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 d7bb806999c74..3f994102a173e 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 6d2cfcab04e36..a4e0f69b63b39 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 c27362eea3e3c..0000000000000 --- 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 dffc8fa2abd70..71494fd5f38dc 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 13ee3f163616e..ba1b7f03b0f41 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 b3cf8257b8f6e..0000000000000 --- 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 ac4b8a5f3090b..addeba03ab870 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 976717249e8eb..3b0e5786f3db3 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 f3b5ccabe79eb..253132e5f07d0 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 fc18095fc8336..924044647d84a 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 8ff514e04e360..8cc531625d179 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 97e67cd2eae27..cac52306d6ae0 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 bf26fc23d3c16..d4cbd255e34c2 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 0a20300e4f4de..42b2fe806e95f 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 f81d4803f8fa4..474a6782b616b 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 6a038927f4a48..0bec3af4273af 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 a298a08a1b7a0..deb0c0d0dc0df 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 7347ded99e7c4..0000000000000 --- 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 7bfd8e0ab7189..f30991a196352 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 59bca87bed0b6..54773d71cbec0 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 669a5cdfe304a..6e88379f9a41b 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 c8da4852ad35f..de8d116255ba2 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 f8a3ce7cda017..baf8c6e4c9791 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 efdd42c382c15..368842ed1b030 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 63fb18a8ba2c2..c87c79ca24eda 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 152fb5dc96107..920cd9e03ab6b 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 a6c6db1a1273e..5c0d0fe9a63d8 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 f4c0992ae1a56..53e78db68b19d 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 4cb7e40a4fbd1..ba12599747068 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 | 310 ++++++++++++++------------ 1 file changed, 163 insertions(+), 147 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 920154bc916f4..8ad11e19b347b 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()); - - 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; + (&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 } - 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 ef82a465ef4bf..395460aca9fe9 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 f2d2db18da4b5..e158541cd1cff 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 4eddf8ae97a90..c8c7fb046b17e 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 0000000000000..05c7747d5b92d --- /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 0000000000000..4b145f1079beb --- /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 0a61eeb6e1c63..6a65c991c9503 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 f5db3e63c7ad4..9e6dbce032593 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 e00cdc9de88da..aa0d0a1539a30 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 d01d240e5b5f1..56d2eabc095a3 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 ccc1d32eab35b..2feb2f8b1e363 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 0bc41eb2c6eae..1e6fb51a8a528 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 1557434a28a27..efafce3fdefb0 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 bdccab4cb9a9f..72b0236a8d2a4 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 d8f5aa6e54836..a64a4febd5a96 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 da2410a04cfe4..459814875ee0e 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 5f697e02a9943..675f568a96099 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 838caa59e4717..9af51a3674826 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 7686a990acc9d..0eec875afc3bb 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 9d91bbc7f9019..289c5dbd08ea0 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 2d5f163e093c7..6d0b6b0e5eaf9 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 26813aa281c66..bf8747fdb6e2f 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 7fb28f27d62aa..05199735d4acb 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 9f502e3ea4312..c22f31cc57ea8 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 be5acaac92aea..82dd3312782c5 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 0001cb6e0caaf..a682fa8584176 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 673246fe30dc1..14bebe0cd915c 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 dd5f3cccea544..e8af07e438159 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 4f56f2441dc41..2cc47f258f076 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 395460aca9fe9..8b57a48f3ce72 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 4d821df72a6e0..9d564fa56f54d 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 ef43b9c0de420..99a64156d667b 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 c8c7fb046b17e..47aafa2251d97 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 17c414485407b..0d6ed91d52981 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 228b885b653c0..cca6bb747d43c 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 1aceec310e1af..a25a6451918d7 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 addeba03ab870..0fee48a8c6c66 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 3b0e5786f3db3..5a8772d61425f 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 05c7747d5b92d..3119b865488e8 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 4b145f1079beb..3da1ba0f0451f 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 c9bbc0d74cddc..b5d16d2927285 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 7adfd9154acf8..48629beafc8cd 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 f287712d9d45d..13578ce051791 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 0f936641cdc75..b509b3472ee41 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 5a1e05f9c1565..a5a73314a6db3 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 2a852fbcd57e3..e8bec66d9875b 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 4def601f1c0e7..2a1294f23b20e 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 14ed253d8e27e..1be8b0dd8628a 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 8d14824d37fee..f3930a8a5d632 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 cb67d709a143a..9a9d421dfe1f0 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 2bf75cf1d3764..6c1cda783b7e8 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 48629beafc8cd..eb421fe55a4d0 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 33c1614e1b297..71236269487ef 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 3fb13739aa75a..cd6d1ee05c788 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 57baeb1fb7486..27b50fc9aaa60 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 2116976d55a4d..dbf0cae6f4ba8 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 7d789bedc50b5..16b387330b9ef 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 835964828d419..a38adabee915b 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 e5e89c3fbd4b9..71c4962d526e3 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 9c48ac43ee468..c48033cab897f 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 c3f4937d26b04..04ea7961f5021 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 396d060de9e90..95e06879fb223 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 6c1cda783b7e8..b24cfbb6899a9 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 89b3b56121a16..832665abdc2d7 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 9b300deaa497e..265db3fe1336a 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 6af07c422ef56..e544585745de3 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 8d0e06549335c..7ca0ee01015b8 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 9d5f8576c633e..08ee955cabbac 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 0000000000000..30264c9f218a1 --- /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 8ad11e19b347b..ae1dbbb1b00ad 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 83d0637173444..167db1e8ac2d7 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 1bf1b09681c4a..a2b824bb016ff 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 e29e0e27394db..001313db6769f 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 df6beab0f5832..0e6e008c61652 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 d57739c400249..28dfe8dca7d38 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 11e10cc2aa7a1..d53954b29b585 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 ab7675e4646c5..c1253706832df 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 36c3eb33c77a2..ea98f6f5f2461 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 1cb1f956e266e..89843979cd015 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 182b05acbb618..1ffc6001af572 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 0e6e008c61652..df6beab0f5832 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 28dfe8dca7d38..d57739c400249 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 34f89bfb877f5..3f813b30ecc1d 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 e092faf4935db..734268c70ac9c 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 1359803070af3..c908c791247d1 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) {