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. 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/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 /// diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 18428d378e3d2..d11ad76d65dfe 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 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 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(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() -> 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 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))); 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/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 { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 7316d45dc21ae..e3d7aeb22e1fa 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 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 3248731d1cafc..9b084acc1938f 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 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 b32eb9ac5fbf6..1a1a9361a89f9 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 b5c2780e9a7af..3a6fd51693e73 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..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, + 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, + 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) + 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 8d7c8c5248bb9..936a2e8b2e1be 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>> { 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 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(); +} 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 91c89e55c54a8..27b7d91d1d4b6 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)