about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-05-31 21:14:02 +0000
committerbors <bors@rust-lang.org>2017-05-31 21:14:02 +0000
commite0cc22b4bae8007c59fbe58f2c104ecd743d746a (patch)
tree8c4084d31f5b5c2cbc0d4fcf7d32fe9f3f6a932f
parentfd7b44b78e39c71e5049a210a0c84a8931835cc3 (diff)
parent7f286a8e38258402c6e8e564864ac0132fac2004 (diff)
downloadrust-e0cc22b4bae8007c59fbe58f2c104ecd743d746a.tar.gz
rust-e0cc22b4bae8007c59fbe58f2c104ecd743d746a.zip
Auto merge of #42336 - Mark-Simulacrum:rollup, r=Mark-Simulacrum
Rollup of 7 pull requests

- Successful merges: #42126, #42196, #42252, #42277, #42315, #42329, #42330
- Failed merges:
-rw-r--r--src/libcore/convert.rs38
-rw-r--r--src/libcore/iter/iterator.rs3
-rw-r--r--src/libcore/iter/range.rs5
-rw-r--r--src/libcore/iter/traits.rs4
-rw-r--r--src/libcore/mem.rs8
-rw-r--r--src/libcore/tests/iter.rs1
-rw-r--r--src/librustc/infer/mod.rs6
-rw-r--r--src/librustc/session/config.rs18
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs14
-rw-r--r--src/librustc_typeck/check/closure.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/upvar.rs57
-rw-r--r--src/libsyntax/parse/parser.rs42
-rw-r--r--src/test/run-pass/macro-named-default.rs27
-rw-r--r--src/test/ui/fn_once-moved.rs3
-rw-r--r--src/test/ui/fn_once-moved.stderr6
18 files changed, 171 insertions, 73 deletions
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index 21c75ad3395..11a360ff900 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -169,6 +169,40 @@ pub trait AsMut<T: ?Sized> {
 /// - [`From<T>`][From]` for U` implies `Into<U> for T`
 /// - [`into`] is reflexive, which means that `Into<T> 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<T>(Vec<T>);
+/// impl<T> From<Wrapper<T>> for Vec<T> {
+///     fn from(w: Wrapper<T>) -> Vec<T> {
+///         w.0
+///     }
+/// }
+/// ```
+///
+/// To fix this, you can implement `Into` directly:
+///
+/// ```
+/// struct Wrapper<T>(Vec<T>);
+/// impl<T> Into<Vec<T>> for Wrapper<T> {
+///     fn into(self) -> Vec<T> {
+///         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<Vec<u8>>`:
@@ -285,9 +319,11 @@ pub trait From<T>: 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<T>: Sized {
     /// The type returned in the event of a conversion error.
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 77cbdb98c83..85149a0f570 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 e02823fd812..c0313333ea9 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -543,6 +543,11 @@ impl<A: Step> Iterator for ops::RangeFrom<A> where
         mem::swap(&mut n, &mut self.start);
         Some(n)
     }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (usize::MAX, None)
+    }
 }
 
 #[unstable(feature = "fused", issue = "35602")]
diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs
index 798dda19928..015cc150dc2 100644
--- a/src/libcore/iter/traits.rs
+++ b/src/libcore/iter/traits.rs
@@ -109,7 +109,7 @@ pub trait FromIterator<A>: 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
     ///
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 18428d378e3..d11ad76d65d 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -220,7 +220,7 @@ pub fn size_of_val<T: ?Sized>(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 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<T>() -> 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 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<T: ?Sized>(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 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<T>() -> 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 the type `T` must be a multiple of this number.
 ///
 /// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
 ///
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index 4030eaf2b23..44d5936c63e 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)));
 
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 270430f40df..a6dbbee79a4 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/session/config.rs b/src/librustc/session/config.rs
index 7cb5f2510d5..589489b49b4 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<String>)
-                                   -> Result<(Vec<CrateType>, bool), String> {
+                                   -> Result<Vec<CrateType>, String> {
     let mut crate_types: Vec<CrateType> = 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<String>)
                 "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<String>)
         }
     }
 
-    return Ok((crate_types, emit_metadata));
+    Ok(crate_types)
 }
 
 pub mod nightly_options {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 7316d45dc21..e3d7aeb22e1 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<ty::PolyFnSig<'tcx>>,
 
-    /// Records the kind of each closure.
-    pub closure_kinds: NodeMap<ty::ClosureKind>,
+    /// 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 3248731d1ca..9b084acc193 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};
@@ -587,9 +585,15 @@ 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`");
+                        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.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/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 4c3d5c8aaca..c2e8269aafe 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 b32eb9ac5fb..1a1a9361a89 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -814,7 +814,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 b5c2780e9a7..3a6fd51693e 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 9bfc5f3f0ea..114290c52d1 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>,
+    temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>,
 }
 
 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<ty::ClosureKind>,
+    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>)
+           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) = self.temp_closure_kinds.get(&id) {
-            self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
+        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,6 +272,8 @@ 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
@@ -289,7 +291,9 @@ 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,
+                                                 guarantor.span,
+                                                 tcx.hir.name(upvar_id.var_id));
 
                         let upvar_capture_map =
                             &mut self.fcx.tables.borrow_mut().upvar_capture_map;
@@ -303,7 +307,9 @@ 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,
+                                                 guarantor.span,
+                                                 tcx.hir.name(upvar_id.var_id));
                     }
                     mc::NoteNone => {
                     }
@@ -331,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
@@ -365,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);
@@ -382,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
     {
@@ -394,7 +400,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
             ty::ImmBorrow => false,
         });
 
-        match *note {
+        let tcx = self.fcx.tcx;
+
+        match cmt.note {
             mc::NoteUpvarRef(upvar_id) => {
                 // if this is an implicit deref of an
                 // upvar, then we need to modify the
@@ -407,7 +415,10 @@ 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,
+                                         cmt.span,
+                                         tcx.hir.name(upvar_id.var_id));
 
                 true
             }
@@ -415,7 +426,10 @@ 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,
+                                         cmt.span,
+                                         tcx.hir.name(upvar_id.var_id));
 
                 true
             }
@@ -462,11 +476,13 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
 
     fn adjust_closure_kind(&mut self,
                            closure_id: ast::NodeId,
-                           new_kind: ty::ClosureKind) {
-        debug!("adjust_closure_kind(closure_id={}, new_kind={:?})",
-               closure_id, new_kind);
+                           new_kind: ty::ClosureKind,
+                           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) {
+        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 +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);
+                    self.temp_closure_kinds.insert(
+                        closure_id,
+                        (new_kind, Some((upvar_span, var_name)))
+                    );
                 }
             }
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8d7c8c5248b..936a2e8b2e1 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,28 @@ 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_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<P<Item>>> {
         let lo = self.span;
@@ -5229,7 +5233,7 @@ 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.eat_defaultness() {
             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 00000000000..028d59a19dd
--- /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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! default {
+    ($($x:tt)*) => { $($x)* }
+}
+
+default! {
+    struct A;
+}
+
+impl A {
+    default! {
+        fn foo(&self) {}
+    }
+}
+
+fn main() {
+    A.foo();
+}
diff --git a/src/test/ui/fn_once-moved.rs b/src/test/ui/fn_once-moved.rs
index 781d3885eae..409964082f2 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 91c89e55c54..27b7d91d1d4 100644
--- a/src/test/ui/fn_once-moved.stderr
+++ b/src/test/ui/fn_once-moved.stderr
@@ -6,7 +6,11 @@ error[E0382]: use of moved value: `debug_dump_dict`
 21 |     debug_dump_dict();
    |     ^^^^^^^^^^^^^^^ value used here after move
    |
-   = help: 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
+  --> $DIR/fn_once-moved.rs:16:29
+   |
+16 |         for (key, value) in dict {
+   |                             ^^^^
 
 error: aborting due to previous error(s)