From 7748bc665d012042d2fe8bbda416ab4682ae45ba Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 24 May 2017 16:23:02 +0100 Subject: [PATCH 01/13] Include context info into closure_kinds --- src/librustc/infer/mod.rs | 6 +++- src/librustc/ty/context.rs | 6 ++-- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/upvar.rs | 36 +++++++++++++++-------- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 270430f40df02..a6dbbee79a48c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1682,7 +1682,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { if let InferTables::InProgress(tables) = self.tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - return tables.borrow().closure_kinds.get(&id).cloned(); + return tables.borrow() + .closure_kinds + .get(&id) + .cloned() + .map(|(kind, _)| kind); } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5ee0b1c9e5ea4..bc9fd1147b6ea 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -58,6 +58,7 @@ use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::symbol::{Symbol, keywords}; +use syntax_pos::Span; use hir; @@ -229,8 +230,9 @@ pub struct TypeckTables<'tcx> { /// Records the type of each closure. pub closure_tys: NodeMap>, - /// Records the kind of each closure. - pub closure_kinds: NodeMap, + /// Records the kind of each closure and the span of the variable that + /// cause the closure to be this kind. + pub closure_kinds: NodeMap<(ty::ClosureKind, Option)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4c3d5c8aaca7f..c2e8269aafef9 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().closure_tys.insert(expr.id, sig); match opt_kind { Some(kind) => { - self.tables.borrow_mut().closure_kinds.insert(expr.id, kind); + self.tables.borrow_mut().closure_kinds.insert(expr.id, (kind, None)); } None => {} } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9ad72b2a137ea..7981df9211aa7 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -802,7 +802,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let closure_kinds = &self.tables.borrow().closure_kinds; let closure_kind = match closure_kinds.get(&closure_id) { - Some(&k) => k, + Some(&(k, _)) => k, None => { return Err(MethodError::ClosureAmbiguity(trait_def_id)); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 24a88140cf041..06af22b9a41e8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -702,7 +702,7 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.typeck_tables_of(def_id).closure_kinds[&node_id] + tcx.typeck_tables_of(def_id).closure_kinds[&node_id].0 } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 9bfc5f3f0ea54..3d5cb13b0eed5 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { capture_clause: hir::CaptureClause) { if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) { - self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn); + self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None)); debug!("check_closure: adding closure {:?} as Fn", expr.id); } @@ -143,12 +143,12 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap) + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } @@ -211,8 +211,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // If we are also inferred the closure kind here, update the // main table and process any deferred resolutions. - if let Some(&kind) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind); + if let Some(&(kind, span)) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, span)); let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); @@ -276,6 +276,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // for that to be legal, the upvar would have to be borrowed // by value instead let guarantor = cmt.guarantor(); + let tcx = self.fcx.tcx; debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", guarantor); match guarantor.cat { @@ -289,7 +290,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // to move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind(upvar_id.closure_expr_id, - ty::ClosureKind::FnOnce); + ty::ClosureKind::FnOnce, + tcx.hir.span(upvar_id.var_id)); let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; @@ -303,7 +305,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // to be a FnOnce closure to permit moves out // of the environment. self.adjust_closure_kind(upvar_id.closure_expr_id, - ty::ClosureKind::FnOnce); + ty::ClosureKind::FnOnce, + tcx.hir.span(upvar_id.var_id)); } mc::NoteNone => { } @@ -394,6 +397,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { ty::ImmBorrow => false, }); + let tcx = self.fcx.tcx; + match *note { mc::NoteUpvarRef(upvar_id) => { // if this is an implicit deref of an @@ -407,7 +412,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } // also need to be in an FnMut closure since this is not an ImmBorrow - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir.span(upvar_id.var_id)); true } @@ -415,7 +422,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // this kind of deref occurs in a `move` closure, or // for a by-value upvar; in either case, to mutate an // upvar, we need to be an FnMut closure - self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut); + self.adjust_closure_kind(upvar_id.closure_expr_id, + ty::ClosureKind::FnMut, + tcx.hir.span(upvar_id.var_id)); true } @@ -462,11 +471,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, - new_kind: ty::ClosureKind) { + new_kind: ty::ClosureKind, + upvar_span: Span) { debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", closure_id, new_kind); - if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) { + if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); @@ -482,7 +492,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind - self.temp_closure_kinds.insert(closure_id, new_kind); + self.temp_closure_kinds.insert(closure_id, (new_kind, Some(upvar_span))); } } } From bf25b5eb823c3cbbacc06d33a3ff539de325be6a Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 24 May 2017 17:30:27 +0100 Subject: [PATCH 02/13] Explain why a closure is `FnOnce` in closure errors --- src/librustc_borrowck/borrowck/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f7c20542cbf2e..297df4978a59e 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -597,6 +597,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Ok(ty::ClosureKind::FnOnce) = ty::queries::closure_kind::try_get(self.tcx, DUMMY_SP, id) { err.help("closure was moved because it only implements `FnOnce`"); + if let Some(&(_kind, Some(span))) = self.tables.closure_kinds.get( ) { + err.span_label(span, "move occured here"); + } false } else { true From b55950768036d36704db6721d6ad47891d95b1ad Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Sat, 27 May 2017 00:25:21 +0200 Subject: [PATCH 03/13] Clarify the docs for align_of and its variants --- src/libcore/mem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f4ce4697d7cf4..97b814a5da217 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -220,7 +220,7 @@ pub fn size_of_val(val: &T) -> usize { /// Returns the [ABI]-required minimum alignment of a type. /// -/// Every valid address of a value of the type `T` must be a multiple of this number. +/// Every reference to a value of type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// @@ -243,7 +243,7 @@ pub fn min_align_of() -> usize { /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. /// -/// Every valid address of a value of the type `T` must be a multiple of this number. +/// Every reference to a value of type `T` must be a multiple of this number. /// /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// @@ -264,7 +264,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// Returns the [ABI]-required minimum alignment of a type. /// -/// Every valid address of a value of the type `T` must be a multiple of this number. +/// Every reference to a value of type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// @@ -285,7 +285,7 @@ pub fn align_of() -> usize { /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. /// -/// Every valid address of a value of the type `T` must be a multiple of this number. +/// Every reference to a value of type `T` must be a multiple of this number. /// /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// From 54bbe23b2efe238044faa2679cb318e8253f0370 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 20 May 2017 15:24:43 -0400 Subject: [PATCH 04/13] Clarify docs on implementing Into. --- src/libcore/convert.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 21c75ad339511..11a360ff900fe 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -169,6 +169,40 @@ pub trait AsMut { /// - [`From`][From]` for U` implies `Into for T` /// - [`into`] is reflexive, which means that `Into for T` is implemented /// +/// # Implementing `Into` +/// +/// There is one exception to implementing `Into`, and it's kind of esoteric. +/// If the destination type is not part of the current crate, and it uses a +/// generic variable, then you can't implement `From` directly. For example, +/// take this crate: +/// +/// ```compile_fail +/// struct Wrapper(Vec); +/// impl From> for Vec { +/// fn from(w: Wrapper) -> Vec { +/// w.0 +/// } +/// } +/// ``` +/// +/// To fix this, you can implement `Into` directly: +/// +/// ``` +/// struct Wrapper(Vec); +/// impl Into> for Wrapper { +/// fn into(self) -> Vec { +/// self.0 +/// } +/// } +/// ``` +/// +/// This won't always allow the conversion: for example, `try!` and `?` +/// always use `From`. However, in most cases, people use `Into` to do the +/// conversions, and this will allow that. +/// +/// In almost all cases, you should try to implement `From`, then fall back +/// to `Into` if `From` can't be implemented. +/// /// # Examples /// /// [`String`] implements `Into>`: @@ -285,9 +319,11 @@ pub trait From: Sized { /// Library authors should not directly implement this trait, but should prefer /// implementing the [`TryFrom`] trait, which offers greater flexibility and /// provides an equivalent `TryInto` implementation for free, thanks to a -/// blanket implementation in the standard library. +/// blanket implementation in the standard library. For more information on this, +/// see the documentation for [`Into`]. /// /// [`TryFrom`]: trait.TryFrom.html +/// [`Into`]: trait.Into.html #[unstable(feature = "try_from", issue = "33417")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. From 9873acc54b03e2caff16bde83962adeee8d0387b Mon Sep 17 00:00:00 2001 From: Michael Kohl Date: Sun, 28 May 2017 13:49:14 +0700 Subject: [PATCH 05/13] Remove --crate-type=metadata deprecation warning Fixes #38640 --- src/librustc/session/config.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7cb5f2510d5c7..589489b49b4fd 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1354,7 +1354,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) }; let unparsed_crate_types = matches.opt_strs("crate-type"); - let (crate_types, emit_metadata) = parse_crate_types_from_list(unparsed_crate_types) + let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_error(error_format, &e[..])); let mut lint_opts = vec![]; @@ -1402,9 +1402,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } } }; - if emit_metadata { - output_types.insert(OutputType::Metadata, None); - } else if output_types.is_empty() { + if output_types.is_empty() { output_types.insert(OutputType::Exe, None); } @@ -1629,9 +1627,8 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } pub fn parse_crate_types_from_list(list_list: Vec) - -> Result<(Vec, bool), String> { + -> Result, String> { let mut crate_types: Vec = Vec::new(); - let mut emit_metadata = false; for unparsed_crate_type in &list_list { for part in unparsed_crate_type.split(',') { let new_part = match part { @@ -1642,13 +1639,6 @@ pub fn parse_crate_types_from_list(list_list: Vec) "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, "proc-macro" => CrateTypeProcMacro, - // FIXME(#38640) remove this when Cargo is fixed. - "metadata" => { - early_warn(ErrorOutputType::default(), "--crate-type=metadata is deprecated, \ - prefer --emit=metadata"); - emit_metadata = true; - CrateTypeRlib - } _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1660,7 +1650,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) } } - return Ok((crate_types, emit_metadata)); + Ok(crate_types) } pub mod nightly_options { From ee88a870b6738232c34aa4e1049d94099648386b Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Sun, 28 May 2017 22:08:51 +0100 Subject: [PATCH 06/13] Explain why closure is moved in error message --- src/librustc/ty/context.rs | 6 ++-- src/librustc_borrowck/borrowck/mod.rs | 16 +++++----- src/librustc_typeck/check/upvar.rs | 45 ++++++++++++++++----------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bc9fd1147b6ea..8deeb35270d25 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -230,9 +230,9 @@ pub struct TypeckTables<'tcx> { /// Records the type of each closure. pub closure_tys: NodeMap>, - /// Records the kind of each closure and the span of the variable that - /// cause the closure to be this kind. - pub closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + /// Records the kind of each closure and the span and name of the variable + /// that caused the closure to be this kind. + pub closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 297df4978a59e..b25252eef8c68 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -39,8 +39,6 @@ use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; -use syntax_pos::DUMMY_SP; - use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; @@ -594,12 +592,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { verb, msg, nl); let need_note = match lp.ty.sty { ty::TypeVariants::TyClosure(id, _) => { - if let Ok(ty::ClosureKind::FnOnce) = - ty::queries::closure_kind::try_get(self.tcx, DUMMY_SP, id) { - err.help("closure was moved because it only implements `FnOnce`"); - if let Some(&(_kind, Some(span))) = self.tables.closure_kinds.get( ) { - err.span_label(span, "move occured here"); - } + let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); + if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = + self.tables.closure_kinds.get(&node_id) + { + err.help(&format!("closure cannot be invoked more than once because \ + it moves the variable `{}` out of its environment", + name)); + err.span_label(span, format!("{} moved here", name)); false } else { true diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 3d5cb13b0eed5..114290c52d195 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -143,12 +143,12 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>, + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option)>) + temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } @@ -211,8 +211,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // If we are also inferred the closure kind here, update the // main table and process any deferred resolutions. - if let Some(&(kind, span)) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, span)); + if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context)); let closure_def_id = self.fcx.tcx.hir.local_def_id(id); debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); @@ -272,11 +272,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { euv::Move(_) => { } } + let tcx = self.fcx.tcx; + // watch out for a move of the deref of a borrowed pointer; // for that to be legal, the upvar would have to be borrowed // by value instead let guarantor = cmt.guarantor(); - let tcx = self.fcx.tcx; debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}", guarantor); match guarantor.cat { @@ -291,7 +292,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // to move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir.span(upvar_id.var_id)); + guarantor.span, + tcx.hir.name(upvar_id.var_id)); let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; @@ -306,7 +308,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // of the environment. self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir.span(upvar_id.var_id)); + guarantor.span, + tcx.hir.name(upvar_id.var_id)); } mc::NoteNone => { } @@ -334,7 +337,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(base, _, mc::BorrowedPtr(..)) | Categorization::Deref(base, _, mc::Implicit(..)) => { - if !self.try_adjust_upvar_deref(&cmt.note, ty::MutBorrow) { + if !self.try_adjust_upvar_deref(cmt, ty::MutBorrow) { // assignment to deref of an `&mut` // borrowed pointer implies that the // pointer itself must be unique, but not @@ -368,7 +371,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { Categorization::Deref(base, _, mc::BorrowedPtr(..)) | Categorization::Deref(base, _, mc::Implicit(..)) => { - if !self.try_adjust_upvar_deref(&cmt.note, ty::UniqueImmBorrow) { + if !self.try_adjust_upvar_deref(cmt, ty::UniqueImmBorrow) { // for a borrowed pointer to be unique, its // base must be unique self.adjust_upvar_borrow_kind_for_unique(base); @@ -385,7 +388,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } fn try_adjust_upvar_deref(&mut self, - note: &mc::Note, + cmt: mc::cmt<'tcx>, borrow_kind: ty::BorrowKind) -> bool { @@ -399,7 +402,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { let tcx = self.fcx.tcx; - match *note { + match cmt.note { mc::NoteUpvarRef(upvar_id) => { // if this is an implicit deref of an // upvar, then we need to modify the @@ -414,7 +417,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // also need to be in an FnMut closure since this is not an ImmBorrow self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, - tcx.hir.span(upvar_id.var_id)); + cmt.span, + tcx.hir.name(upvar_id.var_id)); true } @@ -424,7 +428,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // upvar, we need to be an FnMut closure self.adjust_closure_kind(upvar_id.closure_expr_id, ty::ClosureKind::FnMut, - tcx.hir.span(upvar_id.var_id)); + cmt.span, + tcx.hir.name(upvar_id.var_id)); true } @@ -472,9 +477,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, new_kind: ty::ClosureKind, - upvar_span: Span) { - debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", - closure_id, new_kind); + upvar_span: Span, + var_name: ast::Name) { + debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})", + closure_id, new_kind, upvar_span, var_name); if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", @@ -492,7 +498,10 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind - self.temp_closure_kinds.insert(closure_id, (new_kind, Some(upvar_span))); + self.temp_closure_kinds.insert( + closure_id, + (new_kind, Some((upvar_span, var_name))) + ); } } } From 31bfdd7f178767294427e6257fbbd104e068a510 Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Tue, 30 May 2017 10:47:51 +0100 Subject: [PATCH 07/13] Update fn_once-moved test --- src/test/ui/fn_once-moved.rs | 3 ++- src/test/ui/fn_once-moved.stderr | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/ui/fn_once-moved.rs b/src/test/ui/fn_once-moved.rs index 781d3885eaee8..409964082f2b6 100644 --- a/src/test/ui/fn_once-moved.rs +++ b/src/test/ui/fn_once-moved.rs @@ -20,5 +20,6 @@ fn main() { debug_dump_dict(); debug_dump_dict(); //~^ ERROR use of moved value: `debug_dump_dict` - //~| NOTE closure was moved because it only implements `FnOnce` + //~| NOTE closure cannot be invoked more than once because it moves the + //~| variable `dict` out of its environment } diff --git a/src/test/ui/fn_once-moved.stderr b/src/test/ui/fn_once-moved.stderr index 322ab64ebd4ea..dfee5931da73d 100644 --- a/src/test/ui/fn_once-moved.stderr +++ b/src/test/ui/fn_once-moved.stderr @@ -1,12 +1,15 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/fn_once-moved.rs:21:5 | +16 | for (key, value) in dict { + | ---- dict moved here +... 20 | debug_dump_dict(); | --------------- value moved here 21 | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | - = help: closure was moved because it only implements `FnOnce` + = help: closure cannot be invoked more than once because it moves the variable `dict` out of its environment error: aborting due to previous error From 265dce66b6b1181f4b955032b742c702c753f6c8 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 30 May 2017 09:15:25 -0700 Subject: [PATCH 08/13] RangeFrom should have an infinite size_hint This makes the size_hint from things like `take` more precise. --- src/libcore/iter/iterator.rs | 3 ++- src/libcore/iter/range.rs | 5 +++++ src/libcore/tests/iter.rs | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 77cbdb98c8304..85149a0f57078 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -130,9 +130,10 @@ pub trait Iterator { /// /// ``` /// // an infinite iterator has no upper bound + /// // and the maximum possible lower bound /// let iter = 0..; /// - /// assert_eq!((0, None), iter.size_hint()); + /// assert_eq!((usize::max_value(), None), iter.size_hint()); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e02823fd81280..c0313333ea9ee 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -543,6 +543,11 @@ impl Iterator for ops::RangeFrom where mem::swap(&mut n, &mut self.start); Some(n) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } } #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 4030eaf2b2333..44d5936c63edd 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -764,6 +764,7 @@ fn test_iterator_size_hint() { let v2 = &[10, 11, 12]; let vi = v.iter(); + assert_eq!((0..).size_hint(), (usize::MAX, None)); assert_eq!(c.size_hint(), (usize::MAX, None)); assert_eq!(vi.clone().size_hint(), (10, Some(10))); From c25e271858d3aa131814a6c60669783d20b5e89e Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 30 May 2017 21:34:50 +0200 Subject: [PATCH 09/13] Add 'the' --- src/libcore/mem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 97b814a5da217..da38538a70016 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -220,7 +220,7 @@ pub fn size_of_val(val: &T) -> usize { /// Returns the [ABI]-required minimum alignment of a type. /// -/// Every reference to a value of type `T` must be a multiple of this number. +/// Every reference to a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// @@ -243,7 +243,7 @@ pub fn min_align_of() -> usize { /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. /// -/// Every reference to a value of type `T` must be a multiple of this number. +/// Every reference to a value of the type `T` must be a multiple of this number. /// /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// @@ -264,7 +264,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// Returns the [ABI]-required minimum alignment of a type. /// -/// Every reference to a value of type `T` must be a multiple of this number. +/// Every reference to a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// @@ -285,7 +285,7 @@ pub fn align_of() -> usize { /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. /// -/// Every reference to a value of type `T` must be a multiple of this number. +/// Every reference to a value of the type `T` must be a multiple of this number. /// /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// From c2f7e945526bff3b7d812137d81b235263060ee8 Mon Sep 17 00:00:00 2001 From: Tommy Ip Date: Wed, 31 May 2017 00:07:09 +0100 Subject: [PATCH 10/13] Update closure errors to use `span_note` --- src/librustc_borrowck/borrowck/mod.rs | 9 +++++---- src/test/ui/fn_once-moved.stderr | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index b25252eef8c68..2089a49ad37cd 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -596,10 +596,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { if let Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) = self.tables.closure_kinds.get(&node_id) { - err.help(&format!("closure cannot be invoked more than once because \ - it moves the variable `{}` out of its environment", - name)); - err.span_label(span, format!("{} moved here", name)); + err.span_note(span, &format!( + "closure cannot be invoked more than once because \ + it moves the variable `{}` out of its environment", + name + )); false } else { true diff --git a/src/test/ui/fn_once-moved.stderr b/src/test/ui/fn_once-moved.stderr index dfee5931da73d..acb52651bcd8c 100644 --- a/src/test/ui/fn_once-moved.stderr +++ b/src/test/ui/fn_once-moved.stderr @@ -1,15 +1,16 @@ error[E0382]: use of moved value: `debug_dump_dict` --> $DIR/fn_once-moved.rs:21:5 | -16 | for (key, value) in dict { - | ---- dict moved here -... 20 | debug_dump_dict(); | --------------- value moved here 21 | debug_dump_dict(); | ^^^^^^^^^^^^^^^ value used here after move | - = help: closure cannot be invoked more than once because it moves the variable `dict` out of its environment +note: closure cannot be invoked more than once because it moves the variable `dict` out of its environment + --> $DIR/fn_once-moved.rs:16:29 + | +16 | for (key, value) in dict { + | ^^^^ error: aborting due to previous error From 69f822524f417ec9ab50131379eb34412c3b2b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Huchet?= Date: Wed, 31 May 2017 11:38:19 +0200 Subject: [PATCH 11/13] fix links to "module-level documentation" --- src/libcore/iter/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 798dda1992813..015cc150dc27c 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -109,7 +109,7 @@ pub trait FromIterator: Sized { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: trait.FromIterator.html + /// [module-level documentation]: index.html /// /// # Examples /// @@ -219,7 +219,7 @@ pub trait IntoIterator { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: trait.IntoIterator.html + /// [module-level documentation]: index.html /// /// # Examples /// From 54edfee71a7d2a8f710c578be75c0537a430eaaf Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 31 May 2017 19:24:01 +0900 Subject: [PATCH 12/13] Parse macros named "default" correctly. --- src/libsyntax/parse/parser.rs | 33 ++++++++++-------------- src/test/run-pass/macro-named-default.rs | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 src/test/run-pass/macro-named-default.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8d7c8c5248bb9..63fe33b8754d3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -698,24 +698,6 @@ impl<'a> Parser<'a> { } } - pub fn check_contextual_keyword(&mut self, ident: Ident) -> bool { - self.expected_tokens.push(TokenType::Token(token::Ident(ident))); - if let token::Ident(ref cur_ident) = self.token { - cur_ident.name == ident.name - } else { - false - } - } - - pub fn eat_contextual_keyword(&mut self, ident: Ident) -> bool { - if self.check_contextual_keyword(ident) { - self.bump(); - true - } else { - false - } - } - /// If the given word is not a keyword, signal an error. /// If the next token is not the given word, signal an error. /// Otherwise, eat it. @@ -3755,6 +3737,18 @@ impl<'a> Parser<'a> { self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) } + fn is_defaultness(&self) -> bool { + // `pub` is included for better error messages + self.token.is_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl) || + t.is_keyword(keywords::Const) || + t.is_keyword(keywords::Fn) || + t.is_keyword(keywords::Unsafe) || + t.is_keyword(keywords::Extern) || + t.is_keyword(keywords::Type) || + t.is_keyword(keywords::Pub)) + } + fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option>> { let lo = self.span; @@ -5229,7 +5223,8 @@ impl<'a> Parser<'a> { /// Parse defaultness: DEFAULT or nothing fn parse_defaultness(&mut self) -> PResult<'a, Defaultness> { - if self.eat_contextual_keyword(keywords::Default.ident()) { + if self.is_defaultness() { + self.bump(); Ok(Defaultness::Default) } else { Ok(Defaultness::Final) diff --git a/src/test/run-pass/macro-named-default.rs b/src/test/run-pass/macro-named-default.rs new file mode 100644 index 0000000000000..028d59a19dd64 --- /dev/null +++ b/src/test/run-pass/macro-named-default.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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. + +macro_rules! default { + ($($x:tt)*) => { $($x)* } +} + +default! { + struct A; +} + +impl A { + default! { + fn foo(&self) {} + } +} + +fn main() { + A.foo(); +} From b670930933fd8af2316364d4e15e6a22983cf78d Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 31 May 2017 23:22:33 +0900 Subject: [PATCH 13/13] Emit proper expectation for the "default" keyword. --- src/libsyntax/parse/parser.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 63fe33b8754d3..936a2e8b2e1be 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3749,6 +3749,16 @@ impl<'a> Parser<'a> { t.is_keyword(keywords::Pub)) } + fn eat_defaultness(&mut self) -> bool { + let is_defaultness = self.is_defaultness(); + if is_defaultness { + self.bump() + } else { + self.expected_tokens.push(TokenType::Keyword(keywords::Default)); + } + is_defaultness + } + fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option>> { let lo = self.span; @@ -5223,8 +5233,7 @@ impl<'a> Parser<'a> { /// Parse defaultness: DEFAULT or nothing fn parse_defaultness(&mut self) -> PResult<'a, Defaultness> { - if self.is_defaultness() { - self.bump(); + if self.eat_defaultness() { Ok(Defaultness::Default) } else { Ok(Defaultness::Final)