From 1ec9adcfc0da7b1cdfe8d42f7eedcbd727c6861c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 21 Mar 2015 11:08:15 -0700 Subject: 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(-) (limited to 'src') diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4537fc763c9..df94a6ac80f 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 c9b105f72a5..df280dab37d 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 a1c8630e0ec..a48758366f3 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 9fa12b1ef30..9079c0aaffb 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 e52e68dad23..43aa4155629 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 2a852fbcd57..53f18a57325 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"); -- cgit 1.4.1-3-g733a5 From 558c427cd3baac76d98c4c73cea15c4073ef5e93 Mon Sep 17 00:00:00 2001 From: Liam Monahan Date: Sun, 22 Mar 2015 23:54:59 -0400 Subject: Fix a typo in the Rust Book ownership page. --- src/doc/trpl/ownership.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 6aced23ede0..9a2eb458bc6 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 -- cgit 1.4.1-3-g733a5 From 37601131a0ffc49e93b8797020429a980520171c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 15 Feb 2015 15:09:26 -0500 Subject: 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(-) (limited to 'src') diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 6324e8fa874..fc3f4b426d8 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 e8181395b5c..dd7144636df 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 6b66d7227d3..b4f21492ca1 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 7dfbccea0dc..764e342a0c5 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 99c35c6e542..4b8c4ee88c0 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 cf36ec1f3ed..07c94097e2d 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 c1bc7219ad8..5a48b8e4bce 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 4da17972c55..aa038f8ddca 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 28e7027b212..4f06346fb45 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 32f91a175f3..d2a06fcf990 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 bc581a6af41..b95e0ce8cb3 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 97cc3ac7c48..8744df0e202 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, -- cgit 1.4.1-3-g733a5 From 9330bae4bde720dbdf8d379bd5529a1bb7a6f1e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Mar 2015 10:08:33 -0400 Subject: 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 ++++++++-- src/test/compile-fail/borrowck-overloaded-call.rs | 18 ++++++++++++++---- src/test/compile-fail/coerce-unsafe-to-closure.rs | 3 ++- src/test/compile-fail/extern-wrong-value-type.rs | 2 +- .../feature-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 +++++++-- src/test/compile-fail/overloaded-calls-nontuple.rs | 6 +++++- .../compile-fail/unboxed-closures-fnmut-as-fn.rs | 9 ++++++--- .../unboxed-closures-recursive-fn-using-fn-mut.rs | 9 +++++++-- .../unboxed-closures-unsafe-extern-fn.rs | 8 ++++++-- .../compile-fail/unboxed-closures-wrong-abi.rs | 8 ++++++-- .../unboxed-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 +++++++++- .../run-pass/overloaded-calls-param-vtables.rs | 11 +++++++++-- src/test/run-pass/overloaded-calls-simple.rs | 18 ++++++++++++++++-- src/test/run-pass/overloaded-calls-zero-args.rs | 6 +++++- .../unboxed-closures-fn-as-fnmut-and-fnonce.rs | 10 +++++++++- .../run-pass/unboxed-closures-fnmut-as-fnonce.rs | 8 ++++++-- .../unboxed-closures-infer-recursive-fn.rs | 11 +++++++++-- src/test/run-pass/unboxed-closures-manual-impl.rs | 8 ++++++-- 28 files changed, 216 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index 488f0d756d3..234cd6e0fd2 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 673c025e863..93c37524bf5 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 fe7635f065c..27b4a04054f 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 db3373ea027..d1abed9b262 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 e5e5ddadafc..d86c5d211dc 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 35c55193136..6433255bd4d 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 838e65e1d05..8e1e88a92e4 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 8f79022405e..3853434e128 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 e4bedbbb7e1..fe427e02451 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 61752e62abd..77ac97bc8b8 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 c4019fa2209..ea47d676412 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 92e6affa4c2..93498ac7f83 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 713b64b1349..2dcd7a97d89 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 23f7ee2b010..dc7c70ba649 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 40655f8a3ce..cdcb435b65a 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 ebcbdbbc006..150bf36dcc2 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 81a8b29461c..6c0e5edae72 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 6335f79be6c..ab5a2f03ece 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 53d0f7dae05..91ad7e03623 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 389baecafd1..fda35d3e7f4 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 3082fc27a7d..9a476f563ed 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 0ac9c97532b..081e1417d5f 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 d18a91c5452..b20c80dc4c9 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 78e84b9d55b..245ff6df614 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 0aab5be2877..aad190d0236 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 a8bb0918932..94be6406367 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 2d1ba7f39b2..a2ab06049d6 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 f1b79a1829e..439ec4af9eb 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 } -- cgit 1.4.1-3-g733a5 From 37dc801fe630214e7b27899eb89626c8611ce5ff Mon Sep 17 00:00:00 2001 From: Liam Monahan Date: Mon, 23 Mar 2015 21:19:54 -0400 Subject: 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(-) (limited to 'src') diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 9a2eb458bc6..b851f19d22d 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 -- cgit 1.4.1-3-g733a5 From a9b31969dcf52f7d3092036be5e0bbe77a9ff7e4 Mon Sep 17 00:00:00 2001 From: Nicholas Mazzuca Date: Tue, 24 Mar 2015 03:25:48 -0700 Subject: 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(+) (limited to 'src') diff --git a/src/etc/libc.c b/src/etc/libc.c index 2bf919d7e2c..249b5d22b6b 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 893781e6220..16570086d43 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; -- cgit 1.4.1-3-g733a5 From a34e87f3ab29f6643679d2e430f21724cdcc26b6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 23 Mar 2015 15:40:43 -0400 Subject: 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(+) (limited to 'src') diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index 7df6d6887a2..72f4fbb116c 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) -- cgit 1.4.1-3-g733a5 From f2996c0c0eaad9e2f589844ba2ee401f1196d347 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 20 Mar 2015 22:09:57 -0400 Subject: 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 (limited to 'src') diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 6ff51e8d1b9..69d49f67941 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 00000000000..f36c2c56b6a --- /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. -- cgit 1.4.1-3-g733a5 From 0031d57a2107546d3763a0cfd867189a64fac77b Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 12:15:49 -0400 Subject: 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(-) (limited to 'src') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 3938a610668..c94d8e2ed0c 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` -- cgit 1.4.1-3-g733a5 From f2e0810cb8a3aacea93193ec70c882d3b6b4971c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 12:41:22 -0400 Subject: correct reference wrt shifts Fixes #23421 --- src/doc/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/doc/reference.md b/src/doc/reference.md index 415ec4e4fbf..6e6c56d3df2 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 -- cgit 1.4.1-3-g733a5 From 4ccf374b4a2ef24862d365783b70217bbfbf3bc7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 11:14:35 -0700 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 237435d6dfb..33c4156fc0c 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) + } } } -- cgit 1.4.1-3-g733a5 From 406524682bc54e821b78dc0ef5a30e6294d9997d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 24 Mar 2015 16:58:08 -0400 Subject: An example for clone --- src/libcore/clone.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 058eff121e6..85e5bde4859 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; -- cgit 1.4.1-3-g733a5 From 95602a759d9190cad92279aa5929d30166f2255c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 20 Mar 2015 17:15:27 +1300 Subject: 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 --- src/test/compile-fail/kindck-impl-type-params.rs | 1 + src/test/compile-fail/lint-dead-code-3.rs | 2 +- src/test/compile-fail/lint-unnecessary-casts.rs | 24 ---- src/test/compile-fail/liveness-unused.rs | 2 +- .../compile-fail/object-safety-by-value-self.rs | 1 + .../regions-close-object-into-object-5.rs | 1 + .../regions-close-over-type-parameter-1.rs | 2 + ...pe-parameter-defaults-referencing-Self-ppaux.rs | 2 +- src/test/compile-fail/vector-cast-weirdness.rs | 6 +- src/test/debuginfo/type-names.rs | 12 +- src/test/pretty/path-type-bounds.rs | 2 +- src/test/run-make/symbols-are-reasonable/lib.rs | 2 +- src/test/run-pass/autoderef-method-on-trait.rs | 2 +- src/test/run-pass/cast-region-to-uint.rs | 2 +- .../run-pass/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 +- ...od-two-traits-distinguished-via-where-clause.rs | 2 +- src/test/run-pass/object-one-type-two-traits.rs | 2 +- .../run-pass/objects-coerce-freeze-borrored.rs | 2 +- .../run-pass/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 +- src/test/run-pass/typeck_type_placeholder_1.rs | 10 +- src/test/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 (limited to 'src') diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 1b0356b88b0..7843be0b483 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 da2c61b6fd3..0a61eeb6e1c 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 59819d01bc6..af2daabc2d0 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 a9c5de23d94..f5db3e63c7a 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 cf427c16588..e00cdc9de88 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 49da99b97cb..d01d240e5b5 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 1d5e174a8dc..ccc1d32eab3 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 551f97ead12..0bc41eb2c6e 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 5ea60d0d96d..1557434a28a 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 7d9faa998c1..bdccab4cb9a 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 5a70911387b..d8f5aa6e548 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 1d7d78ffa6c..da2410a04cf 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 fe0d6d13c4c..5f697e02a99 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 0fd0d90b125..838caa59e47 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 9ca7b48fbe5..7686a990acc 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 21635799a77..9d91bbc7f90 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 7d520770503..2d5f163e093 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 f10822077dc..26813aa281c 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 3d6922b07b1..7fb28f27d62 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 d0c4885ad00..9f502e3ea43 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 602ef4fe45e..be5acaac92a 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 d92622eeb70..9b3ee3ef5e0 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 b7285d30a73..035d070cd6d 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 bf3e1cf03cb..17d6b684c50 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 adc15b9fbc2..4f5f269d437 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 4537fc763c9..2c431e1e050 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 e6f27a28ffa..0001cb6e0ca 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 7ea62b7fd3f..673246fe30d 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 1a794f56f80..182b05acbb6 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 793eff6a9da..dd5f3cccea5 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 44718d1c525..4f56f2441dc 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 e5e89c3fbd4..38a20c61d2e 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 e65fe904dd2..ef82a465ef4 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 ef65acf8b13..f2d2db18da4 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 506bf4a058f..4d821df72a6 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 b9ec22b86f0..ef43b9c0de4 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 e181df545e6..15738d1e61a 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 ceb9a29efa8..4d7431a20b7 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 4da17972c55..d13076df637 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 f731507ba90..920154bc916 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 6f2d0cb3667..cd6a1226e00 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 c3f4937d26b..4eddf8ae97a 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 963be9aa2e2..2858dc9b569 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 cdd8457687a..cfa84de5ca7 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 abbfc82319f..17c41448540 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 90eca6168f2..228b885b653 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 ef811f832b3..b77c8d50997 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 e52e68dad23..86b1d031f68 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 1abe8d0a3c1..6a00fff1860 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 35449bde0b2..b679456b353 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 c11ffe66e6c..1aceec310e1 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 5940b791843..1e53db60301 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 e0953a8ace6..0843713681b 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 4ae5e0faa31..44097ffeb20 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 828d085fd43..5941f044a07 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 c907b87bc3c..41e066cc94a 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 309320b52ff..1d6657d5932 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 cc9a2880b5d..8d0a9e6e971 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 402774321bf..c48c7e413d0 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 473739c919d..44af43be787 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 560844332a1..d66cfe9bf63 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 d7bb806999c..3f994102a17 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 6d2cfcab04e..a4e0f69b63b 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 c27362eea3e..00000000000 --- 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 dffc8fa2abd..71494fd5f38 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 13ee3f16361..ba1b7f03b0f 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 b3cf8257b8f..00000000000 --- 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 ac4b8a5f309..addeba03ab8 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 976717249e8..3b0e5786f3d 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 f3b5ccabe79..253132e5f07 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 fc18095fc83..924044647d8 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 8ff514e04e3..8cc531625d1 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 97e67cd2eae..cac52306d6a 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 bf26fc23d3c..d4cbd255e34 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 0a20300e4f4..42b2fe806e9 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 f81d4803f8f..474a6782b61 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 6a038927f4a..0bec3af4273 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 a298a08a1b7..deb0c0d0dc0 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 7347ded99e7..00000000000 --- 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 7bfd8e0ab71..f30991a1963 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 59bca87bed0..54773d71cbe 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 669a5cdfe30..6e88379f9a4 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 c8da4852ad3..de8d116255b 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 f8a3ce7cda0..baf8c6e4c97 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 efdd42c382c..368842ed1b0 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 63fb18a8ba2..c87c79ca24e 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 152fb5dc961..920cd9e03ab 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 a6c6db1a127..5c0d0fe9a63 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 f4c0992ae1a..53e78db68b1 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 4cb7e40a4fb..ba125997470 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 ()) } } -- cgit 1.4.1-3-g733a5 From 9374c216f6040189301aeb043d317c12ffb17a0b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 15:26:51 +1300 Subject: Minor refactoring in coercion.rs --- src/librustc_typeck/check/coercion.rs | 310 ++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 147 deletions(-) (limited to 'src') diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 920154bc916..8ad11e19b34 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 - } + }) }) } -- cgit 1.4.1-3-g733a5 From 088cd566ea87c90a9c765a113a2310d60849e7c1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 15:50:32 +1300 Subject: Remove the UnusedCasts lint --- src/librustc_lint/builtin.rs | 24 ------------------------ src/librustc_lint/lib.rs | 1 - 2 files changed, 25 deletions(-) (limited to 'src') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ef82a465ef4..395460aca9f 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 f2d2db18da4..e158541cd1c 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, -- cgit 1.4.1-3-g733a5 From dc206a91c8b641b4eccd51541f59d96fabea877d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 23 Mar 2015 17:28:57 +1300 Subject: 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 (limited to 'src') diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4eddf8ae97a..c8c7fb046b1 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 00000000000..05c7747d5b9 --- /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 00000000000..4b145f1079b --- /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; +} -- cgit 1.4.1-3-g733a5 From e7122a5a09d06aedd1d27d14c3ac38c40b0a7425 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 24 Mar 2015 11:23:34 +1300 Subject: 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(-) (limited to 'src') diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 0a61eeb6e1c..6a65c991c95 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 f5db3e63c7a..9e6dbce0325 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 e00cdc9de88..aa0d0a1539a 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 d01d240e5b5..56d2eabc095 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 ccc1d32eab3..2feb2f8b1e3 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 0bc41eb2c6e..1e6fb51a8a5 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 1557434a28a..efafce3fdef 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 bdccab4cb9a..72b0236a8d2 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 d8f5aa6e548..a64a4febd5a 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 da2410a04cf..459814875ee 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 5f697e02a99..675f568a960 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 838caa59e47..9af51a36748 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 7686a990acc..0eec875afc3 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 9d91bbc7f90..289c5dbd08e 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 2d5f163e093..6d0b6b0e5ea 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 26813aa281c..bf8747fdb6e 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 7fb28f27d62..05199735d4a 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 9f502e3ea43..c22f31cc57e 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 be5acaac92a..82dd3312782 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 0001cb6e0ca..a682fa85841 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 673246fe30d..14bebe0cd91 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 dd5f3cccea5..e8af07e4381 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 4f56f2441dc..2cc47f258f0 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 395460aca9f..8b57a48f3ce 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 4d821df72a6..9d564fa56f5 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 ef43b9c0de4..99a64156d66 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 c8c7fb046b1..47aafa2251d 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 17c41448540..0d6ed91d529 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 228b885b653..cca6bb747d4 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 1aceec310e1..a25a6451918 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 addeba03ab8..0fee48a8c6c 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 3b0e5786f3d..5a8772d6142 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 05c7747d5b9..3119b865488 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 4b145f1079b..3da1ba0f045 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) {} -- cgit 1.4.1-3-g733a5 From 5fa4b4c4af14e391d7f16b4968aa25cca7c617c6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:13:07 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index c9bbc0d74cd..b5d16d29272 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. -- cgit 1.4.1-3-g733a5 From 0adab507bbb0b04fe389a00af19fc17753b76343 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:14:28 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 7adfd9154ac..48629beafc8 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 f287712d9d4..13578ce0517 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 0f936641cdc..b509b3472ee 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 5a1e05f9c15..a5a73314a6d 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 2a852fbcd57..e8bec66d987 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, -- cgit 1.4.1-3-g733a5 From 26a79e3c204496f55b8c6ff9db741672554f1705 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:20:12 +0100 Subject: Added `Write` bounds to avoid a specialized Drop impl for `BufWriter`. --- src/libstd/io/buffered.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4def601f1c0..2a1294f23b2 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; -- cgit 1.4.1-3-g733a5 From 1249e6089180211c18fdc381a464274ec95edb25 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:22:21 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 14ed253d8e2..1be8b0dd862 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 8d14824d37f..f3930a8a5d6 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? -- cgit 1.4.1-3-g733a5 From 1e71d2e71c037b0008ce9f65a61cf814abd52b68 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:28:20 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/old_io/buffered.rs b/src/libstd/old_io/buffered.rs index cb67d709a14..9a9d421dfe1 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; -- cgit 1.4.1-3-g733a5 From 018eeb76f0e7384f760afa2a97a07110eef05145 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:30:26 +0100 Subject: added `T:Send` bound to `Mutex` to avoid specialized Drop impl. --- src/libstd/sync/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 2bf75cf1d37..6c1cda783b7 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 -- cgit 1.4.1-3-g733a5 From 123b5c124e12ba08bd351c414753902aae9eb045 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:31:58 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 48629beafc8..eb421fe55a4 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 33c1614e1b2..71236269487 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, -- cgit 1.4.1-3-g733a5 From 5f57fd591d890cbf9cfc94123071c1a30d809b9e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:33:12 +0100 Subject: 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(-) (limited to 'src') diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 3fb13739aa7..cd6d1ee05c7 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 -- cgit 1.4.1-3-g733a5 From 290c8de0a6f233b1d30c8a97cb41614fce989d30 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:34:33 +0100 Subject: Added `T:Send` bound to `JoinGuard` to avoid specialized `Drop` impl. --- src/libstd/thread/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 57baeb1fb74..27b50fc9aaa 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>, } -- cgit 1.4.1-3-g733a5 From 5b2e8693e42dee545d336c0364773b3fbded93a5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 21 Mar 2015 13:12:08 +0100 Subject: 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 +- src/librustc/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(-) (limited to 'src') diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 2116976d55a..dbf0cae6f4b 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 7d789bedc50..16b387330b9 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 835964828d4..a38adabee91 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 e5e89c3fbd4..71c4962d526 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 9c48ac43ee4..c48033cab89 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 c3f4937d26b..04ea7961f50 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 396d060de9e..95e06879fb2 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 6c1cda783b7..b24cfbb6899 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 89b3b56121a..832665abdc2 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 9b300deaa49..265db3fe133 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 6af07c422ef..e544585745d 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 8d0e0654933..7ca0ee01015 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 9d5f8576c63..08ee955cabb 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 } -- cgit 1.4.1-3-g733a5 From 1955e052675d4457432da85a00db0ae55be64e83 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 24 Mar 2015 10:46:40 +0100 Subject: Unit tests for Issue 8142, collected into one file. --- .../compile-fail/reject-specialized-drops-8142.rs | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/test/compile-fail/reject-specialized-drops-8142.rs (limited to 'src') 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 00000000000..30264c9f218 --- /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() { } -- cgit 1.4.1-3-g733a5 From 7e3ee02006ec53ff176fc3490ba01eb2a9c823b8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 24 Mar 2015 13:50:14 +1300 Subject: 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(-) (limited to 'src') diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8ad11e19b34..ae1dbbb1b00 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 83d06371734..167db1e8ac2 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 1bf1b09681c..a2b824bb016 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 e29e0e27394..001313db676 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 }) } } -- cgit 1.4.1-3-g733a5 From 492f07bbda5cfd521606d1c5540855a8789659ad Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 25 Mar 2015 00:39:29 +0200 Subject: 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(-) (limited to 'src') diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index df6beab0f58..0e6e008c616 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 d57739c4002..28dfe8dca7d 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 11e10cc2aa7..d53954b29b5 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 -- cgit 1.4.1-3-g733a5 From efaef2430484852fc761b08b0653b7d74a17becd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 16:48:50 -0700 Subject: Test fixes and rebase conflicts, round 1 --- src/libstd/fs/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/libstd/fs/mod.rs b/src/libstd/fs/mod.rs index ab7675e4646..c1253706832 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")); -- cgit 1.4.1-3-g733a5 From 3021d4c56422e15331e38f4b7b04c7229e024fda Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Mar 2015 16:55:35 -0700 Subject: 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(-) (limited to 'src') diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 36c3eb33c77..ea98f6f5f24 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 1cb1f956e26..89843979cd0 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 182b05acbb6..1ffc6001af5 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 0e6e008c616..df6beab0f58 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 28dfe8dca7d..d57739c4002 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 34f89bfb877..3f813b30ecc 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 e092faf4935..734268c70ac 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 1359803070a..c908c791247 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) { -- cgit 1.4.1-3-g733a5