From aaac69f78e6a9f0ee52b41969d81f4bb79da6418 Mon Sep 17 00:00:00 2001 From: Maxwell Powlison Date: Fri, 16 Mar 2018 03:41:53 -0400 Subject: [PATCH 01/48] Fix Issue #48345, is_file, is_dir, and is_symlink note mutual exclusion The methods on the structures `fs::FileType` and `fs::Metadata` of (respectively) `is_file`, `is_dir`, and `is_symlink` had some ambiguity in documentation, where it was not noted whether files will pass those tests exclusively or not. It is now written that the tests are mutually exclusive. Fixes #48345. --- src/libstd/fs.rs | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index db52ed67d3a85..5caa703ee97e3 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -906,7 +906,13 @@ impl Metadata { FileType(self.0.file_type()) } - /// Returns whether this metadata is for a directory. + /// Returns whether this metadata is for a directory. The + /// result is mutually exclusive to the result of + /// [`is_file`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_file`]: struct.Metadata.html#method.is_file + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// @@ -923,7 +929,13 @@ impl Metadata { #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.file_type().is_dir() } - /// Returns whether this metadata is for a regular file. + /// Returns whether this metadata is for a regular file. The + /// result is mutually exclusive to the result of + /// [`is_dir`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_dir`]: struct.Metadata.html#method.is_dir + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// @@ -1148,7 +1160,13 @@ impl Permissions { } impl FileType { - /// Test whether this file type represents a directory. + /// Test whether this file type represents a directory. The + /// result is mutually exclusive to the results of + /// [`is_file`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_file`]: struct.FileType.html#method.is_file + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// @@ -1167,6 +1185,12 @@ impl FileType { pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Test whether this file type represents a regular file. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// @@ -1185,6 +1209,9 @@ impl FileType { pub fn is_file(&self) -> bool { self.0.is_file() } /// Test whether this file type represents a symbolic link. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_file`]; only zero or one of these + /// tests may pass. /// /// The underlying [`Metadata`] struct needs to be retrieved /// with the [`fs::symlink_metadata`] function and not the @@ -1195,6 +1222,8 @@ impl FileType { /// [`Metadata`]: struct.Metadata.html /// [`fs::metadata`]: fn.metadata.html /// [`fs::symlink_metadata`]: fn.symlink_metadata.html + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_file`]: struct.FileType.html#method.is_file /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples From 683ad942966c427be773b412d9314baa55a6e188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 15 Mar 2018 10:38:12 +0100 Subject: [PATCH 02/48] Add OnDrop --- src/librustc_data_structures/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 81246aea1b56e..bf0b3726bb301 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -76,6 +76,14 @@ pub mod flock; pub mod sync; pub mod owning_ref; +pub struct OnDrop(pub F); + +impl Drop for OnDrop { + fn drop(&mut self) { + (self.0)(); + } +} + // See comments in src/librustc/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} From 3b43dcbb4c62a36b68afd7f9a1bf12aed1b53d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 14 Mar 2018 20:11:23 +0100 Subject: [PATCH 03/48] Replace Rc with Lrc --- src/librustc/middle/const_val.rs | 4 ++-- src/librustc/traits/query/dropck_outlives.rs | 6 +++--- src/librustc/traits/query/normalize.rs | 6 +++--- src/librustc/ty/structural_impls.rs | 3 ++- src/librustc_mir/interpret/const_eval.rs | 6 +++--- src/librustc_traits/dropck_outlives.rs | 4 ++-- src/librustc_traits/normalize_projection_ty.rs | 4 ++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 8c3dfd0bce752..19a7576b7ceac 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -19,7 +19,7 @@ use graphviz::IntoCow; use syntax_pos::Span; use std::borrow::Cow; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; @@ -52,7 +52,7 @@ impl<'tcx> ConstVal<'tcx> { #[derive(Clone, Debug)] pub struct ConstEvalErr<'tcx> { pub span: Span, - pub kind: Rc>, + pub kind: Lrc>, } #[derive(Clone, Debug)] diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 1caab6fd89ef9..e16a1082214f7 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -15,7 +15,7 @@ use std::iter::FromIterator; use traits::query::CanonicalTyGoal; use ty::{self, Ty, TyCtxt}; use ty::subst::Kind; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set @@ -182,13 +182,13 @@ impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> { impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> { // we ought to intern this, but I'm too lazy just now - type Canonicalized = Rc>>>; + type Canonicalized = Lrc>>>; fn intern( _gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical<'gcx, Self::Lifted>, ) -> Self::Canonicalized { - Rc::new(value) + Lrc::new(value) } } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 70c5cf5f39029..63f50cff4c2ad 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -17,7 +17,7 @@ use infer::at::At; use infer::canonical::{Canonical, Canonicalize, QueryResult}; use middle::const_val::ConstVal; use mir::interpret::GlobalId; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use traits::query::CanonicalProjectionGoal; use traits::project::Normalized; @@ -259,13 +259,13 @@ impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, ty::Pr impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, NormalizationResult<'tcx>> { // we ought to intern this, but I'm too lazy just now - type Canonicalized = Rc>>>; + type Canonicalized = Lrc>>>; fn intern( _gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical<'gcx, Self::Lifted>, ) -> Self::Canonicalized { - Rc::new(value) + Lrc::new(value) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index c9a69d5405c9a..3fc20508ad7ee 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -18,6 +18,7 @@ use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::sync::Lrc; use mir::interpret; use std::rc::Rc; @@ -465,7 +466,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { tcx.lift(&*self.kind).map(|kind| { ConstEvalErr { span: self.span, - kind: Rc::new(kind), + kind: Lrc::new(kind), } }) } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 82eb28287b033..50997089a5764 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -14,7 +14,7 @@ use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory}; use std::fmt; use std::error::Error; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -477,7 +477,7 @@ pub fn const_eval_provider<'a, 'tcx>( // Do match-check before building MIR if tcx.check_match(def_id).is_err() { return Err(ConstEvalErr { - kind: Rc::new(CheckMatchError), + kind: Lrc::new(CheckMatchError), span, }); } @@ -489,7 +489,7 @@ pub fn const_eval_provider<'a, 'tcx>( // Do not continue into miri if typeck errors occurred; it will fail horribly if tables.tainted_by_errors { return Err(ConstEvalErr { - kind: Rc::new(TypeckError), + kind: Lrc::new(TypeckError), span, }); } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 2a8cfe5cc06b3..1fe2f87128abd 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -16,14 +16,14 @@ use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResu use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; use rustc::ty::subst::Subst; use rustc::util::nodemap::FxHashSet; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; use syntax::codemap::{Span, DUMMY_SP}; use util; crate fn dropck_outlives<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: CanonicalTyGoal<'tcx>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", goal); tcx.infer_ctxt().enter(|ref infcx| { diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 55785d9586cc3..62d5ef11551c0 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -14,7 +14,7 @@ use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause, use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult}; use rustc::ty::{ParamEnvAnd, TyCtxt}; use rustc::util::common::CellUsizeExt; -use std::rc::Rc; +use rustc_data_structures::sync::Lrc; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::DUMMY_SP; use util; @@ -22,7 +22,7 @@ use util; crate fn normalize_projection_ty<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: CanonicalProjectionGoal<'tcx>, -) -> Result>>>, NoSolution> { +) -> Result>>>, NoSolution> { debug!("normalize_provider(goal={:#?})", goal); tcx.sess.perf_stats.normalize_projection_ty.increment(); From 910bf840cce1da57b96f7ac15f8b803675bb8a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 15 Mar 2018 10:09:20 +0100 Subject: [PATCH 04/48] Always print `aborting due to n previous error(s)` and only print it once for multi-threaded code --- src/librustc_driver/lib.rs | 54 +++++++++++++++++++--------------- src/librustc_errors/lib.rs | 34 +++++++++++---------- src/librustc_typeck/astconv.rs | 3 +- 3 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 5a1983bfec64f..2a15d57a262e1 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -63,6 +63,7 @@ use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::OnDrop; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::CompileIncomplete; use rustc::session::config::{Input, PrintRequest, ErrorOutputType}; @@ -515,30 +516,35 @@ fn run_compiler_impl<'a>(args: &[String], target_features::add_configuration(&mut cfg, &sess, &*trans); sess.parse_sess.config = cfg; - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); - - let cstore = CStore::new(trans.metadata_loader()); - - do_or_return!(callbacks.late_callback(&*trans, - &matches, - &sess, - &cstore, - &input, - &odir, - &ofile), Some(sess)); - - let control = callbacks.build_controller(&sess, &matches); - - (driver::compile_input(trans, - &sess, - &cstore, - &input_file_path, - &input, - &odir, - &ofile, - Some(plugins), - &control), - Some(sess)) + let result = { + let plugins = sess.opts.debugging_opts.extra_plugins.clone(); + + let cstore = CStore::new(trans.metadata_loader()); + + do_or_return!(callbacks.late_callback(&*trans, + &matches, + &sess, + &cstore, + &input, + &odir, + &ofile), Some(sess)); + + let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count()); + + let control = callbacks.build_controller(&sess, &matches); + + driver::compile_input(trans, + &sess, + &cstore, + &input_file_path, + &input, + &odir, + &ofile, + Some(plugins), + &control) + }; + + (result, Some(sess)) } // Extract output directory and file from matches. diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 7148969191f2b..b3265c21884be 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -555,21 +555,15 @@ impl Handler { pub fn has_errors(&self) -> bool { self.err_count() > 0 } - pub fn abort_if_errors(&self) { - let s; - match self.err_count() { - 0 => { - if let Some(bug) = self.delayed_span_bug.borrow_mut().take() { - DiagnosticBuilder::new_diagnostic(self, bug).emit(); - } - return; - } - 1 => s = "aborting due to previous error".to_string(), - _ => { - s = format!("aborting due to {} previous errors", self.err_count()); - } - } - let err = self.fatal(&s); + + pub fn print_error_count(&self) { + let s = match self.err_count() { + 0 => return, + 1 => "aborting due to previous error".to_string(), + _ => format!("aborting due to {} previous errors", self.err_count()) + }; + + let _ = self.fatal(&s); let can_show_explain = self.emitter.borrow().should_show_explain(); let are_there_diagnostics = !self.tracked_diagnostic_codes.borrow().is_empty(); @@ -600,8 +594,16 @@ impl Handler { } } } + } - err.raise(); + pub fn abort_if_errors(&self) { + if self.err_count() == 0 { + if let Some(bug) = self.delayed_span_bug.borrow_mut().take() { + DiagnosticBuilder::new_diagnostic(self, bug).emit(); + } + return; + } + FatalError.raise(); } pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.flags.can_emit_warnings { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 827ca79334cbe..bc69fbdb77837 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -27,6 +27,7 @@ use std::slice; use require_c_abi_if_variadic; use util::common::ErrorReported; use util::nodemap::FxHashSet; +use errors::FatalError; use std::iter; use syntax::{abi, ast}; @@ -337,7 +338,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::Trait(trait_def_id) => trait_def_id, Def::TraitAlias(alias_def_id) => alias_def_id, Def::Err => { - self.tcx().sess.fatal("cannot continue compilation due to previous error"); + FatalError.raise(); } _ => unreachable!(), } From b1d872b38eaacefbef73faa6a4a0c07622a8c941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 15 Mar 2018 16:13:47 +0100 Subject: [PATCH 05/48] Update tests --- src/test/ui-fulldeps/custom-derive/issue-36935.stderr | 2 ++ src/test/ui-fulldeps/proc-macro/load-panic.stderr | 2 ++ src/test/ui/codemap_tests/two_files.stderr | 3 ++- src/test/ui/cross-file-errors/main.stderr | 2 ++ src/test/ui/did_you_mean/recursion_limit_macro.stderr | 2 ++ src/test/ui/error-codes/E0404.stderr | 3 ++- src/test/ui/error-codes/E0405.stderr | 3 ++- src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr | 2 ++ src/test/ui/feature-gate-fn_must_use.stderr | 2 ++ .../feature-gate/issue-43106-gating-of-builtin-attrs.stderr | 2 ++ .../ui/feature-gate/issue-43106-gating-of-deprecated.stderr | 2 ++ src/test/ui/impl-trait/universal_wrong_bounds.stderr | 4 +++- src/test/ui/issue-22644.stderr | 2 ++ src/test/ui/issue-44406.stderr | 2 ++ src/test/ui/lint-output-format-2.stderr | 2 ++ src/test/ui/loops-reject-duplicate-labels-2.stderr | 2 ++ src/test/ui/loops-reject-duplicate-labels.stderr | 2 ++ src/test/ui/loops-reject-labels-shadowing-lifetimes.stderr | 2 ++ src/test/ui/loops-reject-lifetime-shadowing-label.stderr | 2 ++ src/test/ui/macro-context.stderr | 2 ++ src/test/ui/macros/macro_path_as_generic_bound.stderr | 3 ++- src/test/ui/macros/trace_faulty_macros.stderr | 2 ++ src/test/ui/raw_string.stderr | 2 ++ src/test/ui/resolve/issue-21221-1.stderr | 4 +++- src/test/ui/resolve/issue-21221-2.stderr | 3 ++- src/test/ui/resolve/issue-21221-3.stderr | 3 ++- src/test/ui/resolve/issue-21221-4.stderr | 3 ++- src/test/ui/resolve/issue-3907.stderr | 3 ++- src/test/ui/resolve/issue-5035.stderr | 4 +++- .../ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr | 4 +++- .../generic-associated-types-where.stderr | 2 -- src/test/ui/span/issue-24690.stderr | 2 ++ src/test/ui/span/issue-35987.stderr | 3 ++- 33 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/test/ui-fulldeps/custom-derive/issue-36935.stderr b/src/test/ui-fulldeps/custom-derive/issue-36935.stderr index b082999a8978d..0278256994120 100644 --- a/src/test/ui-fulldeps/custom-derive/issue-36935.stderr +++ b/src/test/ui-fulldeps/custom-derive/issue-36935.stderr @@ -6,3 +6,5 @@ LL | #[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked | = help: message: lolnope +error: aborting due to previous error + diff --git a/src/test/ui-fulldeps/proc-macro/load-panic.stderr b/src/test/ui-fulldeps/proc-macro/load-panic.stderr index edfd134469cda..30ad53f9041f0 100644 --- a/src/test/ui-fulldeps/proc-macro/load-panic.stderr +++ b/src/test/ui-fulldeps/proc-macro/load-panic.stderr @@ -6,3 +6,5 @@ LL | #[derive(A)] | = help: message: nope! +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index 614531c982128..e247e86fbcb22 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -4,5 +4,6 @@ error[E0404]: expected trait, found type alias `Bar` LL | impl Bar for Baz { } //~ ERROR expected trait, found type alias | ^^^ type aliases cannot be used for traits -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0404`. diff --git a/src/test/ui/cross-file-errors/main.stderr b/src/test/ui/cross-file-errors/main.stderr index a9db5214e6a2e..8fe795f7f1d8a 100644 --- a/src/test/ui/cross-file-errors/main.stderr +++ b/src/test/ui/cross-file-errors/main.stderr @@ -9,3 +9,5 @@ LL | _ LL | underscore!(); | -------------- in this macro invocation +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr index f6bce55528c7d..265a688df9910 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -9,3 +9,5 @@ LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0404.stderr b/src/test/ui/error-codes/E0404.stderr index 9f705da586167..afb748bedbe0f 100644 --- a/src/test/ui/error-codes/E0404.stderr +++ b/src/test/ui/error-codes/E0404.stderr @@ -10,5 +10,6 @@ error[E0404]: expected trait, found struct `Foo` LL | fn baz(_: T) {} //~ ERROR E0404 | ^^^ not a trait -error: cannot continue compilation due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0404`. diff --git a/src/test/ui/error-codes/E0405.stderr b/src/test/ui/error-codes/E0405.stderr index b5901dd9c848b..27190af1c6c11 100644 --- a/src/test/ui/error-codes/E0405.stderr +++ b/src/test/ui/error-codes/E0405.stderr @@ -4,5 +4,6 @@ error[E0405]: cannot find trait `SomeTrait` in this scope LL | impl SomeTrait for Foo {} //~ ERROR E0405 | ^^^^^^^^^ not found in this scope -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr index a9952ff4fac13..a2c1dedff385a 100644 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr +++ b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr @@ -4,3 +4,5 @@ error: compilation successful LL | fn main() {} //~ ERROR compilation successful | ^^^^^^^^^^^^ +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate-fn_must_use.stderr b/src/test/ui/feature-gate-fn_must_use.stderr index 4772cf28f6c12..431c57abd2653 100644 --- a/src/test/ui/feature-gate-fn_must_use.stderr +++ b/src/test/ui/feature-gate-fn_must_use.stderr @@ -20,3 +20,5 @@ error: compilation successful LL | fn main() {} //~ ERROR compilation successful | ^^^^^^^^^^^^ +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 9c4fb79f6f1aa..0beed62798710 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1316,3 +1316,5 @@ LL | | println!("Hello World"); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.stderr index 83f6e016370bb..802c5d9384d75 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-deprecated.stderr @@ -6,3 +6,5 @@ LL | | println!("Hello World"); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr index a02fc1f748faa..3cc0bebe81655 100644 --- a/src/test/ui/impl-trait/universal_wrong_bounds.stderr +++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr @@ -24,5 +24,7 @@ help: possible candidate is found in another module, you can import it into scop LL | use std::fmt::Debug; | -error: cannot continue compilation due to previous error +error: aborting due to 3 previous errors +Some errors occurred: E0405, E0425. +For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr index 257b9bd235d76..aeb465b2ab233 100644 --- a/src/test/ui/issue-22644.stderr +++ b/src/test/ui/issue-22644.stderr @@ -89,3 +89,5 @@ error: expected type, found `4` LL | println!("{}", a: &mut 4); //~ ERROR expected type, found `4` | ^ expecting a type here because of type ascription +error: aborting due to 9 previous errors + diff --git a/src/test/ui/issue-44406.stderr b/src/test/ui/issue-44406.stderr index 443b28cf09968..de7c11732e4a3 100644 --- a/src/test/ui/issue-44406.stderr +++ b/src/test/ui/issue-44406.stderr @@ -13,3 +13,5 @@ LL | bar(baz: $rest) LL | foo!(true); //~ ERROR expected type, found keyword | ^^^^ expecting a type here because of type ascription +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint-output-format-2.stderr b/src/test/ui/lint-output-format-2.stderr index b2d1e1ac05822..d484061ef9661 100644 --- a/src/test/ui/lint-output-format-2.stderr +++ b/src/test/ui/lint-output-format-2.stderr @@ -22,3 +22,5 @@ LL | | let _y = bar(); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/loops-reject-duplicate-labels-2.stderr b/src/test/ui/loops-reject-duplicate-labels-2.stderr index d35ed4ff88a67..830270a99d112 100644 --- a/src/test/ui/loops-reject-duplicate-labels-2.stderr +++ b/src/test/ui/loops-reject-duplicate-labels-2.stderr @@ -70,3 +70,5 @@ LL | | foo(); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/loops-reject-duplicate-labels.stderr b/src/test/ui/loops-reject-duplicate-labels.stderr index d1b874ea99729..a71f98b812a8c 100644 --- a/src/test/ui/loops-reject-duplicate-labels.stderr +++ b/src/test/ui/loops-reject-duplicate-labels.stderr @@ -73,3 +73,5 @@ LL | | foo(); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/loops-reject-labels-shadowing-lifetimes.stderr b/src/test/ui/loops-reject-labels-shadowing-lifetimes.stderr index 0cdd58fdbd75d..af524d5b01766 100644 --- a/src/test/ui/loops-reject-labels-shadowing-lifetimes.stderr +++ b/src/test/ui/loops-reject-labels-shadowing-lifetimes.stderr @@ -108,3 +108,5 @@ LL | | foo(); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/loops-reject-lifetime-shadowing-label.stderr b/src/test/ui/loops-reject-lifetime-shadowing-label.stderr index a050aec50c72b..999cfb9cc3c6b 100644 --- a/src/test/ui/loops-reject-lifetime-shadowing-label.stderr +++ b/src/test/ui/loops-reject-lifetime-shadowing-label.stderr @@ -14,3 +14,5 @@ LL | | foo(); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/macro-context.stderr b/src/test/ui/macro-context.stderr index 4dc6bbe4d656c..b3e67fb2607cd 100644 --- a/src/test/ui/macro-context.stderr +++ b/src/test/ui/macro-context.stderr @@ -43,3 +43,5 @@ LL | () => ( i ; typeof ); //~ ERROR expected expression, found reserved k LL | m!(); | ----- in this macro invocation +error: aborting due to 4 previous errors + diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 06d22714dd8b6..0f9f0607c5bf2 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -4,5 +4,6 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m` LL | foo!(m::m2::A); //~ ERROR failed to resolve | ^ Use of undeclared type or module `m` -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 9fb5b17a3114b..a9ffef8ef8090 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -45,3 +45,5 @@ LL | my_recursive_macro!(); = note: expanding `my_recursive_macro! { }` = note: to `my_recursive_macro ! ( ) ;` +error: aborting due to 2 previous errors + diff --git a/src/test/ui/raw_string.stderr b/src/test/ui/raw_string.stderr index b8aa596ef953a..ddf1cfe406f7c 100644 --- a/src/test/ui/raw_string.stderr +++ b/src/test/ui/raw_string.stderr @@ -6,3 +6,5 @@ LL | let x = r##"lol"#; | = note: this raw string should be terminated with `"##` +error: aborting due to previous error + diff --git a/src/test/ui/resolve/issue-21221-1.stderr b/src/test/ui/resolve/issue-21221-1.stderr index a9d2aeee2d151..3edfa33d80a02 100644 --- a/src/test/ui/resolve/issue-21221-1.stderr +++ b/src/test/ui/resolve/issue-21221-1.stderr @@ -45,5 +45,7 @@ help: possible candidate is found in another module, you can import it into scop LL | use std::ops::Div; | -error: cannot continue compilation due to previous error +error: aborting due to 4 previous errors +Some errors occurred: E0405, E0412. +For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/issue-21221-2.stderr b/src/test/ui/resolve/issue-21221-2.stderr index c61ffe3b33e8a..e11fe9ac4cf11 100644 --- a/src/test/ui/resolve/issue-21221-2.stderr +++ b/src/test/ui/resolve/issue-21221-2.stderr @@ -8,5 +8,6 @@ help: possible candidate is found in another module, you can import it into scop LL | use foo::bar::T; | -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/issue-21221-3.stderr b/src/test/ui/resolve/issue-21221-3.stderr index 7725f74cb49fc..f406cd6e35fcf 100644 --- a/src/test/ui/resolve/issue-21221-3.stderr +++ b/src/test/ui/resolve/issue-21221-3.stderr @@ -8,5 +8,6 @@ help: possible candidate is found in another module, you can import it into scop LL | use issue_21221_3::outer::OuterTrait; | -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/issue-21221-4.stderr b/src/test/ui/resolve/issue-21221-4.stderr index b0a4d5ba4d898..c0a7f1734f49c 100644 --- a/src/test/ui/resolve/issue-21221-4.stderr +++ b/src/test/ui/resolve/issue-21221-4.stderr @@ -8,5 +8,6 @@ help: possible candidate is found in another module, you can import it into scop LL | use issue_21221_4::T; | -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr index 2b8b2b20685f8..3627c09b28fd9 100644 --- a/src/test/ui/resolve/issue-3907.stderr +++ b/src/test/ui/resolve/issue-3907.stderr @@ -8,5 +8,6 @@ help: possible better candidate is found in another module, you can import it in LL | use issue_3907::Foo; | -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0404`. diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr index 6597f05889af8..353a0b1c3d9d0 100644 --- a/src/test/ui/resolve/issue-5035.stderr +++ b/src/test/ui/resolve/issue-5035.stderr @@ -13,5 +13,7 @@ LL | impl K for isize {} //~ ERROR expected trait, found type alias `K` | did you mean `I`? | type aliases cannot be used for traits -error: cannot continue compilation due to previous error +error: aborting due to 2 previous errors +Some errors occurred: E0404, E0432. +For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index 6e7bd28d16fc3..f32c5e9b2c6bd 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -10,5 +10,7 @@ error[E0404]: expected trait, found type alias `Typedef` LL | fn g isize>(x: F) {} | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used for traits -error: cannot continue compilation due to previous error +error: aborting due to 2 previous errors +Some errors occurred: E0404, E0405. +For more information about an error, try `rustc --explain E0404`. diff --git a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr index bb55d86f620b7..e69de29bb2d1d 100644 --- a/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/generic-associated-types-where.stderr @@ -1,2 +0,0 @@ -error: cannot continue compilation due to previous error - diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr index 6a4ec73b27a66..b496a1a76c017 100644 --- a/src/test/ui/span/issue-24690.stderr +++ b/src/test/ui/span/issue-24690.stderr @@ -36,3 +36,5 @@ LL | | println!("{}", theTwo); LL | | } | |_^ +error: aborting due to previous error + diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr index 2d4a7cc72f5f6..1dd45bb1e5efe 100644 --- a/src/test/ui/span/issue-35987.stderr +++ b/src/test/ui/span/issue-35987.stderr @@ -8,5 +8,6 @@ help: possible better candidate is found in another module, you can import it in LL | use std::ops::Add; | -error: cannot continue compilation due to previous error +error: aborting due to previous error +For more information about this error, try `rustc --explain E0404`. From 6fd4d67819a6eb8273768b6c3789ca70582cd703 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 16 Mar 2018 08:35:03 -0700 Subject: [PATCH 06/48] rustbuild: Tweak where timing information goes This commit tweaks where timing and step information is printed out as part of the build, ensuring that we do it as close to the location where work happens as possible. In rustbuild various functions may perform long blocking work as dependencies are assembled, so if we print out timing information early on we may accidentally time more than just the step we were intending to time! --- src/bootstrap/check.rs | 20 +++++++++------ src/bootstrap/compile.rs | 27 ++++++++++---------- src/bootstrap/test.rs | 55 ++++++++++++++++++++-------------------- src/bootstrap/tool.rs | 12 ++++----- 4 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 33bcfaa80ca31..a9dccea827b6e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -40,17 +40,18 @@ impl Step for Std { let target = self.target; let compiler = builder.compiler(0, build.build); - let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); - println!("Checking std artifacts ({} -> {})", &compiler.host, target); - let out_dir = build.stage_out(compiler, Mode::Libstd); build.clear_if_dirty(&out_dir, &builder.rustc(compiler)); let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check"); std_cargo(builder, &compiler, target, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); + println!("Checking std artifacts ({} -> {})", &compiler.host, target); run_cargo(build, &mut cargo, &libstd_stamp(build, compiler, target), true); + let libdir = builder.sysroot_libdir(compiler, target); add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target)); } @@ -86,19 +87,20 @@ impl Step for Rustc { let compiler = builder.compiler(0, build.build); let target = self.target; - let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); - println!("Checking compiler artifacts ({} -> {})", &compiler.host, target); - let stage_out = builder.stage_out(compiler, Mode::Librustc); build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target)); build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); rustc_cargo(build, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); + println!("Checking compiler artifacts ({} -> {})", &compiler.host, target); run_cargo(build, &mut cargo, &librustc_stamp(build, compiler, target), true); + let libdir = builder.sysroot_libdir(compiler, target); add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target)); } @@ -128,16 +130,18 @@ impl Step for Test { let target = self.target; let compiler = builder.compiler(0, build.build); - let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); - println!("Checking test artifacts ({} -> {})", &compiler.host, target); let out_dir = build.stage_out(compiler, Mode::Libtest); build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check"); test_cargo(build, &compiler, target, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); + println!("Checking test artifacts ({} -> {})", &compiler.host, target); run_cargo(build, &mut cargo, &libtest_stamp(build, compiler, target), true); + let libdir = builder.sysroot_libdir(compiler, target); add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target)); } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 86263c8fa0733..d697403180c18 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -93,10 +93,6 @@ impl Step for Std { return; } - let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); - println!("Building stage{} std artifacts ({} -> {})", compiler.stage, - &compiler.host, target); - if target.contains("musl") { let libdir = builder.sysroot_libdir(compiler, target); copy_musl_third_party_objects(build, target, &libdir); @@ -106,6 +102,10 @@ impl Step for Std { build.clear_if_dirty(&out_dir, &builder.rustc(compiler)); let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build"); std_cargo(builder, &compiler, target, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); + println!("Building stage{} std artifacts ({} -> {})", compiler.stage, + &compiler.host, target); run_cargo(build, &mut cargo, &libstd_stamp(build, compiler, target), @@ -360,13 +360,14 @@ impl Step for Test { return; } - let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); - println!("Building stage{} test artifacts ({} -> {})", compiler.stage, - &compiler.host, target); let out_dir = build.stage_out(compiler, Mode::Libtest); build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build"); test_cargo(build, &compiler, target, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); + println!("Building stage{} test artifacts ({} -> {})", compiler.stage, + &compiler.host, target); run_cargo(build, &mut cargo, &libtest_stamp(build, compiler, target), @@ -482,16 +483,16 @@ impl Step for Rustc { target: build.build, }); - let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); - println!("Building stage{} compiler artifacts ({} -> {})", - compiler.stage, &compiler.host, target); - let stage_out = builder.stage_out(compiler, Mode::Librustc); build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target)); build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); rustc_cargo(build, &mut cargo); + + let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); + println!("Building stage{} compiler artifacts ({} -> {})", + compiler.stage, &compiler.host, target); run_cargo(build, &mut cargo, &librustc_stamp(build, compiler, target), @@ -634,8 +635,6 @@ impl Step for CodegenBackend { .arg(build.src.join("src/librustc_trans/Cargo.toml")); rustc_cargo_env(build, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); - match &*self.backend { "llvm" | "emscripten" => { // Build LLVM for our target. This will implicitly build the @@ -685,6 +684,8 @@ impl Step for CodegenBackend { let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target) .join(".tmp.stamp"); + + let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); let files = run_cargo(build, cargo.arg("--features").arg(features), &tmp_stamp, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index de938ec8e8306..e129ae8c52105 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -530,8 +530,6 @@ impl Step for Tidy { fn run(self, builder: &Builder) { let build = builder.build; - let _folder = build.fold_output(|| "tidy"); - println!("tidy check"); let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(build.src.join("src")); cmd.arg(&build.initial_cargo); @@ -541,6 +539,9 @@ impl Step for Tidy { if build.config.quiet_tests { cmd.arg("--quiet"); } + + let _folder = build.fold_output(|| "tidy"); + println!("tidy check"); try_run(build, &mut cmd); } @@ -836,9 +837,6 @@ impl Step for Compiletest { builder.ensure(native::TestHelpers { target }); builder.ensure(RemoteCopyLibs { compiler, target }); - let _folder = build.fold_output(|| format!("test_{}", suite)); - println!("Check compiletest suite={} mode={} ({} -> {})", - suite, mode, &compiler.host, target); let mut cmd = builder.tool_cmd(Tool::Compiletest); // compiletest currently has... a lot of arguments, so let's just pass all @@ -998,6 +996,9 @@ impl Step for Compiletest { build.ci_env.force_coloring_in_ci(&mut cmd); + let _folder = build.fold_output(|| format!("test_{}", suite)); + println!("Check compiletest suite={} mode={} ({} -> {})", + suite, mode, &compiler.host, target); let _time = util::timeit(); try_run(build, &mut cmd); } @@ -1142,20 +1143,21 @@ impl Step for ErrorIndex { builder.ensure(compile::Std { compiler, target: compiler.host }); - let _folder = build.fold_output(|| "test_error_index"); - println!("Testing error-index stage{}", compiler.stage); - let dir = testdir(build, compiler.host); t!(fs::create_dir_all(&dir)); let output = dir.join("error-index.md"); - let _time = util::timeit(); - build.run(builder.tool_cmd(Tool::ErrorIndex) - .arg("markdown") - .arg(&output) - .env("CFG_BUILD", &build.build) - .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir())); + let mut tool = builder.tool_cmd(Tool::ErrorIndex); + tool.arg("markdown") + .arg(&output) + .env("CFG_BUILD", &build.build) + .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir()); + + let _folder = build.fold_output(|| "test_error_index"); + println!("Testing error-index stage{}", compiler.stage); + let _time = util::timeit(); + build.run(&mut tool); markdown_test(builder, compiler, &output); } } @@ -1400,11 +1402,6 @@ impl Step for Crate { } _ => panic!("can only test libraries"), }; - let _folder = build.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) - }); - println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, - &compiler.host, target); // Build up the base `cargo test` command. // @@ -1436,8 +1433,6 @@ impl Step for Crate { cargo.arg("--quiet"); } - let _time = util::timeit(); - if target.contains("emscripten") { cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), build.config.nodejs.as_ref().expect("nodejs not configured")); @@ -1465,6 +1460,13 @@ impl Step for Crate { format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display())); } + + let _folder = build.fold_output(|| { + format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) + }); + println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, + &compiler.host, target); + let _time = util::timeit(); try_run(build, &mut cargo); } } @@ -1513,12 +1515,6 @@ impl Step for CrateRustdoc { target, test_kind.subcommand(), "src/tools/rustdoc"); - let _folder = build.fold_output(|| { - format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) - }); - println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, - &compiler.host, target); - if test_kind.subcommand() == "test" && !build.fail_fast { cargo.arg("--no-fail-fast"); } @@ -1532,6 +1528,11 @@ impl Step for CrateRustdoc { cargo.arg("--quiet"); } + let _folder = build.fold_output(|| { + format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) + }); + println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, + &compiler.host, target); let _time = util::timeit(); try_run(build, &mut cargo); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 5f5b10a07b865..d308cecb27521 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -112,11 +112,11 @@ impl Step for ToolBuild { Mode::Tool => panic!("unexpected Mode::Tool for tool build") } - let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); - println!("Building stage{} tool {} ({})", compiler.stage, tool, target); - let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path); cargo.arg("--features").arg(self.extra_features.join(" ")); + + let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); + println!("Building stage{} tool {} ({})", compiler.stage, tool, target); let is_expected = build.try_run(&mut cargo); build.save_toolstate(tool, if is_expected { ToolState::TestFail @@ -339,9 +339,6 @@ impl Step for Rustdoc { builder.ensure(compile::Rustc { compiler: build_compiler, target }); - let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); - println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host); - let mut cargo = prepare_tool_cargo(builder, build_compiler, target, @@ -352,7 +349,10 @@ impl Step for Rustdoc { cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string()) .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string()); + let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); + println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host); build.run(&mut cargo); + // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" // rustdoc a different name. From b57ea5615921609815752c2d2133956b8a4fded6 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 17 Mar 2018 21:41:14 +0000 Subject: [PATCH 07/48] Stabilise FromUtf8Error::as_bytes Closes #40895. --- src/liballoc/string.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 9fec90914985d..e253122ffd6b6 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1576,7 +1576,6 @@ impl FromUtf8Error { /// Basic usage: /// /// ``` - /// #![feature(from_utf8_error_as_bytes)] /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; /// @@ -1584,7 +1583,7 @@ impl FromUtf8Error { /// /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); /// ``` - #[unstable(feature = "from_utf8_error_as_bytes", reason = "recently added", issue = "40895")] + #[stable(feature = "from_utf8_error_as_bytes", since = "1.26.0")] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] } From b4981923a05869ea2c50f1893acf433b1b67f79a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 17 Mar 2018 15:34:12 -0700 Subject: [PATCH 08/48] Add a -Z flag for LLVM align attributes on arguments LLVM seems to still put the assume calls in when inlining, so this probably isn't in a place where it can be turned on by default, but it's interesting to experiment with. For example, this makes `swap::` be 8x `vmovaps ymm` instead of 16x `vmovups xmm`, on my cpu. --- src/librustc/session/config.rs | 2 ++ src/librustc_trans/abi.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1c5cfa87ef46f..a5eae35c5567a 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1208,6 +1208,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the MIR optimization level (0-3, default: 1)"), mutable_noalias: bool = (false, parse_bool, [UNTRACKED], "emit noalias metadata for mutable references"), + arg_align_attributes: bool = (false, parse_bool, [UNTRACKED], + "emit align metadata for reference arguments"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], "dump MIR state at various points in translation"), dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED], diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index ee0f2415bd808..c8c9147766983 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -778,7 +778,7 @@ impl<'a, 'tcx> FnType<'tcx> { // HACK(eddyb) LLVM inserts `llvm.assume` calls when inlining functions // with align attributes, and those calls later block optimizations. - if !is_return { + if !is_return && !cx.tcx.sess.opts.debugging_opts.arg_align_attributes { attrs.pointee_align = None; } From efa9016390c6980983c58271436813215595bd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 17 Mar 2018 22:17:33 +0100 Subject: [PATCH 09/48] Add a CI job for parallel rustc using x.py check --- config.toml.example | 3 +++ src/bootstrap/configure.py | 1 + src/ci/docker/x86_64-gnu-debug/Dockerfile | 1 + src/ci/run.sh | 7 +++++++ 4 files changed, 12 insertions(+) diff --git a/config.toml.example b/config.toml.example index b47f9163c0dac..86ddefefb43bc 100644 --- a/config.toml.example +++ b/config.toml.example @@ -268,6 +268,9 @@ # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true +# Build rustc with experimental parallelization +#experimental-parallel-queries = false + # The default linker that will be hard-coded into the generated compiler for # targets that don't specify linker explicitly in their target specifications. # Note that this is not the linker used to link said compiler. diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 97da7cae07f7c..a5c373d5d5e77 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -44,6 +44,7 @@ def v(*args): o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") +o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization") o("test-miri", "rust.test-miri", "run miri's test suite") o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata") o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests") diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 95d41028595f8..ff6ab1013b4c2 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV PARALLEL_CHECK 1 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ diff --git a/src/ci/run.sh b/src/ci/run.sh index e3f38e4834a92..7fc2a963640b1 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -72,6 +72,13 @@ fi # sccache server at the start of the build, but no need to worry if this fails. SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true +if [ "$PARALLEL_CHECK" != "" ]; then + $SRC/configure --enable-experimental-parallel-queries + python2.7 ../x.py check + rm -f config.toml + rm -rf build +fi + travis_fold start configure travis_time_start $SRC/configure $RUST_CONFIGURE_ARGS From c5c650d670f5f191ea9667b455c15a607e550fdb Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 19 Mar 2018 00:26:41 -0500 Subject: [PATCH 10/48] Split out termination_trait_test feature gate --- src/libsyntax/feature_gate.rs | 3 +++ src/libsyntax/test.rs | 8 +++---- .../feature-gate-termination_trait_test.rs | 22 +++++++++++++++++++ .../termination-trait-in-test.rs | 2 +- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-termination_trait_test.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fa600cd686064..0950965233f6a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -432,6 +432,9 @@ declare_features! ( // Termination trait in main (RFC 1937) (active, termination_trait, "1.24.0", Some(43301), None), + // Termination trait in tests (RFC 1937) + (active, termination_trait_test, "1.24.0", Some(48854), None), + // Allows use of the :lifetime macro fragment specifier (active, macro_lifetime_matcher, "1.24.0", Some(46895), None), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 9edfa767d3195..d107ab59a9ad9 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -332,7 +332,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. - let output_matches = if cx.features.termination_trait { + let output_matches = if cx.features.termination_trait_test { true } else { let no_output = match decl.output { @@ -359,7 +359,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { match has_test_signature(cx, i) { Yes => true, No => { - if cx.features.termination_trait { + if cx.features.termination_trait_test { diag.span_err(i.span, "functions used as tests can not have any arguments"); } else { diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"); @@ -388,7 +388,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. - let output_matches = if cx.features.termination_trait { + let output_matches = if cx.features.termination_trait_test { true } else { let no_output = match decl.output { @@ -416,7 +416,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { if has_bench_attr && !has_bench_signature { let diag = cx.span_diagnostic; - if cx.features.termination_trait { + if cx.features.termination_trait_test { diag.span_err(i.span, "functions used as benches must have signature \ `fn(&mut Bencher) -> impl Termination`"); } else { diff --git a/src/test/compile-fail/feature-gate-termination_trait_test.rs b/src/test/compile-fail/feature-gate-termination_trait_test.rs new file mode 100644 index 0000000000000..4af7e94671627 --- /dev/null +++ b/src/test/compile-fail/feature-gate-termination_trait_test.rs @@ -0,0 +1,22 @@ +// 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. + +// compile-flags: --test + +fn main() {} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() -> Result<(), ()> { + //~^ ERROR functions used as tests must have signature fn() -> () + Ok(()) + } +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs index 494500d522abe..11997eb691728 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -10,7 +10,7 @@ // compile-flags: --test -#![feature(termination_trait)] +#![feature(termination_trait_test)] #![feature(test)] extern crate test; From 97b3bf99f667736c3220a91b72a587eafe4cda49 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 19 Mar 2018 01:31:04 -0500 Subject: [PATCH 11/48] Stabilize termination_trait This stabilizes `main` with non-() return types; see #48453. --- src/librustc_typeck/check/mod.rs | 35 +++++++++---------- src/librustc_typeck/lib.rs | 3 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 5 ++- .../termination-trait-main-i32.rs} | 3 +- .../termination-trait-main-wrong-type.rs | 1 - .../termination-trait-not-satisfied.rs | 2 -- .../termination-trait-for-never.rs | 2 -- ...mination-trait-for-result-box-error_err.rs | 2 -- .../termination-trait-for-empty.rs | 2 -- .../termination-trait-for-exitcode.rs | 1 - ...rmination-trait-for-result-box-error_ok.rs | 2 -- .../termination-trait-for-result.rs | 2 -- 13 files changed, 22 insertions(+), 40 deletions(-) rename src/test/compile-fail/{feature-gate-termination_trait.rs => rfc-1937-termination-trait/termination-trait-main-i32.rs} (82%) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4a685cfddb7a4..42bf516a0afa5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1106,25 +1106,22 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.features().termination_trait { - // If the termination trait language item is activated, check that the main return type - // implements the termination trait. - if let Some(term_id) = fcx.tcx.lang_items().termination() { - if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() { - if id == fn_id { - match fcx.sess().entry_type.get() { - Some(config::EntryMain) => { - let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); - let trait_ref = ty::TraitRef::new(term_id, substs); - let cause = traits::ObligationCause::new( - span, fn_id, ObligationCauseCode::MainFunctionType); - - inherited.register_predicate( - traits::Obligation::new( - cause, param_env, trait_ref.to_predicate())); - }, - _ => {}, - } + // Check that the main return type implements the termination trait. + if let Some(term_id) = fcx.tcx.lang_items().termination() { + if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() { + if id == fn_id { + match fcx.sess().entry_type.get() { + Some(config::EntryMain) => { + let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); + let trait_ref = ty::TraitRef::new(term_id, substs); + let cause = traits::ObligationCause::new( + span, fn_id, ObligationCauseCode::MainFunctionType); + + inherited.register_predicate( + traits::Obligation::new( + cause, param_env, trait_ref.to_predicate())); + }, + _ => {}, } } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 964c0021133aa..8089014044211 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -208,8 +208,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let actual = tcx.fn_sig(main_def_id); - let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.features().termination_trait { + let expected_return_type = if tcx.lang_items().termination().is_some() { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a159..33da0e5788653 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -308,7 +308,6 @@ #![feature(str_char)] #![feature(str_internals)] #![feature(str_utf16)] -#![feature(termination_trait)] #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] @@ -325,6 +324,7 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![cfg_attr(stage0, feature(never_type))] +#![cfg_attr(stage0, feature(termination_trait))] #![default_lib_allocator] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0950965233f6a..781071b7f7f07 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -429,9 +429,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660), None), - // Termination trait in main (RFC 1937) - (active, termination_trait, "1.24.0", Some(43301), None), - // Termination trait in tests (RFC 1937) (active, termination_trait_test, "1.24.0", Some(48854), None), @@ -558,6 +555,8 @@ declare_features! ( (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // allow `..=` in patterns (RFC 1192) (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + // Termination trait in main (RFC 1937) + (accepted, termination_trait, "1.26.0", Some(43301), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/feature-gate-termination_trait.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs similarity index 82% rename from src/test/compile-fail/feature-gate-termination_trait.rs rename to src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 5a56445b64e57..ff2b32f3fd93b 100644 --- a/src/test/compile-fail/feature-gate-termination_trait.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() -> i32 { //~ ERROR main function has wrong type [E0580] +fn main() -> i32 { +//~^ ERROR the trait bound `i32: std::process::Termination` is not satisfied [E0277] 0 } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 93e2561adf753..ea39ba92f4143 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] fn main() -> char { //~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index e87e0ceebf1b1..bab02fc559706 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - struct ReturnType {} fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs index c1dd44a91765e..863de85af88fb 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - // error-pattern:oh, dear fn main() -> ! { diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs index 8ce27c0a06250..0c6cb4de9567d 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs @@ -11,8 +11,6 @@ // must-compile-successfully // failure-status: 1 -#![feature(termination_trait)] - use std::io::{Error, ErrorKind}; fn main() -> Result<(), Box> { diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs index 5e534da012875..046d27a9f0fe5 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - fn main() {} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs index 80fa4d17b6116..4aa7d8c3a77d2 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] #![feature(process_exitcode_placeholder)] use std::process::ExitCode; diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs index 269ac451cf4d8..33686ed0b8fa2 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - use std::io::Error; fn main() -> Result<(), Box> { diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs index 751db0fb50082..1c87e31e763e9 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - use std::io::Error; fn main() -> Result<(), Error> { From e5a55e74405dedf8bc0744300a8c506eea94bc18 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 19 Mar 2018 01:59:51 -0500 Subject: [PATCH 12/48] Stabilize termination_trait in 1.25, not 1.26 --- src/libsyntax/feature_gate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 781071b7f7f07..e71726bcebdc9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -551,12 +551,12 @@ declare_features! ( (accepted, match_beginning_vert, "1.25.0", Some(44101), None), // Nested groups in `use` (RFC 2128) (accepted, use_nested_groups, "1.25.0", Some(44494), None), + // Termination trait in main (RFC 1937) + (accepted, termination_trait, "1.25.0", Some(43301), None), // a..=b and ..=b (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // allow `..=` in patterns (RFC 1192) (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Termination trait in main (RFC 1937) - (accepted, termination_trait, "1.26.0", Some(43301), None), ); // If you change this, please modify src/doc/unstable-book as well. You must From be29e52c5a3d9da894a0292f9175106a955071c9 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 00:02:17 -0500 Subject: [PATCH 13/48] Match against friendly error message --- .../rfc-1937-termination-trait/termination-trait-main-i32.rs | 2 +- .../termination-trait-main-wrong-type.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index ff2b32f3fd93b..67ee39d10d91c 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern:`main` can only return types that implement std::process::Termination, not `i32` fn main() -> i32 { -//~^ ERROR the trait bound `i32: std::process::Termination` is not satisfied [E0277] 0 } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index ea39ba92f4143..5f4ccf2b5862e 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern:`main` can only return types that implement std::process::Termination, not `char fn main() -> char { -//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied ' ' } From 5ccf3ffab24a4237e467b884af6783b1af54bdd8 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 00:06:46 -0500 Subject: [PATCH 14/48] diagnostics: Remove main return type errors from E0580 --- src/librustc/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index b3a904f2f5fec..7627071e56037 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1764,12 +1764,12 @@ The `main` function was incorrectly declared. Erroneous code example: ```compile_fail,E0580 -fn main() -> i32 { // error: main function has wrong type - 0 +fn main(x: i32) { // error: main function has wrong type + println!("{}", x); } ``` -The `main` function prototype should never take arguments or return type. +The `main` function prototype should never take arguments. Example: ``` From 72334fee6fad3c51a036d7f592915ea472959714 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 14:19:16 -0500 Subject: [PATCH 15/48] typeck: Report main return type errors on return type span --- src/librustc_typeck/check/mod.rs | 3 ++- .../termination-trait-main-wrong-type.rs | 3 +-- .../termination-trait-main-wrong-type.stderr | 11 +++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) rename src/test/{compile-fail => ui}/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs (80%) create mode 100644 src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 42bf516a0afa5..a951fa7eb220e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1114,8 +1114,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, Some(config::EntryMain) => { let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); let trait_ref = ty::TraitRef::new(term_id, substs); + let return_ty_span = decl.output.span(); let cause = traits::ObligationCause::new( - span, fn_id, ObligationCauseCode::MainFunctionType); + return_ty_span, fn_id, ObligationCauseCode::MainFunctionType); inherited.register_predicate( traits::Obligation::new( diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs similarity index 80% rename from src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs rename to src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 5f4ccf2b5862e..425f51ca2fb54 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:`main` can only return types that implement std::process::Termination, not `char -fn main() -> char { +fn main() -> char { //~ ERROR ' ' } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr new file mode 100644 index 0000000000000..d09aac3ac2f27 --- /dev/null +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `char: std::process::Termination` is not satisfied + --> $DIR/termination-trait-main-wrong-type.rs:11:14 + | +LL | fn main() -> char { //~ ERROR + | ^^^^ `main` can only return types that implement std::process::Termination, not `char` + | + = help: the trait `std::process::Termination` is not implemented for `char` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 57896abc38f56dce27ca9d4642c18f44be8db620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 20 Mar 2018 00:48:41 +0100 Subject: [PATCH 16/48] Make resuming generators unsafe instead of the creation of immovable generators. Fixes #47787 --- .../src/language-features/generators.md | 20 ++++++------- src/liballoc/boxed.rs | 2 +- src/libcore/ops/generator.rs | 12 +++++--- src/librustc_mir/diagnostics.rs | 10 +++---- src/librustc_mir/transform/check_unsafety.rs | 12 ++------ src/test/run-pass/dynamic-drop.rs | 2 +- .../run-pass/generator/conditional-drop.rs | 8 +++--- src/test/run-pass/generator/control-flow.rs | 2 +- src/test/run-pass/generator/drop-env.rs | 4 +-- src/test/run-pass/generator/issue-44197.rs | 6 ++-- src/test/run-pass/generator/iterator-count.rs | 4 ++- .../generator/live-upvar-across-yield.rs | 2 +- .../run-pass/generator/nested_generators.rs | 2 +- src/test/run-pass/generator/panic-drops.rs | 4 +-- src/test/run-pass/generator/panic-safe.rs | 4 +-- .../run-pass/generator/resume-after-return.rs | 4 +-- src/test/run-pass/generator/smoke.rs | 28 +++++++++---------- .../run-pass/generator/static-generators.rs | 18 ++++++------ .../run-pass/generator/xcrate-reachable.rs | 2 +- src/test/run-pass/generator/xcrate.rs | 6 ++-- src/test/ui/generator/borrowing.rs | 2 +- src/test/ui/generator/borrowing.stderr | 10 +++---- src/test/ui/generator/dropck.rs | 2 +- src/test/ui/generator/sized-yield.rs | 2 +- src/test/ui/generator/sized-yield.stderr | 6 ++-- src/test/ui/generator/unsafe-immovable.rs | 17 ----------- src/test/ui/generator/unsafe-immovable.stderr | 11 -------- .../ui/generator/yield-while-iterating.rs | 6 ++-- .../generator/yield-while-local-borrowed.rs | 6 ++-- .../generator/yield-while-ref-reborrowed.rs | 6 ++-- 30 files changed, 96 insertions(+), 124 deletions(-) delete mode 100644 src/test/ui/generator/unsafe-immovable.rs delete mode 100644 src/test/ui/generator/unsafe-immovable.stderr diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index e8e2132dca254..8e888de90a951 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -36,11 +36,11 @@ fn main() { return "foo" }; - match generator.resume() { + match unsafe { generator.resume() } { GeneratorState::Yielded(1) => {} _ => panic!("unexpected value from resume"), } - match generator.resume() { + match unsafe { generator.resume() } { GeneratorState::Complete("foo") => {} _ => panic!("unexpected value from resume"), } @@ -69,9 +69,9 @@ fn main() { }; println!("1"); - generator.resume(); + unsafe { generator.resume() }; println!("3"); - generator.resume(); + unsafe { generator.resume() }; println!("5"); } ``` @@ -92,7 +92,7 @@ The `Generator` trait in `std::ops` currently looks like: pub trait Generator { type Yield; type Return; - fn resume(&mut self) -> GeneratorState; + unsafe fn resume(&mut self) -> GeneratorState; } ``` @@ -175,8 +175,8 @@ fn main() { return ret }; - generator.resume(); - generator.resume(); + unsafe { generator.resume() }; + unsafe { generator.resume() }; } ``` @@ -200,7 +200,7 @@ fn main() { type Yield = i32; type Return = &'static str; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { use std::mem; match mem::replace(self, __Generator::Done) { __Generator::Start(s) => { @@ -223,8 +223,8 @@ fn main() { __Generator::Start(ret) }; - generator.resume(); - generator.resume(); + unsafe { generator.resume() }; + unsafe { generator.resume() }; } ``` diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index b776556d59f11..a86ab87ec185f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -892,7 +892,7 @@ impl Generator for Box { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index dc7669d195c13..4b70c5398be4f 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -56,11 +56,11 @@ pub enum GeneratorState { /// return "foo" /// }; /// -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } -/// match generator.resume() { +/// match unsafe { generator.resume() } { /// GeneratorState::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } @@ -98,6 +98,10 @@ pub trait Generator { /// generator will continue executing until it either yields or returns, at /// which point this function will return. /// + /// The function is unsafe because it can be used on an immovable generator. + /// After such a call, the immovable generator must not move again, but + /// this is not enforced by the compiler. + /// /// # Return value /// /// The `GeneratorState` enum returned from this function indicates what @@ -116,7 +120,7 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume(&mut self) -> GeneratorState; + unsafe fn resume(&mut self) -> GeneratorState; } #[unstable(feature = "generator_trait", issue = "43122")] @@ -125,7 +129,7 @@ impl<'a, T> Generator for &'a mut T { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> GeneratorState { + unsafe fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 2000ebea25d7e..4f36c3888b961 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2247,7 +2247,7 @@ let mut b = || { yield (); // ...is still in scope here, when the yield occurs. println!("{}", a); }; -b.resume(); +unsafe { b.resume() }; ``` At present, it is not permitted to have a yield that occurs while a @@ -2265,7 +2265,7 @@ let mut b = || { yield (); println!("{}", a); }; -b.resume(); +unsafe { b.resume() }; ``` This is a very simple case, of course. In more complex cases, we may @@ -2283,7 +2283,7 @@ let mut b = || { yield x; // ...when this yield occurs. } }; -b.resume(); +unsafe { b.resume() }; ``` Such cases can sometimes be resolved by iterating "by value" (or using @@ -2298,7 +2298,7 @@ let mut b = || { yield x; // <-- Now yield is OK. } }; -b.resume(); +unsafe { b.resume() }; ``` If taking ownership is not an option, using indices can work too: @@ -2314,7 +2314,7 @@ let mut b = || { yield x; // <-- Now yield is OK. } }; -b.resume(); +unsafe { b.resume() }; // (*) -- Unfortunately, these temporaries are currently required. // See . diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 86d08dec2b9c3..033fb493d735c 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -125,21 +125,13 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { &AggregateKind::Array(..) | &AggregateKind::Tuple | &AggregateKind::Adt(..) => {} - &AggregateKind::Closure(def_id, _) => { + &AggregateKind::Closure(def_id, _) | + &AggregateKind::Generator(def_id, _, _) => { let UnsafetyCheckResult { violations, unsafe_blocks } = self.tcx.unsafety_check_result(def_id); self.register_violations(&violations, &unsafe_blocks); } - &AggregateKind::Generator(def_id, _, interior) => { - let UnsafetyCheckResult { - violations, unsafe_blocks - } = self.tcx.unsafety_check_result(def_id); - self.register_violations(&violations, &unsafe_blocks); - if !interior.movable { - self.require_unsafe("construction of immovable generator") - } - } } } self.super_rvalue(rvalue, location); diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 4d0bd3f3412f1..abbce16b77cf6 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -178,7 +178,7 @@ fn generator(a: &Allocator, run_count: usize) { ); }; for _ in 0..run_count { - gen.resume(); + unsafe { gen.resume(); } } } diff --git a/src/test/run-pass/generator/conditional-drop.rs b/src/test/run-pass/generator/conditional-drop.rs index 8329684e1a39b..3d39c46186be3 100644 --- a/src/test/run-pass/generator/conditional-drop.rs +++ b/src/test/run-pass/generator/conditional-drop.rs @@ -42,9 +42,9 @@ fn t1() { }; let n = A.load(Ordering::SeqCst); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); } @@ -58,8 +58,8 @@ fn t2() { }; let n = A.load(Ordering::SeqCst); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n); - a.resume(); + unsafe { a.resume() }; assert_eq!(A.load(Ordering::SeqCst), n + 1); } diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs index 60a00b4e46756..09971410e556d 100644 --- a/src/test/run-pass/generator/control-flow.rs +++ b/src/test/run-pass/generator/control-flow.rs @@ -16,7 +16,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { loop { - match t.resume() { + match unsafe { t.resume() } { GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), GeneratorState::Complete(ret) => { assert_eq!(amt, 0); diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index ac42a25899dbb..ef4dc24472e61 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -37,7 +37,7 @@ fn t1() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume()); + drop(unsafe { foo.resume() }); assert_eq!(A.load(Ordering::SeqCst), n); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); @@ -50,7 +50,7 @@ fn t2() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume()); + drop(unsafe { foo.resume() }); assert_eq!(A.load(Ordering::SeqCst), n + 1); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); diff --git a/src/test/run-pass/generator/issue-44197.rs b/src/test/run-pass/generator/issue-44197.rs index 7cb80ea8b21b7..8ce4fc6affab3 100644 --- a/src/test/run-pass/generator/issue-44197.rs +++ b/src/test/run-pass/generator/issue-44197.rs @@ -35,6 +35,8 @@ fn bar2(baz: String) -> impl Generator { } fn main() { - assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new())); - assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(())); + unsafe { + assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new())); + assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(())); + } } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 9afe95f9e865c..654b18928c077 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -14,11 +14,13 @@ use std::ops::{GeneratorState, Generator}; struct W(T); +// This impl isn't safe in general, but the generator used in this test is movable +// so it won't cause problems. impl> Iterator for W { type Item = T::Yield; fn next(&mut self) -> Option { - match self.0.resume() { + match unsafe { self.0.resume() } { GeneratorState::Complete(..) => None, GeneratorState::Yielded(v) => Some(v), } diff --git a/src/test/run-pass/generator/live-upvar-across-yield.rs b/src/test/run-pass/generator/live-upvar-across-yield.rs index e34b0b3100c32..28e7da232ce09 100644 --- a/src/test/run-pass/generator/live-upvar-across-yield.rs +++ b/src/test/run-pass/generator/live-upvar-across-yield.rs @@ -17,5 +17,5 @@ fn main() { let mut a = || { b(yield); }; - a.resume(); + unsafe { a.resume() }; } diff --git a/src/test/run-pass/generator/nested_generators.rs b/src/test/run-pass/generator/nested_generators.rs index f70d4144a3c9e..29808da85a7a9 100644 --- a/src/test/run-pass/generator/nested_generators.rs +++ b/src/test/run-pass/generator/nested_generators.rs @@ -20,7 +20,7 @@ fn main() { yield 2; }; - match sub_generator.resume() { + match unsafe { sub_generator.resume() } { GeneratorState::Yielded(x) => { yield x; } diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 36e401a54bcdd..3d7b60ab6b901 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -42,7 +42,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 0); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); @@ -57,7 +57,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 1); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs index 0d5bae7876bd3..ace5cdde51d85 100644 --- a/src/test/run-pass/generator/panic-safe.rs +++ b/src/test/run-pass/generator/panic-safe.rs @@ -24,13 +24,13 @@ fn main() { }; let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); for _ in 0..10 { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume() + unsafe { foo.resume() } })); assert!(res.is_err()); } diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index 56511dcd53a6a..06e7615d26191 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -23,12 +23,12 @@ fn main() { yield; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } - match panic::catch_unwind(move || foo.resume()) { + match panic::catch_unwind(move || unsafe { foo.resume() }) { Ok(_) => panic!("generator successfully resumed"), Err(_) => {} } diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index 8693964665d34..7395c8484c169 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -24,7 +24,7 @@ fn simple() { } }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -40,7 +40,7 @@ fn return_capture() { a }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -52,11 +52,11 @@ fn simple_yield() { yield; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -69,11 +69,11 @@ fn yield_capture() { yield b; }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -86,11 +86,11 @@ fn simple_yield_value() { return String::from("foo") }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "bar" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -104,11 +104,11 @@ fn return_after_yield() { return a }; - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -156,11 +156,11 @@ fn send_and_sync() { fn send_over_threads() { let mut foo = || { yield }; thread::spawn(move || { - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -169,11 +169,11 @@ fn send_over_threads() { let a = String::from("a"); let mut foo = || { yield a }; thread::spawn(move || { - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(ref s) if *s == "a" => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } diff --git a/src/test/run-pass/generator/static-generators.rs b/src/test/run-pass/generator/static-generators.rs index 9504414d8b6f5..ebc070eee09c1 100644 --- a/src/test/run-pass/generator/static-generators.rs +++ b/src/test/run-pass/generator/static-generators.rs @@ -13,14 +13,14 @@ use std::ops::{Generator, GeneratorState}; fn main() { - let mut generator = unsafe { - static || { - let a = true; - let b = &a; - yield; - assert_eq!(b as *const _, &a as *const _); - } + let mut generator = static || { + let a = true; + let b = &a; + yield; + assert_eq!(b as *const _, &a as *const _); }; - assert_eq!(generator.resume(), GeneratorState::Yielded(())); - assert_eq!(generator.resume(), GeneratorState::Complete(())); + unsafe { + assert_eq!(generator.resume(), GeneratorState::Yielded(())); + assert_eq!(generator.resume(), GeneratorState::Complete(())); + } } diff --git a/src/test/run-pass/generator/xcrate-reachable.rs b/src/test/run-pass/generator/xcrate-reachable.rs index dff5e08b9c20e..8eeb013314499 100644 --- a/src/test/run-pass/generator/xcrate-reachable.rs +++ b/src/test/run-pass/generator/xcrate-reachable.rs @@ -17,5 +17,5 @@ extern crate xcrate_reachable as foo; use std::ops::Generator; fn main() { - foo::foo().resume(); + unsafe { foo::foo().resume(); } } diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs index dc7a6fdef9c7e..04791d5135677 100644 --- a/src/test/run-pass/generator/xcrate.rs +++ b/src/test/run-pass/generator/xcrate.rs @@ -19,18 +19,18 @@ use std::ops::{GeneratorState, Generator}; fn main() { let mut foo = xcrate::foo(); - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } let mut foo = xcrate::bar(3); - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Yielded(3) => {} s => panic!("bad state: {:?}", s), } - match foo.resume() { + match unsafe { foo.resume() } { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index de10bdef4aee0..e56927d818231 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -15,7 +15,7 @@ use std::ops::Generator; fn main() { let _b = { let a = 3; - (|| yield &a).resume() + unsafe { (|| yield &a).resume() } //~^ ERROR: `a` does not live long enough }; diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr index 2a5de3790ada9..45d950b5aef64 100644 --- a/src/test/ui/generator/borrowing.stderr +++ b/src/test/ui/generator/borrowing.stderr @@ -1,10 +1,10 @@ error[E0597]: `a` does not live long enough - --> $DIR/borrowing.rs:18:20 + --> $DIR/borrowing.rs:18:29 | -LL | (|| yield &a).resume() - | -- ^ borrowed value does not live long enough - | | - | capture occurs here +LL | unsafe { (|| yield &a).resume() } + | -- ^ borrowed value does not live long enough + | | + | capture occurs here LL | //~^ ERROR: `a` does not live long enough LL | }; | - borrowed value only lives until here diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs index 0b143d7f5143e..b2240fb225f58 100644 --- a/src/test/ui/generator/dropck.rs +++ b/src/test/ui/generator/dropck.rs @@ -23,6 +23,6 @@ fn main() { let _d = ref_.take(); //~ ERROR `ref_` does not live long enough yield; }; - gen.resume(); + unsafe { gen.resume(); } // drops the RefCell and then the Ref, leading to use-after-free } diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index f38ebf8b94636..a1c8ca77e41e8 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -17,5 +17,5 @@ fn main() { let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied yield s[..]; }; - gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index fc99c7e3bd747..957fac172c258 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -11,10 +11,10 @@ LL | | }; = note: the yield type of a generator must have a statically known size error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/sized-yield.rs:20:8 + --> $DIR/sized-yield.rs:20:17 | -LL | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied - | ^^^^^^ `str` does not have a constant size known at compile-time +LL | unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/generator/unsafe-immovable.rs b/src/test/ui/generator/unsafe-immovable.rs deleted file mode 100644 index 45acbf50931bc..0000000000000 --- a/src/test/ui/generator/unsafe-immovable.rs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -#![feature(generators)] - -fn main() { - static || { //~ ERROR: construction of immovable generator requires unsafe - yield; - }; -} diff --git a/src/test/ui/generator/unsafe-immovable.stderr b/src/test/ui/generator/unsafe-immovable.stderr deleted file mode 100644 index b2add55613d54..0000000000000 --- a/src/test/ui/generator/unsafe-immovable.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0133]: construction of immovable generator requires unsafe function or block - --> $DIR/unsafe-immovable.rs:14:5 - | -LL | / static || { //~ ERROR: construction of immovable generator requires unsafe -LL | | yield; -LL | | }; - | |_____^ construction of immovable generator - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/generator/yield-while-iterating.rs b/src/test/ui/generator/yield-while-iterating.rs index bc53448cb08e6..b8a67a0e7b65d 100644 --- a/src/test/ui/generator/yield-while-iterating.rs +++ b/src/test/ui/generator/yield-while-iterating.rs @@ -43,7 +43,7 @@ fn yield_during_iter_borrowed_slice_2() { println!("{:?}", x); } -fn yield_during_iter_borrowed_slice_3() { +unsafe fn yield_during_iter_borrowed_slice_3() { // OK to take a mutable ref to `x` and yield // up pointers from it: let mut x = vec![22_i32]; @@ -55,7 +55,7 @@ fn yield_during_iter_borrowed_slice_3() { b.resume(); } -fn yield_during_iter_borrowed_slice_4() { +unsafe fn yield_during_iter_borrowed_slice_4() { // ...but not OK to do that while reading // from `x` too let mut x = vec![22_i32]; @@ -68,7 +68,7 @@ fn yield_during_iter_borrowed_slice_4() { b.resume(); } -fn yield_during_range_iter() { +unsafe fn yield_during_range_iter() { // Should be OK. let mut b = || { let v = vec![1,2,3]; diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs index 11bd4ed05caca..3dc2650a2ecbf 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.rs +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -15,7 +15,7 @@ use std::ops::{GeneratorState, Generator}; use std::cell::Cell; -fn borrow_local_inline() { +unsafe fn borrow_local_inline() { // Not OK to yield with a borrow of a temporary. // // (This error occurs because the region shows up in the type of @@ -30,7 +30,7 @@ fn borrow_local_inline() { b.resume(); } -fn borrow_local_inline_done() { +unsafe fn borrow_local_inline_done() { // No error here -- `a` is not in scope at the point of `yield`. let mut b = move || { { @@ -41,7 +41,7 @@ fn borrow_local_inline_done() { b.resume(); } -fn borrow_local() { +unsafe fn borrow_local() { // Not OK to yield with a borrow of a temporary. // // (This error occurs because the region shows up in the type of diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs index b9c963ae74077..573dd4377bb2c 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.rs +++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs @@ -13,7 +13,7 @@ use std::ops::{GeneratorState, Generator}; use std::cell::Cell; -fn reborrow_shared_ref(x: &i32) { +unsafe fn reborrow_shared_ref(x: &i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the generator. let mut b = move || { @@ -24,7 +24,7 @@ fn reborrow_shared_ref(x: &i32) { b.resume(); } -fn reborrow_mutable_ref(x: &mut i32) { +unsafe fn reborrow_mutable_ref(x: &mut i32) { // This is OK -- we have a borrow live over the yield, but it's of // data that outlives the generator. let mut b = move || { @@ -35,7 +35,7 @@ fn reborrow_mutable_ref(x: &mut i32) { b.resume(); } -fn reborrow_mutable_ref_2(x: &mut i32) { +unsafe fn reborrow_mutable_ref_2(x: &mut i32) { // ...but not OK to go on using `x`. let mut b = || { let a = &mut *x; From 1937661961fa54aa2bce8c301d85536916224a74 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 22:45:35 -0500 Subject: [PATCH 17/48] Revert "Stabilize termination_trait in 1.25, not 1.26" This reverts commit e5a55e74405dedf8bc0744300a8c506eea94bc18. --- src/libsyntax/feature_gate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e71726bcebdc9..781071b7f7f07 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -551,12 +551,12 @@ declare_features! ( (accepted, match_beginning_vert, "1.25.0", Some(44101), None), // Nested groups in `use` (RFC 2128) (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Termination trait in main (RFC 1937) - (accepted, termination_trait, "1.25.0", Some(43301), None), // a..=b and ..=b (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // allow `..=` in patterns (RFC 1192) (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + // Termination trait in main (RFC 1937) + (accepted, termination_trait, "1.26.0", Some(43301), None), ); // If you change this, please modify src/doc/unstable-book as well. You must From 94bdeb64f96b266d990ba7b76cd78a1e2ed1977f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 23:01:42 -0500 Subject: [PATCH 18/48] termination_trait: Add () example to error message --- src/libstd/process.rs | 2 +- .../rfc-1937-termination-trait/termination-trait-main-i32.rs | 2 +- .../termination-trait-main-wrong-type.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d5ac2d19e831f..a6aa3502f26bb 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1443,7 +1443,7 @@ pub fn id() -> u32 { #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] + "`main` can only return types like `()` that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 67ee39d10d91c..ffff33da581bf 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:`main` can only return types that implement std::process::Termination, not `i32` +// error-pattern:`main` can only return types like `()` that implement std::process::Termination, no fn main() -> i32 { 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index d09aac3ac2f27..24371c27742d2 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `char: std::process::Termination` is not satisfied --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types like `()` that implement std::process::Termination, not `char` | = help: the trait `std::process::Termination` is not implemented for `char` From 2cdc7af41366182259a05435e325d7444653a3e8 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 21 Mar 2018 00:24:06 -0500 Subject: [PATCH 19/48] Use NOTE instead of error-pattern directive --- .../rfc-1937-termination-trait/termination-trait-main-i32.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index ffff33da581bf..053d6bbf93a2d 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:`main` can only return types like `()` that implement std::process::Termination, no fn main() -> i32 { +//~^ ERROR `i32: std::process::Termination` is not satisfied +//~| NOTE `main` can only return types like `()` that implement std::process::Termination, not `i32` 0 } From 5201e7cf8ac0c78bc8e4f0feb8f97e91b957a19e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 21 Mar 2018 07:31:39 +0100 Subject: [PATCH 20/48] document format_args! behavior wrt. Display and Debug --- src/libcore/fmt/mod.rs | 72 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3ecd73873c091..0363714c31b5c 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -406,6 +406,18 @@ impl<'a> Arguments<'a> { /// macro validates the format string at compile-time so usage of the [`write`] /// and [`format`] functions can be safely performed. /// +/// You can use the `Arguments<'a>` that [`format_args!`] returns in `Debug` +/// and `Display` contexts as seen below. The example also shows that `Debug` +/// and `Display` format to the same thing: the interpolated format string +/// in `format_args!`. +/// +/// ```rust +/// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); +/// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); +/// assert_eq!("1 foo 2", display); +/// assert_eq!(display, debug); +/// ``` +/// /// [`format_args!`]: ../../std/macro.format_args.html /// [`format`]: ../../std/fmt/fn.format.html /// [`write`]: ../../std/fmt/fn.write.html @@ -1553,10 +1565,12 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::net::Ipv4Addr; /// /// struct Foo { /// bar: i32, /// baz: String, + /// addr: Ipv4Addr, /// } /// /// impl fmt::Debug for Foo { @@ -1564,12 +1578,19 @@ impl<'a> Formatter<'a> { /// fmt.debug_struct("Foo") /// .field("bar", &self.bar) /// .field("baz", &self.baz) + /// .field("addr", &format_args!("{}", self.addr)) /// .finish() /// } /// } /// - /// // prints "Foo { bar: 10, baz: "Hello World" }" - /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); + /// assert_eq!( + /// "Foo { bar: 10, baz: \"Hello World\", addr: 127.0.0.1 }", + /// format!("{:?}", Foo { + /// bar: 10, + /// baz: "Hello World".to_string(), + /// addr: Ipv4Addr::new(127, 0, 0, 1), + /// }) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { @@ -1583,20 +1604,24 @@ impl<'a> Formatter<'a> { /// /// ```rust /// use std::fmt; + /// use std::marker::PhantomData; /// - /// struct Foo(i32, String); + /// struct Foo(i32, String, PhantomData); /// - /// impl fmt::Debug for Foo { + /// impl fmt::Debug for Foo { /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { /// fmt.debug_tuple("Foo") /// .field(&self.0) /// .field(&self.1) + /// .field(&format_args!("_")) /// .finish() /// } /// } /// - /// // prints "Foo(10, "Hello World")" - /// println!("{:?}", Foo(10, "Hello World".to_string())); + /// assert_eq!( + /// "Foo(10, \"Hello\", _)", + /// format!("{:?}", Foo(10, "Hello".to_string(), PhantomData::)) + /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> { @@ -1646,6 +1671,41 @@ impl<'a> Formatter<'a> { /// // prints "{10, 11}" /// println!("{:?}", Foo(vec![10, 11])); /// ``` + /// + /// [`format_args!`]: ../../std/macro.format_args.html + /// + /// In this more complex example, we use [`format_args!`] and `.debug_set()` + /// to build a list of match arms: + /// + /// ```rust + /// use std::fmt; + /// + /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R)); + /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V); + /// + /// impl<'a, L, R> fmt::Debug for Arm<'a, L, R> + /// where + /// L: 'a + fmt::Debug, R: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// L::fmt(&(self.0).0, fmt)?; + /// fmt.write_str(" => ")?; + /// R::fmt(&(self.0).1, fmt) + /// } + /// } + /// + /// impl<'a, K, V> fmt::Debug for Table<'a, K, V> + /// where + /// K: 'a + fmt::Debug, V: 'a + fmt::Debug + /// { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// fmt.debug_set() + /// .entries(self.0.iter().map(Arm)) + /// .entry(&Arm(&(format_args!("_"), &self.1))) + /// .finish() + /// } + /// } + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> { builders::debug_set_new(self) From afff64e7a4c88b39402c95f1368c880b17cdf793 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 21 Mar 2018 07:55:09 +0100 Subject: [PATCH 21/48] document format_args! further wrt. Debug & Display" --- src/libstd/macros.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 000f971361530..47609f17221ef 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -335,6 +335,18 @@ pub mod builtin { /// proxied through this one. `format_args!`, unlike its derived macros, avoids /// heap allocations. /// + /// You can use the [`fmt::Arguments`] value that `format_args!` returns + /// in `Debug` and `Display` contexts as seen below. The example also shows + /// that `Debug` and `Display` format to the same thing: the interpolated + /// format string in `format_args!`. + /// + /// ```rust + /// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); + /// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); + /// assert_eq!("1 foo 2", display); + /// assert_eq!(display, debug); + /// ``` + /// /// For more information, see the documentation in [`std::fmt`]. /// /// [`Display`]: ../std/fmt/trait.Display.html From 06f81032955e4dd92cb6be3d67f9a56c375c7313 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Wed, 21 Mar 2018 03:04:09 +0100 Subject: [PATCH 22/48] Bump racer and home This removes 10 dependencies from the build :tada: --- src/Cargo.lock | 114 ++++++------------------------------------------- 1 file changed, 12 insertions(+), 102 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 675457905eade..b452e83870a2c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1,20 +1,3 @@ -[[package]] -name = "advapi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aho-corasick" version = "0.6.4" @@ -199,7 +182,7 @@ dependencies = [ "git2-curl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "home 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -567,15 +550,6 @@ dependencies = [ "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "env_logger" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" version = "0.5.5" @@ -774,14 +748,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "home" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1053,14 +1025,6 @@ dependencies = [ "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.0.1" @@ -1319,13 +1283,13 @@ dependencies = [ [[package]] name = "racer" -version = "2.0.12" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1392,18 +1356,6 @@ version = "0.1.0" name = "reformat_with_range" version = "0.1.0" -[[package]] -name = "regex" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "0.2.7" @@ -1416,11 +1368,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.5.0" @@ -1461,7 +1408,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1525,7 +1472,7 @@ name = "rls-vfs" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2094,11 +2041,6 @@ name = "scoped-tls" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "scopeguard" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" @@ -2416,23 +2358,6 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.5" @@ -2583,11 +2508,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "utf8-ranges" version = "1.0.0" @@ -2680,8 +2600,6 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" @@ -2720,7 +2638,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0628f04f7c26ebccf40d7fc2c1cf92236c05ec88cf2132641cc956812312f0f" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" @@ -2741,7 +2658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96ab92362c06811385ae9a34d2698e8a1160745e0c78fbb434a44c8de3fabc" "checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" "checksum hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "459d3cf58137bb02ad4adeef5036377ff59f066dbb82517b7192e3a5462a2abc" -"checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db" +"checksum home 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f94f6fbdc000a6eba0c8cf08632b2091bb59141d36ac321a2a96d6365e5e4dc" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" @@ -2767,7 +2684,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lzma-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c1b93b78f89e8737dac81837fc8f5521ac162abcba902e1a3db949d55346d1da" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fef236caad7ba3b5b3944df946f19ab3e190bca53c111dd00fe05fa8d879f2fd" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" @@ -2796,16 +2712,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" -"checksum racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "034f1c4528581c40a60e96875467c03315868084e08ff4ceb46a00f7be3b16b4" +"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d" "checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a62bf8bb734ab90b7f234b681b01af396e5d39b028906c210dc04fa1d5e9e5b3" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48d7391e7e90e06eaf3aefbe4652464153ecfec64806f3bf77ffc59638a63e77" "checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" "checksum rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4b9a3a3f2345854e39768e6425d1c893855da217183d1c0b3ff6f1664b6b6d" @@ -2825,7 +2739,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fbaffce35eb61c5b00846e73128b0cd62717e7c0ec46abbec132370d013975b4" "checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" -"checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -2854,8 +2767,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "56c456352e44f9f91f774ddeeed27c1ec60a2455ed66d692059acfb1d731bda1" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" @@ -2873,7 +2784,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" From 75dcc61d3c1cce7b4428dd85bb588e99d9faf7a9 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Wed, 21 Mar 2018 23:12:24 +0900 Subject: [PATCH 23/48] Cargo fmt libtest --- src/libtest/formatters/json.rs | 49 ++--- src/libtest/formatters/pretty.rs | 9 +- src/libtest/formatters/terse.rs | 9 +- src/libtest/lib.rs | 325 ++++++++++++++----------------- src/libtest/stats.rs | 23 ++- 5 files changed, 182 insertions(+), 233 deletions(-) diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs index d323d50f702ba..89235d897bde6 100644 --- a/src/libtest/formatters/json.rs +++ b/src/libtest/formatters/json.rs @@ -36,17 +36,12 @@ impl JsonFormatter { if let Some(extras) = extra { self.write_message(&*format!( r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, - ty, - name, - evt, - extras + ty, name, evt, extras )) } else { self.write_message(&*format!( r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, - ty, - name, - evt + ty, name, evt )) } } @@ -89,14 +84,12 @@ impl OutputFormatter for JsonFormatter { self.write_event("test", desc.name.as_slice(), "failed", extra_data) } - TrFailedMsg(ref m) => { - self.write_event( - "test", - desc.name.as_slice(), - "failed", - Some(format!(r#""message": "{}""#, EscapedString(m))), - ) - } + TrFailedMsg(ref m) => self.write_event( + "test", + desc.name.as_slice(), + "failed", + Some(format!(r#""message": "{}""#, EscapedString(m))), + ), TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None), @@ -116,13 +109,10 @@ impl OutputFormatter for JsonFormatter { let line = format!( "{{ \"type\": \"bench\", \ - \"name\": \"{}\", \ - \"median\": {}, \ - \"deviation\": {}{} }}", - desc.name, - median, - deviation, - mbps + \"name\": \"{}\", \ + \"median\": {}, \ + \"deviation\": {}{} }}", + desc.name, median, deviation, mbps ); self.write_message(&*line) @@ -138,16 +128,15 @@ impl OutputFormatter for JsonFormatter { } fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result { - self.write_message(&*format!( "{{ \"type\": \"suite\", \ - \"event\": \"{}\", \ - \"passed\": {}, \ - \"failed\": {}, \ - \"allowed_fail\": {}, \ - \"ignored\": {}, \ - \"measured\": {}, \ - \"filtered_out\": \"{}\" }}", + \"event\": \"{}\", \ + \"passed\": {}, \ + \"failed\": {}, \ + \"allowed_fail\": {}, \ + \"ignored\": {}, \ + \"measured\": {}, \ + \"filtered_out\": \"{}\" }}", if state.failed == 0 { "ok" } else { "failed" }, state.passed, state.failed + state.allowed_fail, diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs index f2064deefce62..8e5fa00b5f27d 100644 --- a/src/libtest/formatters/pretty.rs +++ b/src/libtest/formatters/pretty.rs @@ -196,8 +196,7 @@ impl OutputFormatter for PrettyFormatter { self.write_plain(&format!( "test {} has been running for over {} seconds\n", - desc.name, - TEST_WARN_TIMEOUT_S + desc.name, TEST_WARN_TIMEOUT_S )) } @@ -232,11 +231,7 @@ impl OutputFormatter for PrettyFormatter { } else { format!( ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", - state.passed, - state.failed, - state.ignored, - state.measured, - state.filtered_out + state.passed, state.failed, state.ignored, state.measured, state.filtered_out ) }; diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs index 88689485144c0..85286027d6921 100644 --- a/src/libtest/formatters/terse.rs +++ b/src/libtest/formatters/terse.rs @@ -195,8 +195,7 @@ impl OutputFormatter for TerseFormatter { fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { self.write_plain(&format!( "test {} has been running for over {} seconds\n", - desc.name, - TEST_WARN_TIMEOUT_S + desc.name, TEST_WARN_TIMEOUT_S )) } @@ -231,11 +230,7 @@ impl OutputFormatter for TerseFormatter { } else { format!( ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", - state.passed, - state.failed, - state.ignored, - state.measured, - state.filtered_out + state.passed, state.failed, state.ignored, state.measured, state.filtered_out ) }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 59d701dd0fbc8..b8be1aeff1742 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -30,10 +30,8 @@ #![unstable(feature = "test", issue = "27812")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - test(attr(deny(warnings))))] + html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![deny(warnings)] - #![feature(asm)] #![feature(fnbox)] #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] @@ -43,10 +41,10 @@ #![feature(termination_trait_lib)] extern crate getopts; -extern crate term; #[cfg(any(unix, target_os = "cloudabi"))] extern crate libc; extern crate panic_unwind; +extern crate term; pub use self::TestFn::*; pub use self::ColorConfig::*; @@ -72,7 +70,7 @@ use std::process::Termination; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; -use std::time::{Instant, Duration}; +use std::time::{Duration, Instant}; use std::borrow::Cow; use std::process; @@ -81,16 +79,16 @@ const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in qu // to be used by rustc to compile tests in libtest pub mod test { - pub use {Bencher, TestName, TestResult, TestDesc, TestDescAndFn, TestOpts, TrFailed, - TrFailedMsg, TrIgnored, TrOk, Metric, MetricMap, StaticTestFn, StaticTestName, - DynTestName, DynTestFn, assert_test_result, run_test, test_main, test_main_static, - filter_tests, parse_opts, StaticBenchFn, ShouldPanic, Options}; + pub use {assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, + Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, ShouldPanic, + StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, + TestOpts, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk}; } pub mod stats; mod formatters; -use formatters::{OutputFormatter, PrettyFormatter, TerseFormatter, JsonFormatter}; +use formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}; // The name of a test. By convention this follows the rules for rust // paths; i.e. it should be a series of identifiers separated by double @@ -255,7 +253,9 @@ pub struct Options { impl Options { pub fn new() -> Options { - Options { display_output: false } + Options { + display_output: false, + } } pub fn display_output(mut self, display_output: bool) -> Options { @@ -272,7 +272,7 @@ pub fn test_main(args: &[String], tests: Vec, options: Options) { Some(Err(msg)) => { eprintln!("error: {}", msg); process::exit(101); - }, + } None => return, }; @@ -289,7 +289,7 @@ pub fn test_main(args: &[String], tests: Vec, options: Options) { Err(e) => { eprintln!("error: io error when listing tests: {:?}", e); process::exit(101); - }, + } } } } @@ -306,18 +306,14 @@ pub fn test_main_static(tests: &[TestDescAndFn]) { let owned_tests = tests .iter() .map(|t| match t.testfn { - StaticTestFn(f) => { - TestDescAndFn { - testfn: StaticTestFn(f), - desc: t.desc.clone(), - } - } - StaticBenchFn(f) => { - TestDescAndFn { - testfn: StaticBenchFn(f), - desc: t.desc.clone(), - } - } + StaticTestFn(f) => TestDescAndFn { + testfn: StaticTestFn(f), + desc: t.desc.clone(), + }, + StaticBenchFn(f) => TestDescAndFn { + testfn: StaticBenchFn(f), + desc: t.desc.clone(), + }, _ => panic!("non-static tests passed to test::test_main_static"), }) .collect(); @@ -397,34 +393,34 @@ fn optgroups() -> getopts::Options { "", "logfile", "Write logs to the specified file instead \ - of stdout", + of stdout", "PATH", ) .optflag( "", "nocapture", "don't capture stdout/stderr of each \ - task, allow printing directly", + task, allow printing directly", ) .optopt( "", "test-threads", "Number of threads used for running tests \ - in parallel", + in parallel", "n_threads", ) .optmulti( "", "skip", "Skip tests whose names contain FILTER (this flag can \ - be used multiple times)", + be used multiple times)", "FILTER", ) .optflag( "q", "quiet", "Display one character per test instead of one line. \ - Alias to --format=terse", + Alias to --format=terse", ) .optflag( "", @@ -516,8 +512,7 @@ pub fn parse_opts(args: &[String]) -> Option { if let Some(opt) = matches.opt_str("Z") { if !is_nightly() { return Some(Err( - "the option `Z` is only accepted on the nightly compiler" - .into(), + "the option `Z` is only accepted on the nightly compiler".into(), )); } @@ -562,19 +557,17 @@ pub fn parse_opts(args: &[String]) -> Option { } let test_threads = match matches.opt_str("test-threads") { - Some(n_str) => { - match n_str.parse::() { - Ok(0) => return Some(Err(format!("argument for --test-threads must not be 0"))), - Ok(n) => Some(n), - Err(e) => { - return Some(Err(format!( - "argument for --test-threads must be a number > 0 \ - (error: {})", - e - ))) - } + Some(n_str) => match n_str.parse::() { + Ok(0) => return Some(Err(format!("argument for --test-threads must not be 0"))), + Ok(n) => Some(n), + Err(e) => { + return Some(Err(format!( + "argument for --test-threads must be a number > 0 \ + (error: {})", + e + ))) } - } + }, None => None, }; @@ -586,7 +579,7 @@ pub fn parse_opts(args: &[String]) -> Option { Some(v) => { return Some(Err(format!( "argument for --color must be auto, always, or never (was \ - {})", + {})", v ))) } @@ -599,8 +592,7 @@ pub fn parse_opts(args: &[String]) -> Option { Some("json") => { if !allow_unstable { return Some(Err( - "The \"json\" format is only accepted on the nightly compiler" - .into(), + "The \"json\" format is only accepted on the nightly compiler".into(), )); } OutputFormat::Json @@ -609,7 +601,7 @@ pub fn parse_opts(args: &[String]) -> Option { Some(v) => { return Some(Err(format!( "argument for --format must be pretty, terse, or json (was \ - {})", + {})", v ))) } @@ -811,8 +803,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Res ntest += 1; "test" } - StaticBenchFn(..) | - DynBenchFn(..) => { + StaticBenchFn(..) | DynBenchFn(..) => { nbench += 1; "benchmark" } @@ -834,7 +825,8 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Res writeln!(output, "")?; } - writeln!(output, + writeln!( + output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark") @@ -851,7 +843,6 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu st: &mut ConsoleTestState, out: &mut OutputFormatter, ) -> io::Result<()> { - match (*event).clone() { TeFiltered(ref filtered_tests) => { st.total = filtered_tests.len(); @@ -989,8 +980,7 @@ fn use_color(opts: &TestOpts) -> bool { } } -#[cfg(any(target_os = "cloudabi", - target_os = "redox", +#[cfg(any(target_os = "cloudabi", target_os = "redox", all(target_arch = "wasm32", not(target_os = "emscripten"))))] fn stdout_isatty() -> bool { // FIXME: Implement isatty on Redox @@ -1089,10 +1079,12 @@ where let now = Instant::now(); let timed_out = running_tests .iter() - .filter_map(|(desc, timeout)| if &now >= timeout { - Some(desc.clone()) - } else { - None + .filter_map(|(desc, timeout)| { + if &now >= timeout { + Some(desc.clone()) + } else { + None + } }) .collect(); for test in &timed_out { @@ -1174,12 +1166,10 @@ fn get_concurrency() -> usize { let opt_n: Option = s.parse().ok(); match opt_n { Some(n) if n > 0 => n, - _ => { - panic!( - "RUST_TEST_THREADS is `{}`, should be a positive integer.", - s - ) - } + _ => panic!( + "RUST_TEST_THREADS is `{}`, should be a positive integer.", + s + ), } } Err(..) => num_cpus(), @@ -1223,20 +1213,15 @@ fn get_concurrency() -> usize { 1 } - #[cfg(any(target_os = "android", - target_os = "cloudabi", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "solaris"))] + #[cfg(any(target_os = "android", target_os = "cloudabi", target_os = "emscripten", + target_os = "fuchsia", target_os = "ios", target_os = "linux", + target_os = "macos", target_os = "solaris"))] fn num_cpus() -> usize { unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } } #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", - target_os = "netbsd"))] + target_os = "netbsd"))] fn num_cpus() -> usize { use std::ptr; @@ -1308,26 +1293,28 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec filtered, - Some(ref filter) => { - filtered - .into_iter() - .filter(|test| if opts.filter_exact { + Some(ref filter) => filtered + .into_iter() + .filter(|test| { + if opts.filter_exact { test.desc.name.as_slice() == &filter[..] } else { test.desc.name.as_slice().contains(&filter[..]) - }) - .collect() - } + } + }) + .collect(), }; // Skip tests that match any of the skip filters filtered = filtered .into_iter() .filter(|t| { - !opts.skip.iter().any(|sf| if opts.filter_exact { - t.desc.name.as_slice() == &sf[..] - } else { - t.desc.name.as_slice().contains(&sf[..]) + !opts.skip.iter().any(|sf| { + if opts.filter_exact { + t.desc.name.as_slice() == &sf[..] + } else { + t.desc.name.as_slice().contains(&sf[..]) + } }) }) .collect(); @@ -1354,31 +1341,23 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec) -> Vec { // convert benchmarks to tests, if we're not benchmarking them - tests.into_iter().map(|x| { - let testfn = match x.testfn { - DynBenchFn(bench) => { - DynTestFn(Box::new(move || { - bench::run_once(|b| { - __rust_begin_short_backtrace(|| bench.run(b)) - }) - })) - } - StaticBenchFn(benchfn) => { - DynTestFn(Box::new(move || { - bench::run_once(|b| { - __rust_begin_short_backtrace(|| benchfn(b)) - }) - })) - } + tests + .into_iter() + .map(|x| { + let testfn = match x.testfn { + DynBenchFn(bench) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b))) + })), + StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) + })), f => f, }; TestDescAndFn { @@ -1395,22 +1374,22 @@ pub fn run_test( test: TestDescAndFn, monitor_ch: Sender, ) { - let TestDescAndFn { desc, testfn } = test; - let ignore_because_panic_abort = cfg!(target_arch = "wasm32") && - !cfg!(target_os = "emscripten") && - desc.should_panic != ShouldPanic::No; + let ignore_because_panic_abort = cfg!(target_arch = "wasm32") && !cfg!(target_os = "emscripten") + && desc.should_panic != ShouldPanic::No; if force_ignore || desc.ignore || ignore_because_panic_abort { monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap(); return; } - fn run_test_inner(desc: TestDesc, - monitor_ch: Sender, - nocapture: bool, - testfn: Box) { + fn run_test_inner( + desc: TestDesc, + monitor_ch: Sender, + nocapture: bool, + testfn: Box, + ) { // Buffer for capturing standard I/O let data = Arc::new(Mutex::new(Vec::new())); let data2 = data.clone(); @@ -1440,7 +1419,6 @@ pub fn run_test( .unwrap(); }; - // If the platform is single-threaded we're just going to run // the test synchronously, regardless of the concurrency // level. @@ -1455,27 +1433,25 @@ pub fn run_test( match testfn { DynBenchFn(bencher) => { - ::bench::benchmark(desc, - monitor_ch, - opts.nocapture, - |harness| bencher.run(harness)); + ::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { + bencher.run(harness) + }); } StaticBenchFn(benchfn) => { - ::bench::benchmark(desc, - monitor_ch, - opts.nocapture, - |harness| (benchfn.clone())(harness)); + ::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { + (benchfn.clone())(harness) + }); } DynTestFn(f) => { - let cb = move || { - __rust_begin_short_backtrace(f) - }; + let cb = move || __rust_begin_short_backtrace(f); run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb)) } - StaticTestFn(f) => { - run_test_inner(desc, monitor_ch, opts.nocapture, - Box::new(move || __rust_begin_short_backtrace(f))) - } + StaticTestFn(f) => run_test_inner( + desc, + monitor_ch, + opts.nocapture, + Box::new(move || __rust_begin_short_backtrace(f)), + ), } } @@ -1487,8 +1463,7 @@ fn __rust_begin_short_backtrace(f: F) { fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { match (&desc.should_panic, task_result) { - (&ShouldPanic::No, Ok(())) | - (&ShouldPanic::Yes, Err(_)) => TrOk, + (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { if err.downcast_ref::() .map(|e| &**e) @@ -1545,7 +1520,6 @@ impl MetricMap { } } - // Benchmarking /// A function that is opaque to the optimizer, to allow benchmarks to @@ -1566,7 +1540,6 @@ pub fn black_box(dummy: T) -> T { dummy } - impl Bencher { /// Callback for benchmark functions to run in their body. pub fn iter(&mut self, mut inner: F) @@ -1605,7 +1578,6 @@ where return ns_from_dur(start.elapsed()); } - pub fn iter(inner: &mut F) -> stats::Summary where F: FnMut() -> T, @@ -1649,8 +1621,8 @@ where // If we've run for 100ms and seem to have converged to a // stable median. - if loop_run > Duration::from_millis(100) && summ.median_abs_dev_pct < 1.0 && - summ.median - summ5.median < summ5.median_abs_dev + if loop_run > Duration::from_millis(100) && summ.median_abs_dev_pct < 1.0 + && summ.median - summ5.median < summ5.median_abs_dev { return summ5; } @@ -1680,7 +1652,7 @@ pub mod bench { use std::io; use std::sync::{Arc, Mutex}; use stats; - use super::{Bencher, BenchSamples, BenchMode, Sink, MonitorMsg, TestDesc, Sender, TestResult}; + use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult}; pub fn benchmark(desc: TestDesc, monitor_ch: Sender, nocapture: bool, f: F) where @@ -1711,7 +1683,8 @@ pub mod bench { io::set_panic(panicio); }; - let test_result = match result { //bs.bench(f) { + let test_result = match result { + //bs.bench(f) { Ok(Some(ns_iter_summ)) => { let ns_iter = cmp::max(ns_iter_summ.median as u64, 1); let mb_s = bs.bytes * 1000 / ns_iter; @@ -1732,9 +1705,7 @@ pub mod bench { }; TestResult::TrBench(bs) } - Err(_) => { - TestResult::TrFailed - } + Err(_) => TestResult::TrFailed, }; let stdout = data.lock().unwrap().to_vec(); @@ -1756,9 +1727,9 @@ pub mod bench { #[cfg(test)] mod tests { - use test::{TrFailed, TrFailedMsg, TrIgnored, TrOk, filter_tests, parse_opts, TestDesc, - TestDescAndFn, TestOpts, run_test, MetricMap, StaticTestName, DynTestName, - DynTestFn, ShouldPanic}; + use test::{filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, ShouldPanic, + StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, + TrIgnored, TrOk}; use std::sync::mpsc::channel; use bench; use Bencher; @@ -1904,25 +1875,26 @@ mod tests { opts.run_tests = true; opts.run_ignored = true; - let tests = - vec![TestDescAndFn { - desc: TestDesc { - name: StaticTestName("1"), - ignore: true, - should_panic: ShouldPanic::No, - allow_fail: false, - }, - testfn: DynTestFn(Box::new(move || {})), - }, - TestDescAndFn { - desc: TestDesc { - name: StaticTestName("2"), - ignore: false, - should_panic: ShouldPanic::No, - allow_fail: false, - }, - testfn: DynTestFn(Box::new(move || {})), - }]; + let tests = vec![ + TestDescAndFn { + desc: TestDesc { + name: StaticTestName("1"), + ignore: true, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }, + TestDescAndFn { + desc: TestDesc { + name: StaticTestName("2"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }, + ]; let filtered = filter_tests(&opts, tests); assert_eq!(filtered.len(), 1); @@ -1935,17 +1907,16 @@ mod tests { fn tests() -> Vec { vec!["base", "base::test", "base::test1", "base::test2"] .into_iter() - .map(|name| { - TestDescAndFn { - desc: TestDesc { - name: StaticTestName(name), - ignore: false, - should_panic: ShouldPanic::No, - allow_fail: false, - }, - testfn: DynTestFn(Box::new(move || {})) - } - }).collect() + .map(|name| TestDescAndFn { + desc: TestDesc { + name: StaticTestName(name), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }) + .collect() } let substr = filter_tests( @@ -2127,10 +2098,7 @@ mod tests { allow_fail: false, }; - ::bench::benchmark(desc, - tx, - true, - f); + ::bench::benchmark(desc, tx, true, f); rx.recv().unwrap(); } @@ -2149,10 +2117,7 @@ mod tests { allow_fail: false, }; - ::bench::benchmark(desc, - tx, - true, - f); + ::bench::benchmark(desc, tx, true, f); rx.recv().unwrap(); } } diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index e22fdf77fc171..ddb5dcf2a1cd3 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -279,7 +279,6 @@ impl Stats for [f64] { } } - // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using // linear interpolation. If samples are not sorted, return nonsensical value. fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { @@ -304,7 +303,6 @@ fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { lo + (hi - lo) * d } - /// Winsorize a set of samples, replacing values above the `100-pct` percentile /// and below the `pct` percentile with those percentiles themselves. This is a /// way of minimizing the effect of outliers, at the cost of biasing the sample. @@ -338,15 +336,18 @@ mod tests { use std::io; macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => ({ + ($a: expr, $b: expr) => {{ let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) + assert!( + (*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", + *a, + *b + ); + }}; } fn check(samples: &[f64], summ: &Summary) { - let summ2 = Summary::new(samples); let mut w = io::sink(); @@ -911,14 +912,18 @@ mod bench { #[bench] pub fn sum_three_items(b: &mut Bencher) { - b.iter(|| { [1e20f64, 1.5f64, -1e20f64].sum(); }) + b.iter(|| { + [1e20f64, 1.5f64, -1e20f64].sum(); + }) } #[bench] pub fn sum_many_f64(b: &mut Bencher) { let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60]; let v = (0..500).map(|i| nums[i % 5]).collect::>(); - b.iter(|| { v.sum(); }) + b.iter(|| { + v.sum(); + }) } #[bench] From b6934c91b23517c4e17d8016b6c46ffd0703eded Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 21 Mar 2018 13:32:46 -0500 Subject: [PATCH 24/48] termination_trait: Put examples in error help, not label --- src/librustc/traits/error_reporting.rs | 23 +++++++++++-------- src/libstd/process.rs | 2 +- .../termination-trait-main-i32.rs | 2 +- .../termination-trait-main-wrong-type.stderr | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e5dc02798dff..8572c4077142b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -585,20 +585,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.to_predicate(), post_message) })); + let explanation = match obligation.cause.code { + ObligationCauseCode::MainFunctionType => { + "consider using `()`, or a `Result`".to_owned() + } + _ => { + format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty()) + } + }; + if let Some(ref s) = label { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it as the label! err.span_label(span, s.as_str()); - err.help(&format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.help(&explanation); } else { - err.span_label(span, - &*format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.span_label(span, explanation); } if let Some(ref s) = note { // If it has a custom "#[rustc_on_unimplemented]" note, let's display it diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a6aa3502f26bb..d5ac2d19e831f 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1443,7 +1443,7 @@ pub fn id() -> u32 { #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = - "`main` can only return types like `()` that implement {Termination}, not `{Self}`"] + "`main` can only return types that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 053d6bbf93a2d..2cf9fdcfb4dbd 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -10,6 +10,6 @@ fn main() -> i32 { //~^ ERROR `i32: std::process::Termination` is not satisfied -//~| NOTE `main` can only return types like `()` that implement std::process::Termination, not `i32` +//~| NOTE `main` can only return types that implement std::process::Termination, not `i32` 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 24371c27742d2..211247757cbc1 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `char: std::process::Termination` is not satisfied --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types like `()` that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types that implement std::process::Termination, not `char` | - = help: the trait `std::process::Termination` is not implemented for `char` + = help: consider using `()`, or a `Result` error: aborting due to previous error From 178652a2988d9ecd478a4116237e1d7ea6b777f7 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 20 Mar 2018 02:06:38 +0000 Subject: [PATCH 25/48] Add support to rustbuild for a 'rustc docs' component tarball --- src/bootstrap/builder.rs | 12 ++-- src/bootstrap/dist.rs | 69 +++++++++++++++++--- src/bootstrap/doc.rs | 133 ++++++++++++++++++++++++++++++--------- src/bootstrap/lib.rs | 5 ++ 4 files changed, 178 insertions(+), 41 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 675d3dd437eef..9f779da6f65b3 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -316,11 +316,13 @@ impl<'a> Builder<'a> { test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, - doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, - doc::Reference, doc::Rustdoc, doc::RustByExample, doc::CargoBook), - Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, - dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, - dist::Rls, dist::Rustfmt, dist::Extended, dist::HashSign), + doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, + doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, + doc::CargoBook), + Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc, + dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, + dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended, + dist::HashSign), Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls, install::Rustfmt, install::Analysis, install::Src, install::Rustc), } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index dcb572416594e..e25a7e1852586 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -102,7 +102,7 @@ impl Step for Docs { let dst = image.join("share/doc/rust/html"); t!(fs::create_dir_all(&dst)); - let src = build.out.join(host).join("doc"); + let src = build.doc_out(host); cp_r(&src, &dst); let mut cmd = rust_installer(builder); @@ -120,14 +120,69 @@ impl Step for Docs { build.run(&mut cmd); t!(fs::remove_dir_all(&image)); - // As part of this step, *also* copy the docs directory to a directory which - // buildbot typically uploads. - if host == build.build { - let dst = distdir(build).join("doc").join(build.rust_package_vers()); - t!(fs::create_dir_all(&dst)); - cp_r(&src, &dst); + distdir(build).join(format!("{}-{}.tar.gz", name, host)) + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustcDocs { + pub stage: u32, + pub host: Interned, +} + +impl Step for RustcDocs { + type Output = PathBuf; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/librustc") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(RustcDocs { + stage: run.builder.top_stage, + host: run.target, + }); + } + + /// Builds the `rustc-docs` installer component. + fn run(self, builder: &Builder) -> PathBuf { + let build = builder.build; + let host = self.host; + + let name = pkgname(build, "rustc-docs"); + + println!("Dist compiler docs ({})", host); + if !build.config.compiler_docs { + println!("\tskipping - compiler docs disabled"); + return distdir(build).join(format!("{}-{}.tar.gz", name, host)); } + builder.default_doc(None); + + let image = tmpdir(build).join(format!("{}-{}-image", name, host)); + let _ = fs::remove_dir_all(&image); + + let dst = image.join("share/doc/rustc/html"); + t!(fs::create_dir_all(&dst)); + let src = build.compiler_doc_out(host); + cp_r(&src, &dst); + + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rustc-Documentation") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=Rustc-documentation-is-installed.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(build)) + .arg("--output-dir").arg(&distdir(build)) + .arg(format!("--package-name={}-{}", name, host)) + .arg("--component-name=rustc-docs") + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--bulk-dirs=share/doc/rustc/html"); + build.run(&mut cmd); + t!(fs::remove_dir_all(&image)); + distdir(build).join(format!("{}-{}.tar.gz", name, host)) } } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5bc582b3507bb..ca45adb4649af 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -483,21 +483,17 @@ impl Step for Std { let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc"); compile::std_cargo(builder, &compiler, target, &mut cargo); - // We don't want to build docs for internal std dependencies unless - // in compiler-docs mode. When not in that mode, we whitelist the crates - // for which docs must be built. - if !build.config.compiler_docs { - cargo.arg("--no-deps"); - for krate in &["alloc", "core", "std", "std_unicode"] { - cargo.arg("-p").arg(krate); - // Create all crate output directories first to make sure rustdoc uses - // relative links. - // FIXME: Cargo should probably do this itself. - t!(fs::create_dir_all(out_dir.join(krate))); - } + // Keep a whitelist so we do not build internal stdlib crates, these will be + // build by the rustc step later if enabled. + cargo.arg("--no-deps"); + for krate in &["alloc", "core", "std", "std_unicode"] { + cargo.arg("-p").arg(krate); + // Create all crate output directories first to make sure rustdoc uses + // relative links. + // FIXME: Cargo should probably do this itself. + t!(fs::create_dir_all(out_dir.join(krate))); } - build.run(&mut cargo); cp_r(&my_out, &out); } @@ -563,6 +559,81 @@ impl Step for Test { } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct WhitelistedRustc { + stage: u32, + target: Interned, +} + +impl Step for WhitelistedRustc { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run.krate("rustc-main").default_condition(builder.build.config.docs) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(WhitelistedRustc { + stage: run.builder.top_stage, + target: run.target, + }); + } + + /// Generate whitelisted compiler crate documentation. + /// + /// This will generate all documentation for crates that are whitelisted + /// to be included in the standard documentation. This documentation is + /// included in the standard Rust documentation, so we should always + /// document it and symlink to merge with the rest of the std and test + /// documentation. We don't build other compiler documentation + /// here as we want to be able to keep it separate from the standard + /// documentation. This is largely just a wrapper around `cargo doc`. + fn run(self, builder: &Builder) { + let build = builder.build; + let stage = self.stage; + let target = self.target; + println!("Documenting stage{} whitelisted compiler ({})", stage, target); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); + let compiler = builder.compiler(stage, build.build); + let rustdoc = builder.rustdoc(compiler.host); + let compiler = if build.force_use_stage1(compiler, target) { + builder.compiler(1, compiler.host) + } else { + compiler + }; + + // Build libstd docs so that we generate relative links + builder.ensure(Std { stage, target }); + + builder.ensure(compile::Rustc { compiler, target }); + let out_dir = build.stage_out(compiler, Mode::Librustc) + .join(target).join("doc"); + + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); + + let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); + compile::rustc_cargo(build, &mut cargo); + + // We don't want to build docs for internal compiler dependencies in this + // step (there is another step for that). Therefore, we whitelist the crates + // for which docs must be built. + cargo.arg("--no-deps"); + for krate in &["proc_macro"] { + cargo.arg("-p").arg(krate); + } + + build.run(&mut cargo); + cp_r(&my_out, &out); + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustc { stage: u32, @@ -586,16 +657,18 @@ impl Step for Rustc { }); } - /// Generate all compiler documentation. + /// Generate compiler documentation. /// - /// This will generate all documentation for the compiler libraries and their - /// dependencies. This is largely just a wrapper around `cargo doc`. + /// This will generate all documentation for compiler and dependencies. + /// Compiler documentation is distributed separately, so we make sure + /// we do not merge it with the other documentation from std, test and + /// proc_macros. This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder) { let build = builder.build; let stage = self.stage; let target = self.target; println!("Documenting stage{} compiler ({})", stage, target); - let out = build.doc_out(target); + let out = build.compiler_doc_out(target); t!(fs::create_dir_all(&out)); let compiler = builder.compiler(stage, build.build); let rustdoc = builder.rustdoc(compiler.host); @@ -605,6 +678,11 @@ impl Step for Rustc { compiler }; + if !build.config.compiler_docs { + println!("\tskipping - compiler docs disabled"); + return; + } + // Build libstd docs so that we generate relative links builder.ensure(Std { stage, target }); @@ -613,6 +691,12 @@ impl Step for Rustc { .join(target).join("doc"); // See docs in std above for why we symlink + // + // This step must happen after other documentation steps. This + // invariant ensures that compiler documentation is not included + // in the standard documentation tarballs but that all the + // documentation from the standard documentation tarballs is included + // in the compiler documentation tarball. let my_out = build.crate_doc_out(target); build.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&my_out, &out_dir)); @@ -620,18 +704,9 @@ impl Step for Rustc { let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); compile::rustc_cargo(build, &mut cargo); - if build.config.compiler_docs { - // src/rustc/Cargo.toml contains a bin crate called rustc which - // would otherwise overwrite the docs for the real rustc lib crate. - cargo.arg("-p").arg("rustc_driver"); - } else { - // Like with libstd above if compiler docs aren't enabled then we're not - // documenting internal dependencies, so we have a whitelist. - cargo.arg("--no-deps"); - for krate in &["proc_macro"] { - cargo.arg("-p").arg(krate); - } - } + // src/rustc/Cargo.toml contains a bin crate called rustc which + // would otherwise overwrite the docs for the real rustc lib crate. + cargo.arg("-p").arg("rustc_driver"); build.run(&mut cargo); cp_r(&my_out, &out); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b778ba33d89cc..b2c8ac24d72d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -511,6 +511,11 @@ impl Build { self.out.join(&*target).join("doc") } + /// Output directory for all documentation for a target + fn compiler_doc_out(&self, target: Interned) -> PathBuf { + self.out.join(&*target).join("compiler-doc") + } + /// Output directory for some generated md crate documentation for a target (temporary) fn md_doc_out(&self, target: Interned) -> Interned { INTERNER.intern_path(self.out.join(&*target).join("md-doc")) From 1392179cdc9c96e75353771959c246553b918d57 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 20 Mar 2018 02:07:16 +0000 Subject: [PATCH 26/48] Configure the dist-x86_64-linux builder to produce compiler documentation --- src/ci/docker/dist-x86_64-linux/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 3b98b0aa926bd..28c97e8c6dbf9 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -84,7 +84,8 @@ ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --enable-compiler-docs ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs From c116b0e8296dc4198408a708fae53f47fc1e51c6 Mon Sep 17 00:00:00 2001 From: Maxwell Borden Date: Wed, 21 Mar 2018 18:11:57 -0700 Subject: [PATCH 27/48] Fixed clockwise/counter-clockwise in atan2 documentation in f32 and f64 and included that it returns radians --- src/libstd/f32.rs | 9 +++++---- src/libstd/f64.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index a760922115aef..ceb019bc95b4c 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -780,7 +780,7 @@ impl f32 { unsafe { cmath::atanf(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` @@ -791,12 +791,13 @@ impl f32 { /// use std::f32; /// /// let pi = f32::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0f32; /// let y1 = -3.0f32; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0f32; /// let y2 = 3.0f32; /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 6f34f176a9711..97adf108b73b0 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -716,7 +716,7 @@ impl f64 { unsafe { cmath::atan(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` @@ -727,12 +727,13 @@ impl f64 { /// use std::f64; /// /// let pi = f64::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0_f64; /// let y1 = -3.0_f64; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0_f64; /// let y2 = 3.0_f64; /// From 2b13d95da02d318c12814261dd36edd91ae6879e Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 21 Mar 2018 23:28:48 -0500 Subject: [PATCH 28/48] termination_trait: Make error message more helpful --- src/librustc/traits/error_reporting.rs | 16 +++++++--------- src/libstd/process.rs | 5 +++-- .../termination-trait-main-i32.rs | 5 +++-- .../termination-trait-not-satisfied.rs | 2 +- .../termination-trait-main-wrong-type.stderr | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8572c4077142b..47e6b0feceae3 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -585,17 +585,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.to_predicate(), post_message) })); - let explanation = match obligation.cause.code { - ObligationCauseCode::MainFunctionType => { + let explanation = + if obligation.cause.code == ObligationCauseCode::MainFunctionType { "consider using `()`, or a `Result`".to_owned() - } - _ => { + } else { format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty()) - } - }; + pre_message, + trait_ref, + trait_ref.self_ty()) + }; if let Some(ref s) = label { // If it has a custom "#[rustc_on_unimplemented]" diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d5ac2d19e831f..c877bf6aa35cd 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1442,8 +1442,9 @@ pub fn id() -> u32 { /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] +#[rustc_on_unimplemented( + message="`main` has invalid return type `{Self}`", + label="`main` can only return types that implement {Termination}")] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 2cf9fdcfb4dbd..0e6ddf7c92f1a 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -9,7 +9,8 @@ // except according to those terms. fn main() -> i32 { -//~^ ERROR `i32: std::process::Termination` is not satisfied -//~| NOTE `main` can only return types that implement std::process::Termination, not `i32` +//~^ ERROR `main` has invalid return type `i32` +//~| NOTE `main` can only return types that implement std::process::Termination +//~| HELP consider using `()`, or a `Result` 0 } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index bab02fc559706..b5f5472b49290 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -10,6 +10,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType` ReturnType {} } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 211247757cbc1..5109d9275c58b 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `char: std::process::Termination` is not satisfied +error[E0277]: `main` has invalid return type `char` --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types that implement std::process::Termination | = help: consider using `()`, or a `Result` From 613fb8bc2c5277b9b9a14bdba3939bb6042d91ec Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 22 Mar 2018 10:06:17 +0100 Subject: [PATCH 29/48] document format_args! - fix trailing whitespace --- src/libcore/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0363714c31b5c..62994ed15cc6d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1682,7 +1682,7 @@ impl<'a> Formatter<'a> { /// /// struct Arm<'a, L: 'a, R: 'a>(&'a (L, R)); /// struct Table<'a, K: 'a, V: 'a>(&'a [(K, V)], V); - /// + /// /// impl<'a, L, R> fmt::Debug for Arm<'a, L, R> /// where /// L: 'a + fmt::Debug, R: 'a + fmt::Debug From a1a3bf2b31af680ffbbed4270efc0a2cda80ca87 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 22 Mar 2018 14:38:37 +0100 Subject: [PATCH 30/48] Fix DefKey lookup for proc-macro crates. --- src/librustc_metadata/decoder.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b0c945fbf2a05..1ea009a4e9116 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -14,7 +14,8 @@ use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use schema::*; use rustc_data_structures::sync::{Lrc, ReadGuard}; -use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, + DisambiguatedDefPathData}; use rustc::hir; use rustc::middle::cstore::{LinkagePreference, ExternConstBody, ExternBodyNestedBodies}; @@ -1115,7 +1116,23 @@ impl<'a, 'tcx> CrateMetadata { #[inline] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.def_path_table.def_key(index) + if !self.is_proc_macro(index) { + self.def_path_table.def_key(index) + } else { + // FIXME(#49271) - It would be better if the DefIds were consistent + // with the DefPathTable, but for proc-macro crates + // they aren't. + let name = self.proc_macros + .as_ref() + .unwrap()[index.to_proc_macro_index()].0; + DefKey { + parent: Some(CRATE_DEF_INDEX), + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::MacroDef(name.as_str()), + disambiguator: 0, + } + } + } } // Returns the path leading to the thing with this `id`. From 9839e5fa103d117cbdb936e8594ba832e1eeb320 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 22 Mar 2018 15:05:12 +0100 Subject: [PATCH 31/48] Remove slow HashSet during miri stack frame creation --- src/librustc_mir/interpret/eval_context.rs | 40 ++++++---------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c236ce2abc5f0..ee8419404ca47 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1,4 +1,3 @@ -use std::collections::HashSet; use std::fmt::Write; use rustc::hir::def_id::DefId; @@ -383,40 +382,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; - /// Return the set of locals that have a storage annotation anywhere - fn collect_storage_annotations<'mir, 'tcx>(mir: &'mir mir::Mir<'tcx>) -> HashSet { - use rustc::mir::StatementKind::*; - - let mut set = HashSet::new(); - for block in mir.basic_blocks() { - for stmt in block.statements.iter() { - match stmt.kind { - StorageLive(local) | - StorageDead(local) => { - set.insert(local); - } - _ => {} - } - } - } - set - } - // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local // `Value` for that. let num_locals = mir.local_decls.len() - 1; - let locals = { - let annotated_locals = collect_storage_annotations(mir); - let mut locals = vec![None; num_locals]; - for i in 0..num_locals { - let local = mir::Local::new(i + 1); - if !annotated_locals.contains(&local) { - locals[i] = Some(Value::ByVal(PrimVal::Undef)); + let mut locals = vec![Some(Value::ByVal(PrimVal::Undef)); num_locals]; + trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); + for block in mir.basic_blocks() { + for stmt in block.statements.iter() { + use rustc::mir::StatementKind::{StorageDead, StorageLive}; + match stmt.kind { + StorageLive(local) | StorageDead(local) => if local.index() > 0 { + locals[local.index() - 1] = None; + }, + _ => {} } } - locals - }; + } self.stack.push(Frame { mir, From 9fa14e47d4a14fcda4adff658ccfdda3c8b9005f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 22 Mar 2018 16:59:02 +0100 Subject: [PATCH 32/48] Skip checking for Storage* statements in constants/statics --- src/librustc_mir/interpret/eval_context.rs | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ee8419404ca47..376c7f240583c 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1,6 +1,7 @@ use std::fmt::Write; use rustc::hir::def_id::DefId; +use rustc::hir::def::Def; use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc::mir; @@ -387,17 +388,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let num_locals = mir.local_decls.len() - 1; let mut locals = vec![Some(Value::ByVal(PrimVal::Undef)); num_locals]; - trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); - for block in mir.basic_blocks() { - for stmt in block.statements.iter() { - use rustc::mir::StatementKind::{StorageDead, StorageLive}; - match stmt.kind { - StorageLive(local) | StorageDead(local) => if local.index() > 0 { - locals[local.index() - 1] = None; - }, - _ => {} + match self.tcx.describe_def(instance.def_id()) { + // statics and constants don't have `Storage*` statements, no need to look for them + Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}, + _ => { + trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); + for block in mir.basic_blocks() { + for stmt in block.statements.iter() { + use rustc::mir::StatementKind::{StorageDead, StorageLive}; + match stmt.kind { + StorageLive(local) | StorageDead(local) => if local.index() > 0 { + locals[local.index() - 1] = None; + }, + _ => {} + } + } } - } + }, } self.stack.push(Frame { From 1b0e9f5af9283b003f5fce6f19ede145c1776684 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 22 Mar 2018 14:57:28 +0000 Subject: [PATCH 33/48] Only generate documentation for local rustc crates. --- src/bootstrap/doc.rs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index ca45adb4649af..e525bdb98fc0c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -17,12 +17,13 @@ //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. +use std::collections::HashSet; use std::fs::{self, File}; use std::io::prelude::*; use std::io; use std::path::{PathBuf, Path}; -use Mode; +use {Build, Mode}; use build_helper::up_to_date; use util::{cp_r, symlink_dir}; @@ -704,15 +705,41 @@ impl Step for Rustc { let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); compile::rustc_cargo(build, &mut cargo); - // src/rustc/Cargo.toml contains a bin crate called rustc which - // would otherwise overwrite the docs for the real rustc lib crate. - cargo.arg("-p").arg("rustc_driver"); + // Only include compiler crates, no dependencies of those, such as `libc`. + cargo.arg("--no-deps"); + + // Find dependencies for top level crates. + let mut compiler_crates = HashSet::new(); + for root_crate in &["rustc", "rustc_driver"] { + let interned_root_crate = INTERNER.intern_str(root_crate); + find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates); + } + + for krate in &compiler_crates { + cargo.arg("-p").arg(krate); + } build.run(&mut cargo); cp_r(&my_out, &out); } } +fn find_compiler_crates( + build: &Build, + name: &Interned, + crates: &mut HashSet> +) { + // Add current crate. + crates.insert(*name); + + // Look for dependencies. + for dep in build.crates.get(name).unwrap().deps.iter() { + if build.crates.get(dep).unwrap().is_local(build) { + find_compiler_crates(build, dep, crates); + } + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { target: Interned, From 73fa6d52ed99651940267affa941a1069cc20f35 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 22 Mar 2018 20:49:05 +0000 Subject: [PATCH 34/48] Remove std/test documentation from compiler docs. --- src/bootstrap/dist.rs | 4 ++-- src/bootstrap/doc.rs | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e25a7e1852586..5563b153f5aff 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -163,7 +163,7 @@ impl Step for RustcDocs { let image = tmpdir(build).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); - let dst = image.join("share/doc/rustc/html"); + let dst = image.join("share/doc/rust/html"); t!(fs::create_dir_all(&dst)); let src = build.compiler_doc_out(host); cp_r(&src, &dst); @@ -179,7 +179,7 @@ impl Step for RustcDocs { .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rustc-docs") .arg("--legacy-manifest-dirs=rustlib,cargo") - .arg("--bulk-dirs=share/doc/rustc/html"); + .arg("--bulk-dirs=share/doc/rust/html"); build.run(&mut cmd); t!(fs::remove_dir_all(&image)); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index e525bdb98fc0c..44073a5b07572 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -690,17 +690,10 @@ impl Step for Rustc { builder.ensure(compile::Rustc { compiler, target }); let out_dir = build.stage_out(compiler, Mode::Librustc) .join(target).join("doc"); - - // See docs in std above for why we symlink - // - // This step must happen after other documentation steps. This - // invariant ensures that compiler documentation is not included - // in the standard documentation tarballs but that all the - // documentation from the standard documentation tarballs is included - // in the compiler documentation tarball. - let my_out = build.crate_doc_out(target); - build.clear_if_dirty(&my_out, &rustdoc); - t!(symlink_dir_force(&my_out, &out_dir)); + // We do not symlink to the same shared folder that already contains std library + // documentation from previous steps as we do not want to include that. + build.clear_if_dirty(&out, &rustdoc); + t!(symlink_dir_force(&out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); compile::rustc_cargo(build, &mut cargo); @@ -720,7 +713,6 @@ impl Step for Rustc { } build.run(&mut cargo); - cp_r(&my_out, &out); } } From 86f7d8939d19d42e21d4e794e648f0aef14eeec9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 22 Mar 2018 18:31:32 -0700 Subject: [PATCH 35/48] Allow installing rustfmt without config.extended This assertion was preventing `./x.py install rustfmt` if attempted without an "extended" build configuration, but it actually builds and installs just fine. --- src/bootstrap/dist.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index eca06eac7f307..142296b209586 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1186,7 +1186,6 @@ impl Step for Rustfmt { let build = builder.build; let stage = self.stage; let target = self.target; - assert!(build.config.extended); println!("Dist Rustfmt stage{} ({})", stage, target); let src = build.src.join("src/tools/rustfmt"); From bf8e4f231a0e51a7421e99831450bcbc55b14de3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 23 Mar 2018 08:31:13 +0100 Subject: [PATCH 36/48] Vec<_> -> IndexVec --- src/librustc_mir/interpret/eval_context.rs | 36 +++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 376c7f240583c..10d509548d9a5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -9,7 +9,7 @@ use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::TyCtxtAt; -use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::middle::const_val::FrameInfo; use syntax::codemap::{self, Span}; use syntax::ast::Mutability; @@ -71,12 +71,12 @@ pub struct Frame<'mir, 'tcx: 'mir> { pub return_place: Place, /// The list of locals for this stack frame, stored in order as - /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option`s. + /// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option`s. /// `None` represents a local that is currently dead, while a live local /// can either directly contain `PrimVal` or refer to some part of an `Allocation`. /// /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`. - pub locals: Vec>, + pub locals: IndexVec>, //////////////////////////////////////////////////////////////////////////////// // Current position within the function @@ -383,11 +383,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; - // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local - // `Value` for that. - let num_locals = mir.local_decls.len() - 1; - - let mut locals = vec![Some(Value::ByVal(PrimVal::Undef)); num_locals]; + let mut locals = IndexVec::from_elem(Some(Value::ByVal(PrimVal::Undef)), &mir.local_decls); match self.tcx.describe_def(instance.def_id()) { // statics and constants don't have `Storage*` statements, no need to look for them Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}, @@ -397,9 +393,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M for stmt in block.statements.iter() { use rustc::mir::StatementKind::{StorageDead, StorageLive}; match stmt.kind { - StorageLive(local) | StorageDead(local) => if local.index() > 0 { - locals[local.index() - 1] = None; - }, + StorageLive(local) | + StorageDead(local) => locals[local] = None, _ => {} } } @@ -962,8 +957,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> { let new_place = match place { Place::Local { frame, local } => { - // -1 since we don't store the return value - match self.stack[frame].locals[local.index() - 1] { + match self.stack[frame].locals[local] { None => return err!(DeadLocal), Some(Value::ByRef(ptr, align)) => { Place::Ptr { @@ -977,7 +971,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let ty = self.monomorphize(ty, self.stack[frame].instance.substs); let layout = self.layout_of(ty)?; let ptr = self.alloc_ptr(ty)?; - self.stack[frame].locals[local.index() - 1] = + self.stack[frame].locals[local] = Some(Value::ByRef(ptr.into(), layout.align)); // it stays live let place = Place::from_ptr(ptr, layout.align); self.write_value(ValTy { value: val, ty }, place)?; @@ -1691,13 +1685,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M impl<'mir, 'tcx> Frame<'mir, 'tcx> { pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into()) + self.locals[local].ok_or(EvalErrorKind::DeadLocal.into()) } fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - match self.locals[local.index() - 1] { + match self.locals[local] { None => err!(DeadLocal), Some(ref mut local) => { *local = value; @@ -1709,8 +1701,8 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> { pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { trace!("{:?} is now live", local); - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored + let old = self.locals[local]; + self.locals[local] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored return Ok(old); } @@ -1718,8 +1710,8 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> { pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { trace!("{:?} is now dead", local); - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = None; + let old = self.locals[local]; + self.locals[local] = None; return Ok(old); } } From b18b776b8fd2c710eae7673320343c39ae55bc19 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 23 Mar 2018 10:32:27 +0100 Subject: [PATCH 37/48] Replace uses of `Hash(Map|Set)` with `FxHash(Map|Set)` in miri --- src/librustc_mir/interpret/memory.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index b369f80e849b0..4026f52e9620d 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -1,5 +1,5 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; -use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; +use std::collections::{btree_map, BTreeMap, VecDeque}; use std::{ptr, io}; use rustc::ty::Instance; @@ -7,6 +7,7 @@ use rustc::ty::maps::TyCtxtAt; use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer, EvalResult, PrimVal, EvalErrorKind}; @@ -33,15 +34,15 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { pub data: M::MemoryData, /// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate` - alloc_kind: HashMap>, + alloc_kind: FxHashMap>, /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). - alloc_map: HashMap, + alloc_map: FxHashMap, /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). /// /// Stores statics while they are being processed, before they are interned and thus frozen - uninitialized_statics: HashMap, + uninitialized_statics: FxHashMap, /// The current stack frame. Used to check accesses against locks. pub cur_frame: usize, @@ -53,9 +54,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self { Memory { data, - alloc_kind: HashMap::new(), - alloc_map: HashMap::new(), - uninitialized_statics: HashMap::new(), + alloc_kind: FxHashMap::default(), + alloc_map: FxHashMap::default(), + uninitialized_statics: FxHashMap::default(), tcx, cur_frame: usize::max_value(), } @@ -338,7 +339,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { allocs.sort(); allocs.dedup(); let mut allocs_to_print = VecDeque::from(allocs); - let mut allocs_seen = HashSet::new(); + let mut allocs_seen = FxHashSet::default(); while let Some(id) = allocs_to_print.pop_front() { let mut msg = format!("Alloc {:<5} ", format!("{}:", id)); From 4ea4dd23cde23a8f3c02d77140ae0eb30a0cee25 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 23 Mar 2018 10:47:55 +0100 Subject: [PATCH 38/48] Don't allocate a local array at all if there are no locals --- src/librustc_mir/interpret/eval_context.rs | 38 +++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 10d509548d9a5..db4c8f706ba7b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -383,24 +383,30 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) -> EvalResult<'tcx> { ::log_settings::settings().indentation += 1; - let mut locals = IndexVec::from_elem(Some(Value::ByVal(PrimVal::Undef)), &mir.local_decls); - match self.tcx.describe_def(instance.def_id()) { - // statics and constants don't have `Storage*` statements, no need to look for them - Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}, - _ => { - trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); - for block in mir.basic_blocks() { - for stmt in block.statements.iter() { - use rustc::mir::StatementKind::{StorageDead, StorageLive}; - match stmt.kind { - StorageLive(local) | - StorageDead(local) => locals[local] = None, - _ => {} + let locals = if mir.local_decls.len() > 1 { + let mut locals = IndexVec::from_elem(Some(Value::ByVal(PrimVal::Undef)), &mir.local_decls); + match self.tcx.describe_def(instance.def_id()) { + // statics and constants don't have `Storage*` statements, no need to look for them + Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {}, + _ => { + trace!("push_stack_frame: {:?}: num_bbs: {}", span, mir.basic_blocks().len()); + for block in mir.basic_blocks() { + for stmt in block.statements.iter() { + use rustc::mir::StatementKind::{StorageDead, StorageLive}; + match stmt.kind { + StorageLive(local) | + StorageDead(local) => locals[local] = None, + _ => {} + } } } - } - }, - } + }, + } + locals + } else { + // don't allocate at all for trivial constants + IndexVec::new() + }; self.stack.push(Frame { mir, From ee67e14034438972c5aae46f8773fe69f20f14aa Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 10:57:28 +0100 Subject: [PATCH 39/48] Stabilize the copy_closures and clone_closures features In addition to the `Fn*` family of traits, closures now implement `Copy` (and similarly `Clone`) if all of the captures do. --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/lib.rs | 2 +- src/librustc/traits/select.rs | 8 ++---- src/librustc/ty/context.rs | 8 ------ src/librustc/ty/maps/config.rs | 12 --------- src/librustc/ty/maps/mod.rs | 3 --- src/librustc/ty/maps/plumbing.rs | 2 -- src/librustc_metadata/cstore.rs | 10 ------- src/librustc_metadata/cstore_impl.rs | 3 --- src/librustc_typeck/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 26 +++---------------- src/test/compile-fail/not-clone-closure.rs | 2 -- src/test/compile-fail/not-copy-closure.rs | 3 --- .../unboxed-closer-non-implicit-copyable.rs | 19 -------------- src/test/run-pass/clone-closure.rs | 2 -- src/test/run-pass/copy-closure.rs | 3 --- src/test/ui/feature-gate-clone-closures.rs | 21 --------------- .../ui/feature-gate-clone-closures.stderr | 11 -------- src/test/ui/feature-gate-copy-closures.rs | 19 -------------- src/test/ui/feature-gate-copy-closures.stderr | 13 ---------- .../borrowck-call-is-borrow-issue-12224.rs | 5 +++- ...borrowck-call-is-borrow-issue-12224.stderr | 8 +++--- 22 files changed, 15 insertions(+), 169 deletions(-) delete mode 100644 src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs delete mode 100644 src/test/ui/feature-gate-clone-closures.rs delete mode 100644 src/test/ui/feature-gate-clone-closures.stderr delete mode 100644 src/test/ui/feature-gate-copy-closures.rs delete mode 100644 src/test/ui/feature-gate-copy-closures.stderr diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1e2e4e5a69fa1..5421d2add2594 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -616,8 +616,6 @@ define_dep_nodes!( <'tcx> [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - [] HasCloneClosures(CrateNum), - [] HasCopyClosures(CrateNum), // This query is not expected to have inputs -- as a result, it's // not a good candidate for "replay" because it's essentially a diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 22b07c8cc044f..a759ce59cb644 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,7 +45,7 @@ #![feature(box_syntax)] #![feature(conservative_impl_trait)] #![feature(const_fn)] -#![feature(copy_closures, clone_closures)] +#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(dyn_trait)] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4db81cf1dec1d..f414374d0083a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2086,12 +2086,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyClosure(def_id, substs) => { let trait_id = obligation.predicate.def_id(); - let copy_closures = - Some(trait_id) == self.tcx().lang_items().copy_trait() && - self.tcx().has_copy_closures(def_id.krate); - let clone_closures = - Some(trait_id) == self.tcx().lang_items().clone_trait() && - self.tcx().has_clone_closures(def_id.krate); + let copy_closures = Some(trait_id) == self.tcx().lang_items().copy_trait(); + let clone_closures = Some(trait_id) == self.tcx().lang_items().clone_trait(); if copy_closures || clone_closures { Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect())) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fd3465f59ebf2..f56d866cba5fb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2520,14 +2520,6 @@ pub fn provide(providers: &mut ty::maps::Providers) { assert_eq!(cnum, LOCAL_CRATE); tcx.output_filenames.clone() }; - providers.has_copy_closures = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.features().copy_closures - }; - providers.has_clone_closures = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - tcx.features().clone_closures - }; providers.features_query = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); Lrc::new(tcx.sess.features_untracked().clone()) diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 117d921931235..400bc6ba41518 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -604,24 +604,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::has_clone_closures<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("seeing if the crate has enabled `Clone` closures") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> { fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String { format!("finding all methods for trait {}", tcx.item_path_str(key.def_id())) } } -impl<'tcx> QueryDescription<'tcx> for queries::has_copy_closures<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("seeing if the crate has enabled `Copy` closures") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("looking up enabled feature gates") diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 6c3b4efb932ad..95e00418658bf 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -382,9 +382,6 @@ define_maps! { <'tcx> [] fn output_filenames: output_filenames_node(CrateNum) -> Arc, - [] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool, - [] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool, - // Erases regions from `ty` to yield a new type. // Normally you would just use `tcx.erase_regions(&value)`, // however, which uses this query as a kind of cache. diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 4170fa7679716..d9caf94ed7f60 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -917,8 +917,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, } DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); } DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); } - DepKind::HasCloneClosures => { force!(has_clone_closures, krate!()); } - DepKind::HasCopyClosures => { force!(has_copy_closures, krate!()); } DepKind::Freevars => { force!(freevars, def_id!()); } DepKind::MaybeUnusedTraitImport => { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index bd5ad93946e3c..b9623f2854055 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -228,16 +228,6 @@ impl CrateMetadata { attr::contains_name(&attrs, "no_builtins") } - pub fn has_copy_closures(&self, sess: &Session) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); - attr::contains_feature_attr(&attrs, "copy_closures") - } - - pub fn has_clone_closures(&self, sess: &Session) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX, sess); - attr::contains_feature_attr(&attrs, "clone_closures") - } - pub fn panic_strategy(&self) -> PanicStrategy { self.root.panic_strategy.clone() } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2de27f3a1c3ea..f02a1831db223 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -256,9 +256,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, used_crate_source => { Lrc::new(cdata.source.clone()) } - has_copy_closures => { cdata.has_copy_closures(tcx.sess) } - has_clone_closures => { cdata.has_clone_closures(tcx.sess) } - exported_symbols => { let cnum = cdata.cnum; assert!(cnum != LOCAL_CRATE); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9f98932f24b52..8a1d87fe1ea78 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -76,7 +76,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![feature(copy_closures, clone_closures)] +#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] #![feature(match_default_bindings)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 915396d29fe26..73d088fb58541 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -391,10 +391,6 @@ declare_features! ( // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109), None), - // Copy/Clone closures (RFC 2132) - (active, clone_closures, "1.22.0", Some(44490), None), - (active, copy_closures, "1.22.0", Some(44490), None), - // allow `'_` placeholder lifetimes (active, underscore_lifetimes, "1.22.0", Some(44524), None), @@ -556,6 +552,9 @@ declare_features! ( (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // allow `..=` in patterns (RFC 1192) (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + // Copy/Clone closures (RFC 2132) + (accepted, clone_closures, "1.26.0", Some(44490), None), + (accepted, copy_closures, "1.26.0", Some(44490), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1867,8 +1866,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], struct FeatureChecker { proc_macro: Option, custom_attribute: Option, - copy_closures: Option, - clone_closures: Option, } impl FeatureChecker { @@ -1884,14 +1881,6 @@ impl FeatureChecker { if features.custom_attribute { self.custom_attribute = self.custom_attribute.or(Some(span)); } - - if features.copy_closures { - self.copy_closures = self.copy_closures.or(Some(span)); - } - - if features.clone_closures { - self.clone_closures = self.clone_closures.or(Some(span)); - } } fn check(self, handler: &Handler) { @@ -1903,15 +1892,6 @@ impl FeatureChecker { FatalError.raise(); } - - if let (Some(span), None) = (self.copy_closures, self.clone_closures) { - handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \ - `#![feature(clone_closures)]`") - .span_note(span, "`#![feature(copy_closures)]` declared here") - .emit(); - - FatalError.raise(); - } } } diff --git a/src/test/compile-fail/not-clone-closure.rs b/src/test/compile-fail/not-clone-closure.rs index 2a30dc4fdd49c..967cb3610ca5f 100644 --- a/src/test/compile-fail/not-clone-closure.rs +++ b/src/test/compile-fail/not-clone-closure.rs @@ -10,8 +10,6 @@ // Check that closures do not implement `Clone` if their environment is not `Clone`. -#![feature(clone_closures)] - struct S(i32); fn main() { diff --git a/src/test/compile-fail/not-copy-closure.rs b/src/test/compile-fail/not-copy-closure.rs index 271e6d5fc90fc..10567c5c961a2 100644 --- a/src/test/compile-fail/not-copy-closure.rs +++ b/src/test/compile-fail/not-copy-closure.rs @@ -10,9 +10,6 @@ // Check that closures do not implement `Copy` if their environment is not `Copy`. -#![feature(copy_closures)] -#![feature(clone_closures)] - fn main() { let mut a = 5; let hello = || { diff --git a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs deleted file mode 100644 index 2d55979491981..0000000000000 --- a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.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. - -#![feature(unboxed_closures)] - -fn to_fn_once>(f: F) -> F { f } - -fn main() { - let f = to_fn_once(move|| ()); - f(); - f(); //~ ERROR use of moved value -} diff --git a/src/test/run-pass/clone-closure.rs b/src/test/run-pass/clone-closure.rs index 7f554c77fc4f8..0fe3711d8d32e 100644 --- a/src/test/run-pass/clone-closure.rs +++ b/src/test/run-pass/clone-closure.rs @@ -10,8 +10,6 @@ // Check that closures implement `Clone`. -#![feature(clone_closures)] - #[derive(Clone)] struct S(i32); diff --git a/src/test/run-pass/copy-closure.rs b/src/test/run-pass/copy-closure.rs index 309c83ebd99ac..a211d6fc3a385 100644 --- a/src/test/run-pass/copy-closure.rs +++ b/src/test/run-pass/copy-closure.rs @@ -10,9 +10,6 @@ // Check that closures implement `Copy`. -#![feature(copy_closures)] -#![feature(clone_closures)] - fn call T>(f: F) -> T { f() } fn main() { diff --git a/src/test/ui/feature-gate-clone-closures.rs b/src/test/ui/feature-gate-clone-closures.rs deleted file mode 100644 index a15153ea7bf0a..0000000000000 --- a/src/test/ui/feature-gate-clone-closures.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -#[derive(Clone)] -struct S(i32); - -fn main() { - let a = S(5); - let hello = move || { - println!("Hello {}", a.0); - }; - - let hello = hello.clone(); //~ ERROR no method named `clone` found for type -} diff --git a/src/test/ui/feature-gate-clone-closures.stderr b/src/test/ui/feature-gate-clone-closures.stderr deleted file mode 100644 index 7038a76380d6b..0000000000000 --- a/src/test/ui/feature-gate-clone-closures.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0599]: no method named `clone` found for type `[closure@$DIR/feature-gate-clone-closures.rs:16:17: 18:6 a:_]` in the current scope - --> $DIR/feature-gate-clone-closures.rs:20:23 - | -LL | let hello = hello.clone(); //~ ERROR no method named `clone` found for type - | ^^^^^ - | - = note: hello is a function, perhaps you wish to call it - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/feature-gate-copy-closures.rs b/src/test/ui/feature-gate-copy-closures.rs deleted file mode 100644 index b11b09eb9fd9b..0000000000000 --- a/src/test/ui/feature-gate-copy-closures.rs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -fn main() { - let a = 5; - let hello = || { - println!("Hello {}", a); - }; - - let b = hello; - let c = hello; //~ ERROR use of moved value: `hello` [E0382] -} diff --git a/src/test/ui/feature-gate-copy-closures.stderr b/src/test/ui/feature-gate-copy-closures.stderr deleted file mode 100644 index e72680b69eaea..0000000000000 --- a/src/test/ui/feature-gate-copy-closures.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0382]: use of moved value: `hello` - --> $DIR/feature-gate-copy-closures.rs:18:9 - | -LL | let b = hello; - | - value moved here -LL | let c = hello; //~ ERROR use of moved value: `hello` [E0382] - | ^ value used here after move - | - = note: move occurs because `hello` has type `[closure@$DIR/feature-gate-copy-closures.rs:13:17: 15:6 a:&i32]`, which does not implement the `Copy` trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index 8e03c303e54d7..e8227971691e9 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -58,7 +58,10 @@ fn test6() { fn test7() { fn foo(_: F) where F: FnMut(Box, isize) {} - let mut f = |g: Box, b: isize| {}; + let s = String::new(); // Capture to make f !Copy + let mut f = move |g: Box, b: isize| { + let _ = s.len(); + }; f(Box::new(|a| { foo(f); //~^ ERROR cannot move `f` into closure because it is borrowed diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 318b77dedcba4..2e7e1e0744141 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -28,7 +28,7 @@ LL | f.f.call_mut(()) | ^^^ cannot borrow as mutable error[E0504]: cannot move `f` into closure because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 | LL | f(Box::new(|a| { | - borrow of `f` occurs here @@ -36,11 +36,11 @@ LL | foo(f); | ^ move into closure occurs here error[E0507]: cannot move out of captured outer variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 | -LL | let mut f = |g: Box, b: isize| {}; +LL | let mut f = move |g: Box, b: isize| { | ----- captured outer variable -LL | f(Box::new(|a| { +... LL | foo(f); | ^ cannot move out of captured outer variable in an `FnMut` closure From f9019aee5bc2f84b69771dc4e2e0cfad5e053566 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 23 Mar 2018 12:44:33 +0100 Subject: [PATCH 40/48] Simplify local accessors --- src/librustc_mir/interpret/eval_context.rs | 14 ++++++-------- src/librustc_mir/interpret/step.rs | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index db4c8f706ba7b..b8bfcd756cd23 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -17,6 +17,7 @@ use rustc::mir::interpret::{ GlobalId, Value, Pointer, PrimVal, PrimValKind, EvalError, EvalResult, EvalErrorKind, MemoryPointer, }; +use std::mem; use super::{Place, PlaceExtra, Memory, HasMemory, MemoryKind, @@ -1704,20 +1705,17 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> { } } - pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { + pub fn storage_live(&mut self, local: mir::Local) -> Option { trace!("{:?} is now live", local); - let old = self.locals[local]; - self.locals[local] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored - return Ok(old); + // StorageLive *always* kills the value that's currently stored + mem::replace(&mut self.locals[local], Some(Value::ByVal(PrimVal::Undef))) } /// Returns the old value of the local - pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { + pub fn storage_dead(&mut self, local: mir::Local) -> Option { trace!("{:?} is now dead", local); - let old = self.locals[local]; - self.locals[local] = None; - return Ok(old); + self.locals[local].take() } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 4e1750caf26ba..752c94dec2087 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -69,13 +69,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { // Mark locals as alive StorageLive(local) => { - let old_val = self.frame_mut().storage_live(local)?; + let old_val = self.frame_mut().storage_live(local); self.deallocate_local(old_val)?; } // Mark locals as dead StorageDead(local) => { - let old_val = self.frame_mut().storage_dead(local)?; + let old_val = self.frame_mut().storage_dead(local); self.deallocate_local(old_val)?; } From 00721de714785a8abf95a6403a66a19de6a58fc3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 11:37:11 +0100 Subject: [PATCH 41/48] Mention closures in docs for Clone and Copy --- src/libcore/clone.rs | 5 +++++ src/libcore/marker.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 826420a0c001c..d25f498b99efe 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -63,6 +63,11 @@ /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d /// implementation of [`clone`] calls [`clone`] on each field. /// +/// ## Closures +/// +/// Closure types automatically implement `Clone` if they capture no value from the environment +/// or if all such captured values implement `Clone` themselves. +/// /// ## How can I implement `Clone`? /// /// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally: diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f8a33961811c0..7d0174a178abf 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -166,6 +166,11 @@ pub trait Unsize { /// are allowed to access `x` after the assignment. Under the hood, both a copy and a move /// can result in bits being copied in memory, although this is sometimes optimized away. /// +/// ## Closures +/// +/// Closure types automatically implement `Copy` if they capture no value from the environment +/// or if all such captured values implement `Copy` themselves. +/// /// ## How can I implement `Copy`? /// /// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: From 1efe0b34813650fd0715732b6ffa1fff1e60e05f Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 19:02:14 +0100 Subject: [PATCH 42/48] =?UTF-8?q?Rename=20variables=20in=20rustc=E2=80=99s?= =?UTF-8?q?=20SelectionContext::copy=5Fclone=5Fconditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc/traits/select.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f414374d0083a..11daa96134c59 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2086,10 +2086,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyClosure(def_id, substs) => { let trait_id = obligation.predicate.def_id(); - let copy_closures = Some(trait_id) == self.tcx().lang_items().copy_trait(); - let clone_closures = Some(trait_id) == self.tcx().lang_items().clone_trait(); - - if copy_closures || clone_closures { + let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait(); + let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait(); + if is_copy_trait || is_clone_trait { Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect())) } else { Never From 90588a9086270ecaebe1dab6bcff1dcbacfe1c0e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 23 Mar 2018 21:27:15 +0100 Subject: [PATCH 43/48] Fix IE11 search --- src/librustdoc/html/static/main.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 21c1d9d670d65..6c6c067f95189 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -49,6 +49,13 @@ var themesWidth = null; + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(searchString, position) { + position = position || 0; + return this.indexOf(searchString, position) === position; + }; + } + function hasClass(elem, className) { if (elem && className && elem.className) { var elemClass = elem.className; From 700fd5acd063286156d3409bb26152e9174158c3 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 23 Mar 2018 15:02:59 -0600 Subject: [PATCH 44/48] Remove getopts leftover from tree This was attempted but left incomplete in PR #42664, where only the toml file was removed. --- src/libgetopts/lib.rs | 1622 ----------------------------------------- 1 file changed, 1622 deletions(-) delete mode 100644 src/libgetopts/lib.rs diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs deleted file mode 100644 index 81fa0374f549e..0000000000000 --- a/src/libgetopts/lib.rs +++ /dev/null @@ -1,1622 +0,0 @@ -// Copyright 2012-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. - -//! Simple getopt alternative. -//! -//! Construct a vector of options, either by using `reqopt`, `optopt`, and `optflag` -//! or by building them from components yourself, and pass them to `getopts`, -//! along with a vector of actual arguments (not including `argv[0]`). You'll -//! either get a failure code back, or a match. You'll have to verify whether -//! the amount of 'free' arguments in the match is what you expect. Use `opt_*` -//! accessors to get argument values out of the matches object. -//! -//! Single-character options are expected to appear on the command line with a -//! single preceding dash; multiple-character options are expected to be -//! proceeded by two dashes. Options that expect an argument accept their -//! argument following either a space or an equals sign. Single-character -//! options don't require the space. -//! -//! # Example -//! -//! The following example shows simple command line parsing for an application -//! that requires an input file to be specified, accepts an optional output -//! file name following `-o`, and accepts both `-h` and `--help` as optional flags. -//! -//! ```{.rust} -//! #![feature(rustc_private)] -//! -//! extern crate getopts; -//! use getopts::{optopt,optflag,getopts,OptGroup,usage}; -//! use std::env; -//! -//! fn do_work(inp: &str, out: Option) { -//! println!("{}", inp); -//! match out { -//! Some(x) => println!("{}", x), -//! None => println!("No Output"), -//! } -//! } -//! -//! fn print_usage(program: &str, opts: &[OptGroup]) { -//! let brief = format!("Usage: {} [options]", program); -//! print!("{}", usage(&brief, opts)); -//! } -//! -//! fn main() { -//! let args: Vec = env::args().collect(); -//! -//! let program = args[0].clone(); -//! -//! let opts = &[ -//! optopt("o", "", "set output file name", "NAME"), -//! optflag("h", "help", "print this help menu") -//! ]; -//! let matches = match getopts(&args[1..], opts) { -//! Ok(m) => { m } -//! Err(f) => { panic!(f.to_string()) } -//! }; -//! if matches.opt_present("h") { -//! print_usage(&program, opts); -//! return; -//! } -//! let output = matches.opt_str("o"); -//! let input = if !matches.free.is_empty() { -//! matches.free[0].clone() -//! } else { -//! print_usage(&program, opts); -//! return; -//! }; -//! do_work(&input, output); -//! } -//! ``` - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] - -#![deny(missing_docs)] -#![deny(warnings)] - -use self::Name::*; -use self::HasArg::*; -use self::Occur::*; -use self::Fail::*; -use self::Optval::*; -use self::SplitWithinState::*; -use self::Whitespace::*; -use self::LengthLimit::*; - -use std::fmt; -use std::iter::repeat; -use std::result; - -/// Name of an option. Either a string or a single char. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Name { - /// A string representing the long name of an option. - /// For example: "help" - Long(String), - /// A char representing the short name of an option. - /// For example: 'h' - Short(char), -} - -/// Describes whether an option has an argument. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum HasArg { - /// The option requires an argument. - Yes, - /// The option takes no argument. - No, - /// The option argument is optional. - Maybe, -} - -/// Describes how often an option may occur. -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Occur { - /// The option occurs once. - Req, - /// The option occurs at most once. - Optional, - /// The option occurs zero or more times. - Multi, -} - -/// A description of a possible option. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Opt { - /// Name of the option - pub name: Name, - /// Whether it has an argument - pub hasarg: HasArg, - /// How often it can occur - pub occur: Occur, - /// Which options it aliases - pub aliases: Vec, -} - -/// One group of options, e.g., both `-h` and `--help`, along with -/// their shared description and properties. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct OptGroup { - /// Short name of the option, e.g. `h` for a `-h` option - pub short_name: String, - /// Long name of the option, e.g. `help` for a `--help` option - pub long_name: String, - /// Hint for argument, e.g. `FILE` for a `-o FILE` option - pub hint: String, - /// Description for usage help text - pub desc: String, - /// Whether option has an argument - pub hasarg: HasArg, - /// How often it can occur - pub occur: Occur, -} - -/// Describes whether an option is given at all or has a value. -#[derive(Clone, PartialEq, Eq, Debug)] -enum Optval { - Val(String), - Given, -} - -/// The result of checking command line arguments. Contains a vector -/// of matches and a vector of free strings. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Matches { - /// Options that matched - opts: Vec, - /// Values of the Options that matched - vals: Vec>, - /// Free string fragments - pub free: Vec, -} - -/// The type returned when the command line does not conform to the -/// expected format. Use the `Debug` implementation to output detailed -/// information. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Fail { - /// The option requires an argument but none was passed. - ArgumentMissing(String), - /// The passed option is not declared among the possible options. - UnrecognizedOption(String), - /// A required option is not present. - OptionMissing(String), - /// A single occurrence option is being used multiple times. - OptionDuplicated(String), - /// There's an argument being passed to a non-argument option. - UnexpectedArgument(String), -} - -/// The type of failure that occurred. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[allow(missing_docs)] -pub enum FailType { - ArgumentMissing_, - UnrecognizedOption_, - OptionMissing_, - OptionDuplicated_, - UnexpectedArgument_, -} - -/// The result of parsing a command line with a set of options. -pub type Result = result::Result; - -impl Name { - fn from_str(nm: &str) -> Name { - if nm.len() == 1 { - Short(nm.chars().next().unwrap()) - } else { - Long(nm.to_owned()) - } - } - - fn to_string(&self) -> String { - match *self { - Short(ch) => ch.to_string(), - Long(ref s) => s.to_owned(), - } - } -} - -impl OptGroup { - /// Translate OptGroup into Opt. - /// (Both short and long names correspond to different Opts). - pub fn long_to_short(&self) -> Opt { - let OptGroup { - short_name, - long_name, - hasarg, - occur, - .. - } = (*self).clone(); - - match (short_name.len(), long_name.len()) { - (0, 0) => panic!("this long-format option was given no name"), - (0, _) => { - Opt { - name: Long((long_name)), - hasarg, - occur, - aliases: Vec::new(), - } - } - (1, 0) => { - Opt { - name: Short(short_name.chars().next().unwrap()), - hasarg, - occur, - aliases: Vec::new(), - } - } - (1, _) => { - Opt { - name: Long((long_name)), - hasarg, - occur, - aliases: vec![Opt { - name: Short(short_name.chars().next().unwrap()), - hasarg, - occur, - aliases: Vec::new(), - }], - } - } - _ => panic!("something is wrong with the long-form opt"), - } - } -} - -impl Matches { - fn opt_vals(&self, nm: &str) -> Vec { - match find_opt(&self.opts[..], Name::from_str(nm)) { - Some(id) => self.vals[id].clone(), - None => panic!("No option '{}' defined", nm), - } - } - - fn opt_val(&self, nm: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - None - } else { - Some(vals[0].clone()) - } - } - - /// Returns true if an option was matched. - pub fn opt_present(&self, nm: &str) -> bool { - !self.opt_vals(nm).is_empty() - } - - /// Returns the number of times an option was matched. - pub fn opt_count(&self, nm: &str) -> usize { - self.opt_vals(nm).len() - } - - /// Returns true if any of several options were matched. - pub fn opts_present(&self, names: &[String]) -> bool { - for nm in names { - match find_opt(&self.opts, Name::from_str(&**nm)) { - Some(id) if !self.vals[id].is_empty() => return true, - _ => (), - }; - } - false - } - - /// Returns the string argument supplied to one of several matching options or `None`. - pub fn opts_str(&self, names: &[String]) -> Option { - for nm in names { - if let Some(Val(ref s)) = self.opt_val(&nm[..]) { - return Some(s.clone()) - } - } - None - } - - /// Returns a vector of the arguments provided to all matches of the given - /// option. - /// - /// Used when an option accepts multiple values. - pub fn opt_strs(&self, nm: &str) -> Vec { - let mut acc: Vec = Vec::new(); - let r = self.opt_vals(nm); - for v in &r { - match *v { - Val(ref s) => acc.push((*s).clone()), - _ => (), - } - } - acc - } - - /// Returns the string argument supplied to a matching option or `None`. - pub fn opt_str(&self, nm: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - return None::; - } - match vals[0] { - Val(ref s) => Some((*s).clone()), - _ => None, - } - } - - - /// Returns the matching string, a default, or none. - /// - /// Returns none if the option was not present, `def` if the option was - /// present but no argument was provided, and the argument if the option was - /// present and an argument was provided. - pub fn opt_default(&self, nm: &str, def: &str) -> Option { - let vals = self.opt_vals(nm); - if vals.is_empty() { - None - } else { - match vals[0] { - Val(ref s) => Some((*s).clone()), - _ => Some(def.to_owned()), - } - } - } -} - -fn is_arg(arg: &str) -> bool { - arg.len() > 1 && arg.as_bytes()[0] == b'-' -} - -fn find_opt(opts: &[Opt], nm: Name) -> Option { - // Search main options. - let pos = opts.iter().position(|opt| opt.name == nm); - if pos.is_some() { - return pos; - } - - // Search in aliases. - for candidate in opts { - if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { - return opts.iter().position(|opt| opt.name == candidate.name); - } - } - - None -} - -/// Create a long option that is required and takes an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: hint.to_owned(), - desc: desc.to_owned(), - hasarg: Yes, - occur: Req, - } -} - -/// Create a long option that is optional and takes an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: hint.to_owned(), - desc: desc.to_owned(), - hasarg: Yes, - occur: Optional, - } -} - -/// Create a long option that is optional and does not take an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: "".to_owned(), - desc: desc.to_owned(), - hasarg: No, - occur: Optional, - } -} - -/// Create a long option that can occur more than once and does not -/// take an argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: "".to_owned(), - desc: desc.to_owned(), - hasarg: No, - occur: Multi, - } -} - -/// Create a long option that is optional and takes an optional argument. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: hint.to_owned(), - desc: desc.to_owned(), - hasarg: Maybe, - occur: Optional, - } -} - -/// Create a long option that is optional, takes an argument, and may occur -/// multiple times. -/// -/// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none -/// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none -/// * `desc` - Description for usage help -/// * `hint` - Hint that is used in place of the argument in the usage help, -/// e.g. `"FILE"` for a `-o FILE` option -pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: hint.to_owned(), - desc: desc.to_owned(), - hasarg: Yes, - occur: Multi, - } -} - -/// Create a generic option group, stating all parameters explicitly -pub fn opt(short_name: &str, - long_name: &str, - desc: &str, - hint: &str, - hasarg: HasArg, - occur: Occur) - -> OptGroup { - let len = short_name.len(); - assert!(len == 1 || len == 0); - OptGroup { - short_name: short_name.to_owned(), - long_name: long_name.to_owned(), - hint: hint.to_owned(), - desc: desc.to_owned(), - hasarg, - occur, - } -} - -impl fmt::Display for Fail { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ArgumentMissing(ref nm) => write!(f, "Argument to option '{}' missing.", *nm), - UnrecognizedOption(ref nm) => write!(f, "Unrecognized option: '{}'.", *nm), - OptionMissing(ref nm) => write!(f, "Required option '{}' missing.", *nm), - OptionDuplicated(ref nm) => write!(f, "Option '{}' given more than once.", *nm), - UnexpectedArgument(ref nm) => write!(f, "Option '{}' does not take an argument.", *nm), - } - } -} - -/// Parse command line arguments according to the provided options. -/// -/// On success returns `Ok(Matches)`. Use methods such as `opt_present` -/// `opt_str`, etc. to interrogate results. -/// # Panics -/// -/// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` to display -/// information about it. -pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { - let opts: Vec = optgrps.iter().map(|x| x.long_to_short()).collect(); - let n_opts = opts.len(); - - fn f(_x: usize) -> Vec { - Vec::new() - } - - let mut vals: Vec<_> = (0..n_opts).map(f).collect(); - let mut free: Vec = Vec::new(); - let l = args.len(); - let mut i = 0; - while i < l { - let cur = args[i].clone(); - let curlen = cur.len(); - if !is_arg(&cur[..]) { - free.push(cur); - } else if cur == "--" { - let mut j = i + 1; - while j < l { - free.push(args[j].clone()); - j += 1; - } - break; - } else { - let mut names; - let mut i_arg = None; - if cur.as_bytes()[1] == b'-' { - let tail = &cur[2..curlen]; - let tail_eq: Vec<&str> = tail.splitn(2, '=').collect(); - if tail_eq.len() <= 1 { - names = vec![Long(tail.to_owned())]; - } else { - names = vec![Long(tail_eq[0].to_owned())]; - i_arg = Some(tail_eq[1].to_owned()); - } - } else { - let mut j = 1; - names = Vec::new(); - while j < curlen { - let ch = cur[j..].chars().next().unwrap(); - let opt = Short(ch); - - // In a series of potential options (eg. -aheJ), if we - // see one which takes an argument, we assume all - // subsequent characters make up the argument. This - // allows options such as -L/usr/local/lib/foo to be - // interpreted correctly - - let opt_id = match find_opt(&opts, opt.clone()) { - Some(id) => id, - None => return Err(UnrecognizedOption(opt.to_string())), - }; - - names.push(opt); - - let arg_follows = match opts[opt_id].hasarg { - Yes | Maybe => true, - No => false, - }; - - let next = j + ch.len_utf8(); - if arg_follows && next < curlen { - i_arg = Some((&cur[next..curlen]).to_owned()); - break; - } - - j = next; - } - } - let mut name_pos = 0; - for nm in &names { - name_pos += 1; - let optid = match find_opt(&opts, (*nm).clone()) { - Some(id) => id, - None => return Err(UnrecognizedOption(nm.to_string())), - }; - match opts[optid].hasarg { - No => { - if name_pos == names.len() && !i_arg.is_none() { - return Err(UnexpectedArgument(nm.to_string())); - } - let v = &mut vals[optid]; - v.push(Given); - } - Maybe => { - if !i_arg.is_none() { - let v = &mut vals[optid]; - v.push(Val((i_arg.clone()).unwrap())); - } else if name_pos < names.len() || i + 1 == l || is_arg(&args[i + 1][..]) { - let v = &mut vals[optid]; - v.push(Given); - } else { - i += 1; - let v = &mut vals[optid]; - v.push(Val(args[i].clone())); - } - } - Yes => { - if !i_arg.is_none() { - let v = &mut vals[optid]; - v.push(Val(i_arg.clone().unwrap())); - } else if i + 1 == l { - return Err(ArgumentMissing(nm.to_string())); - } else { - i += 1; - let v = &mut vals[optid]; - v.push(Val(args[i].clone())); - } - } - } - } - } - i += 1; - } - for i in 0..n_opts { - let n = vals[i].len(); - let occ = opts[i].occur; - if occ == Req && n == 0 { - return Err(OptionMissing(opts[i].name.to_string())); - } - if occ != Multi && n > 1 { - return Err(OptionDuplicated(opts[i].name.to_string())); - } - } - Ok(Matches { - opts, - vals, - free, - }) -} - -/// Derive a usage message from a set of long options. -pub fn usage(brief: &str, opts: &[OptGroup]) -> String { - - let desc_sep = format!("\n{}", repeat(" ").take(24).collect::()); - - let rows = opts.iter().map(|optref| { - let OptGroup{short_name, - long_name, - hint, - desc, - hasarg, - ..} = (*optref).clone(); - - let mut row = repeat(" ").take(4).collect::(); - - // short option - match short_name.len() { - 0 => {} - 1 => { - row.push('-'); - row.push_str(&short_name[..]); - row.push(' '); - } - _ => panic!("the short name should only be 1 ascii char long"), - } - - // long option - match long_name.len() { - 0 => {} - _ => { - row.push_str("--"); - row.push_str(&long_name[..]); - row.push(' '); - } - } - - // arg - match hasarg { - No => {} - Yes => row.push_str(&hint[..]), - Maybe => { - row.push('['); - row.push_str(&hint[..]); - row.push(']'); - } - } - - // FIXME(https://github.com/rust-lang-nursery/getopts/issues/7) - // should be graphemes not codepoints - // - // here we just need to indent the start of the description - let rowlen = row.chars().count(); - if rowlen < 24 { - for _ in 0..24 - rowlen { - row.push(' '); - } - } else { - row.push_str(&desc_sep[..]); - } - - // Normalize desc to contain words separated by one space character - let mut desc_normalized_whitespace = String::new(); - for word in desc.split_whitespace() { - desc_normalized_whitespace.push_str(word); - desc_normalized_whitespace.push(' '); - } - - // FIXME(https://github.com/rust-lang-nursery/getopts/issues/7) - // should be graphemes not codepoints - let mut desc_rows = Vec::new(); - each_split_within(&desc_normalized_whitespace[..], 54, |substr| { - desc_rows.push(substr.to_owned()); - true - }); - - // FIXME(https://github.com/rust-lang-nursery/getopts/issues/7) - // should be graphemes not codepoints - // - // wrapped description - row.push_str(&desc_rows.join(&desc_sep[..])); - - row - }); - - format!("{}\n\nOptions:\n{}\n", - brief, - rows.collect::>().join("\n")) -} - -fn format_option(opt: &OptGroup) -> String { - let mut line = String::new(); - - if opt.occur != Req { - line.push('['); - } - - // Use short_name is possible, but fallback to long_name. - if !opt.short_name.is_empty() { - line.push('-'); - line.push_str(&opt.short_name[..]); - } else { - line.push_str("--"); - line.push_str(&opt.long_name[..]); - } - - if opt.hasarg != No { - line.push(' '); - if opt.hasarg == Maybe { - line.push('['); - } - line.push_str(&opt.hint[..]); - if opt.hasarg == Maybe { - line.push(']'); - } - } - - if opt.occur != Req { - line.push(']'); - } - if opt.occur == Multi { - line.push_str(".."); - } - - line -} - -/// Derive a short one-line usage summary from a set of long options. -pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { - let mut line = format!("Usage: {} ", program_name); - line.push_str(&opts.iter() - .map(format_option) - .collect::>() - .join(" ")[..]); - line -} - -#[derive(Copy, Clone)] -enum SplitWithinState { - A, // leading whitespace, initial state - B, // words - C, // internal and trailing whitespace -} -#[derive(Copy, Clone)] -enum Whitespace { - Ws, // current char is whitespace - Cr, // current char is not whitespace -} -#[derive(Copy, Clone)] -enum LengthLimit { - UnderLim, // current char makes current substring still fit in limit - OverLim, // current char makes current substring no longer fit in limit -} - - -/// Splits a string into substrings with possibly internal whitespace, -/// each of them at most `lim` bytes long. The substrings have leading and trailing -/// whitespace removed, and are only cut at whitespace boundaries. -/// -/// Note: Function was moved here from `std::str` because this module is the only place that -/// uses it, and because it was too specific for a general string function. -/// -/// # Panics -/// -/// Panics during iteration if the string contains a non-whitespace -/// sequence longer than the limit. -fn each_split_within(ss: &str, lim: usize, mut it: F) -> bool - where F: FnMut(&str) -> bool -{ - // Just for fun, let's write this as a state machine: - - let mut slice_start = 0; - let mut last_start = 0; - let mut last_end = 0; - let mut state = A; - let mut fake_i = ss.len(); - let mut lim = lim; - - let mut cont = true; - - // if the limit is larger than the string, lower it to save cycles - if lim >= fake_i { - lim = fake_i; - } - - let mut machine = |cont: &mut bool, (i, c): (usize, char)| -> bool { - let whitespace = if c.is_whitespace() { - Ws - } else { - Cr - }; - let limit = if (i - slice_start + 1) <= lim { - UnderLim - } else { - OverLim - }; - - state = match (state, whitespace, limit) { - (A, Ws, _) => A, - (A, Cr, _) => { - slice_start = i; - last_start = i; - B - } - - (B, Cr, UnderLim) => B, - (B, Cr, OverLim) if (i - last_start + 1) > lim => { - panic!("word starting with {} longer than limit!", - &ss[last_start..i + 1]) - } - (B, Cr, OverLim) => { - *cont = it(&ss[slice_start..last_end]); - slice_start = last_start; - B - } - (B, Ws, UnderLim) => { - last_end = i; - C - } - (B, Ws, OverLim) => { - last_end = i; - *cont = it(&ss[slice_start..last_end]); - A - } - - (C, Cr, UnderLim) => { - last_start = i; - B - } - (C, Cr, OverLim) => { - *cont = it(&ss[slice_start..last_end]); - slice_start = i; - last_start = i; - last_end = i; - B - } - (C, Ws, OverLim) => { - *cont = it(&ss[slice_start..last_end]); - A - } - (C, Ws, UnderLim) => C, - }; - - *cont - }; - - ss.char_indices().all(|x| machine(&mut cont, x)); - - // Let the automaton 'run out' by supplying trailing whitespace - while cont && - match state { - B | C => true, - A => false, - } { - machine(&mut cont, (fake_i, ' ')); - fake_i += 1; - } - cont -} - -#[test] -fn test_split_within() { - fn t(s: &str, i: usize, u: &[String]) { - let mut v = Vec::new(); - each_split_within(s, i, |s| { - v.push(s.to_string()); - true - }); - assert!(v.iter().zip(u).all(|(a, b)| a == b)); - } - t("", 0, &[]); - t("", 15, &[]); - t("hello", 15, &["hello".to_string()]); - t("\nMary had a little lamb\nLittle lamb\n", - 15, - &["Mary had a".to_string(), "little lamb".to_string(), "Little lamb".to_string()]); - t("\nMary had a little lamb\nLittle lamb\n", - ::std::usize::MAX, - &["Mary had a little lamb\nLittle lamb".to_string()]); -} - -#[cfg(test)] -mod tests { - use super::*; - - use std::result::Result::{Err, Ok}; - use std::result; - - // Tests for reqopt - #[test] - fn test_reqopt() { - let long_args = vec!["--test=20".to_string()]; - let opts = vec![reqopt("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Ok(ref m) => { - assert!(m.opt_present("test")); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!(m.opt_present("t")); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => { - panic!("test_reqopt failed (long arg)"); - } - } - let short_args = vec!["-t".to_string(), "20".to_string()]; - match getopts(&short_args, &opts) { - Ok(ref m) => { - assert!((m.opt_present("test"))); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!((m.opt_present("t"))); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => { - panic!("test_reqopt failed (short arg)"); - } - } - } - - #[test] - fn test_reqopt_missing() { - let args = vec!["blah".to_string()]; - let opts = vec![reqopt("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Err(OptionMissing(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_reqopt_no_arg() { - let long_args = vec!["--test".to_string()]; - let opts = vec![reqopt("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - let short_args = vec!["-t".to_string()]; - match getopts(&short_args, &opts) { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_reqopt_multi() { - let args = vec!["--test=20".to_string(), "-t".to_string(), "30".to_string()]; - let opts = vec![reqopt("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Err(OptionDuplicated(_)) => {} - _ => panic!(), - } - } - - // Tests for optopt - #[test] - fn test_optopt() { - let long_args = vec!["--test=20".to_string()]; - let opts = vec![optopt("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Ok(ref m) => { - assert!(m.opt_present("test")); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!((m.opt_present("t"))); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => panic!(), - } - let short_args = vec!["-t".to_string(), "20".to_string()]; - match getopts(&short_args, &opts) { - Ok(ref m) => { - assert!((m.opt_present("test"))); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!((m.opt_present("t"))); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => panic!(), - } - } - - #[test] - fn test_optopt_missing() { - let args = vec!["blah".to_string()]; - let opts = vec![optopt("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert!(!m.opt_present("test")); - assert!(!m.opt_present("t")); - } - _ => panic!(), - } - } - - #[test] - fn test_optopt_no_arg() { - let long_args = vec!["--test".to_string()]; - let opts = vec![optopt("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - let short_args = vec!["-t".to_string()]; - match getopts(&short_args, &opts) { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_optopt_multi() { - let args = vec!["--test=20".to_string(), "-t".to_string(), "30".to_string()]; - let opts = vec![optopt("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Err(OptionDuplicated(_)) => {} - _ => panic!(), - } - } - - // Tests for optflag - #[test] - fn test_optflag() { - let long_args = vec!["--test".to_string()]; - let opts = vec![optflag("t", "test", "testing")]; - let rs = getopts(&long_args, &opts); - match rs { - Ok(ref m) => { - assert!(m.opt_present("test")); - assert!(m.opt_present("t")); - } - _ => panic!(), - } - let short_args = vec!["-t".to_string()]; - match getopts(&short_args, &opts) { - Ok(ref m) => { - assert!(m.opt_present("test")); - assert!(m.opt_present("t")); - } - _ => panic!(), - } - } - - #[test] - fn test_optflag_missing() { - let args = vec!["blah".to_string()]; - let opts = vec![optflag("t", "test", "testing")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert!(!m.opt_present("test")); - assert!(!m.opt_present("t")); - } - _ => panic!(), - } - } - - #[test] - fn test_optflag_long_arg() { - let args = vec!["--test=20".to_string()]; - let opts = vec![optflag("t", "test", "testing")]; - let rs = getopts(&args, &opts); - match rs { - Err(UnexpectedArgument(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_optflag_multi() { - let args = vec!["--test".to_string(), "-t".to_string()]; - let opts = vec![optflag("t", "test", "testing")]; - let rs = getopts(&args, &opts); - match rs { - Err(OptionDuplicated(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_optflag_short_arg() { - let args = vec!["-t".to_string(), "20".to_string()]; - let opts = vec![optflag("t", "test", "testing")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - // The next variable after the flag is just a free argument - - assert!(m.free[0] == "20"); - } - _ => panic!(), - } - } - - // Tests for optflagmulti - #[test] - fn test_optflagmulti_short1() { - let args = vec!["-v".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("v"), 1); - } - _ => panic!(), - } - } - - #[test] - fn test_optflagmulti_short2a() { - let args = vec!["-v".to_string(), "-v".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("v"), 2); - } - _ => panic!(), - } - } - - #[test] - fn test_optflagmulti_short2b() { - let args = vec!["-vv".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("v"), 2); - } - _ => panic!(), - } - } - - #[test] - fn test_optflagmulti_long1() { - let args = vec!["--verbose".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("verbose"), 1); - } - _ => panic!(), - } - } - - #[test] - fn test_optflagmulti_long2() { - let args = vec!["--verbose".to_string(), "--verbose".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("verbose"), 2); - } - _ => panic!(), - } - } - - #[test] - fn test_optflagmulti_mix() { - let args = vec!["--verbose".to_string(), - "-v".to_string(), - "-vv".to_string(), - "verbose".to_string()]; - let opts = vec![optflagmulti("v", "verbose", "verbosity")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert_eq!(m.opt_count("verbose"), 4); - assert_eq!(m.opt_count("v"), 4); - } - _ => panic!(), - } - } - - // Tests for optmulti - #[test] - fn test_optmulti() { - let long_args = vec!["--test=20".to_string()]; - let opts = vec![optmulti("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Ok(ref m) => { - assert!((m.opt_present("test"))); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!((m.opt_present("t"))); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => panic!(), - } - let short_args = vec!["-t".to_string(), "20".to_string()]; - match getopts(&short_args, &opts) { - Ok(ref m) => { - assert!((m.opt_present("test"))); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!((m.opt_present("t"))); - assert_eq!(m.opt_str("t").unwrap(), "20"); - } - _ => panic!(), - } - } - - #[test] - fn test_optmulti_missing() { - let args = vec!["blah".to_string()]; - let opts = vec![optmulti("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert!(!m.opt_present("test")); - assert!(!m.opt_present("t")); - } - _ => panic!(), - } - } - - #[test] - fn test_optmulti_no_arg() { - let long_args = vec!["--test".to_string()]; - let opts = vec![optmulti("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - let short_args = vec!["-t".to_string()]; - match getopts(&short_args, &opts) { - Err(ArgumentMissing(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_optmulti_multi() { - let args = vec!["--test=20".to_string(), "-t".to_string(), "30".to_string()]; - let opts = vec![optmulti("t", "test", "testing", "TEST")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert!(m.opt_present("test")); - assert_eq!(m.opt_str("test").unwrap(), "20"); - assert!(m.opt_present("t")); - assert_eq!(m.opt_str("t").unwrap(), "20"); - let pair = m.opt_strs("test"); - assert!(pair[0] == "20"); - assert!(pair[1] == "30"); - } - _ => panic!(), - } - } - - #[test] - fn test_unrecognized_option() { - let long_args = vec!["--untest".to_string()]; - let opts = vec![optmulti("t", "test", "testing", "TEST")]; - let rs = getopts(&long_args, &opts); - match rs { - Err(UnrecognizedOption(_)) => {} - _ => panic!(), - } - let short_args = vec!["-u".to_string()]; - match getopts(&short_args, &opts) { - Err(UnrecognizedOption(_)) => {} - _ => panic!(), - } - } - - #[test] - fn test_combined() { - let args = vec!["prog".to_string(), - "free1".to_string(), - "-s".to_string(), - "20".to_string(), - "free2".to_string(), - "--flag".to_string(), - "--long=30".to_string(), - "-f".to_string(), - "-m".to_string(), - "40".to_string(), - "-m".to_string(), - "50".to_string(), - "-n".to_string(), - "-A B".to_string(), - "-n".to_string(), - "-60 70".to_string()]; - let opts = vec![optopt("s", "something", "something", "SOMETHING"), - optflag("", "flag", "a flag"), - reqopt("", "long", "hi", "LONG"), - optflag("f", "", "another flag"), - optmulti("m", "", "mmmmmm", "YUM"), - optmulti("n", "", "nothing", "NOTHING"), - optopt("", "notpresent", "nothing to see here", "NOPE")]; - let rs = getopts(&args, &opts); - match rs { - Ok(ref m) => { - assert!(m.free[0] == "prog"); - assert!(m.free[1] == "free1"); - assert_eq!(m.opt_str("s").unwrap(), "20"); - assert!(m.free[2] == "free2"); - assert!((m.opt_present("flag"))); - assert_eq!(m.opt_str("long").unwrap(), "30"); - assert!((m.opt_present("f"))); - let pair = m.opt_strs("m"); - assert!(pair[0] == "40"); - assert!(pair[1] == "50"); - let pair = m.opt_strs("n"); - assert!(pair[0] == "-A B"); - assert!(pair[1] == "-60 70"); - assert!((!m.opt_present("notpresent"))); - } - _ => panic!(), - } - } - - #[test] - fn test_multi() { - let opts = vec![optopt("e", "", "encrypt", "ENCRYPT"), - optopt("", "encrypt", "encrypt", "ENCRYPT"), - optopt("f", "", "flag", "FLAG")]; - - let args_single = vec!["-e".to_string(), "foo".to_string()]; - let matches_single = &match getopts(&args_single, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!(), - }; - assert!(matches_single.opts_present(&["e".to_string()])); - assert!(matches_single.opts_present(&["encrypt".to_string(), "e".to_string()])); - assert!(matches_single.opts_present(&["e".to_string(), "encrypt".to_string()])); - assert!(!matches_single.opts_present(&["encrypt".to_string()])); - assert!(!matches_single.opts_present(&["thing".to_string()])); - assert!(!matches_single.opts_present(&[])); - - assert_eq!(matches_single.opts_str(&["e".to_string()]).unwrap(), "foo"); - assert_eq!(matches_single.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(), - "foo"); - assert_eq!(matches_single.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(), - "foo"); - - let args_both = vec!["-e".to_string(), - "foo".to_string(), - "--encrypt".to_string(), - "foo".to_string()]; - let matches_both = &match getopts(&args_both, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!(), - }; - assert!(matches_both.opts_present(&["e".to_string()])); - assert!(matches_both.opts_present(&["encrypt".to_string()])); - assert!(matches_both.opts_present(&["encrypt".to_string(), "e".to_string()])); - assert!(matches_both.opts_present(&["e".to_string(), "encrypt".to_string()])); - assert!(!matches_both.opts_present(&["f".to_string()])); - assert!(!matches_both.opts_present(&["thing".to_string()])); - assert!(!matches_both.opts_present(&[])); - - assert_eq!(matches_both.opts_str(&["e".to_string()]).unwrap(), "foo"); - assert_eq!(matches_both.opts_str(&["encrypt".to_string()]).unwrap(), - "foo"); - assert_eq!(matches_both.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(), - "foo"); - assert_eq!(matches_both.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(), - "foo"); - } - - #[test] - fn test_nospace() { - let args = vec!["-Lfoo".to_string(), "-M.".to_string()]; - let opts = vec![optmulti("L", "", "library directory", "LIB"), - optmulti("M", "", "something", "MMMM")]; - let matches = &match getopts(&args, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(_) => panic!(), - }; - assert!(matches.opts_present(&["L".to_string()])); - assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "foo"); - assert!(matches.opts_present(&["M".to_string()])); - assert_eq!(matches.opts_str(&["M".to_string()]).unwrap(), "."); - - } - - #[test] - fn test_nospace_conflict() { - let args = vec!["-vvLverbose".to_string(), "-v".to_string()]; - let opts = vec![optmulti("L", "", "library directory", "LIB"), - optflagmulti("v", "verbose", "Verbose")]; - let matches = &match getopts(&args, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(e) => panic!("{}", e), - }; - assert!(matches.opts_present(&["L".to_string()])); - assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "verbose"); - assert!(matches.opts_present(&["v".to_string()])); - assert_eq!(3, matches.opt_count("v")); - } - - #[test] - fn test_long_to_short() { - let mut short = Opt { - name: Name::Long("banana".to_string()), - hasarg: HasArg::Yes, - occur: Occur::Req, - aliases: Vec::new(), - }; - short.aliases = vec![Opt { - name: Name::Short('b'), - hasarg: HasArg::Yes, - occur: Occur::Req, - aliases: Vec::new(), - }]; - let verbose = reqopt("b", "banana", "some bananas", "VAL"); - - assert!(verbose.long_to_short() == short); - } - - #[test] - fn test_aliases_long_and_short() { - let opts = vec![optflagmulti("a", "apple", "Desc")]; - - let args = vec!["-a".to_string(), "--apple".to_string(), "-a".to_string()]; - - let matches = getopts(&args, &opts).unwrap(); - assert_eq!(3, matches.opt_count("a")); - assert_eq!(3, matches.opt_count("apple")); - } - - #[test] - fn test_usage() { - let optgroups = vec![reqopt("b", "banana", "Desc", "VAL"), - optopt("a", "012345678901234567890123456789", "Desc", "VAL"), - optflag("k", "kiwi", "Desc"), - optflagopt("p", "", "Desc", "VAL"), - optmulti("l", "", "Desc", "VAL")]; - - let expected = -"Usage: fruits - -Options: - -b --banana VAL Desc - -a --012345678901234567890123456789 VAL - Desc - -k --kiwi Desc - -p [VAL] Desc - -l VAL Desc -"; - - let generated_usage = usage("Usage: fruits", &optgroups); - - assert_eq!(generated_usage, expected); - } - - #[test] - fn test_usage_description_wrapping() { - // indentation should be 24 spaces - // lines wrap after 78: or rather descriptions wrap after 54 - - let optgroups = vec![optflag("k", - "kiwi", - // 54 - "This is a long description which won't be wrapped..+.."), - optflag("a", - "apple", - "This is a long description which _will_ be wrapped..+..")]; - - let expected = -"Usage: fruits - -Options: - -k --kiwi This is a long description which won't be wrapped..+.. - -a --apple This is a long description which _will_ be - wrapped..+.. -"; - - let usage = usage("Usage: fruits", &optgroups); - - assert!(usage == expected) - } - - #[test] - fn test_usage_description_multibyte_handling() { - let optgroups = vec![optflag("k", - "k\u{2013}w\u{2013}", - "The word kiwi is normally spelled with two i's"), - optflag("a", - "apple", - "This \u{201C}description\u{201D} has some characters that \ - could confuse the line wrapping; an apple costs 0.51€ in \ - some parts of Europe.")]; - - let expected = -"Usage: fruits - -Options: - -k --k–w– The word kiwi is normally spelled with two i's - -a --apple This “description” has some characters that could - confuse the line wrapping; an apple costs 0.51€ in - some parts of Europe. -"; - - let usage = usage("Usage: fruits", &optgroups); - - assert!(usage == expected) - } - - #[test] - fn test_short_usage() { - let optgroups = vec![reqopt("b", "banana", "Desc", "VAL"), - optopt("a", "012345678901234567890123456789", "Desc", "VAL"), - optflag("k", "kiwi", "Desc"), - optflagopt("p", "", "Desc", "VAL"), - optmulti("l", "", "Desc", "VAL")]; - - let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string(); - let generated_usage = short_usage("fruits", &optgroups); - - assert_eq!(generated_usage, expected); - } - - #[test] - fn test_args_with_equals() { - let args = vec!["--one".to_string(), "A=B".to_string(), - "--two=C=D".to_string()]; - let opts = vec![optopt("o", "one", "One", "INFO"), - optopt("t", "two", "Two", "INFO")]; - let matches = &match getopts(&args, &opts) { - result::Result::Ok(m) => m, - result::Result::Err(e) => panic!("{}", e) - }; - assert_eq!(matches.opts_str(&["o".to_string()]).unwrap(), "A=B"); - assert_eq!(matches.opts_str(&["t".to_string()]).unwrap(), "C=D"); - } -} From 3bfed9e43f5ebe76719e3c30c8c8cefc81b08f80 Mon Sep 17 00:00:00 2001 From: Hidehito Yabuuchi Date: Thu, 22 Mar 2018 20:57:12 +0900 Subject: [PATCH 45/48] Better diagnostics for '..' pattern fragment not in the last position --- src/libsyntax/parse/parser.rs | 8 +++++++- src/test/ui/issue-49257.rs | 23 +++++++++++++++++++++++ src/test/ui/issue-49257.stderr | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issue-49257.rs create mode 100644 src/test/ui/issue-49257.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a07279acae2d3..98e2528d30f24 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3675,7 +3675,13 @@ impl<'a> Parser<'a> { if self.token != token::CloseDelim(token::Brace) { let token_str = self.this_token_to_string(); let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str)); - err.span_label(self.span, "expected `}`"); + if self.token == token::Comma { // Issue #49257 + err.span_label(self.span, + "`..` must be in the last position, \ + and cannot have a trailing comma"); + } else { + err.span_label(self.span, "expected `}`"); + } return Err(err); } etc = true; diff --git a/src/test/ui/issue-49257.rs b/src/test/ui/issue-49257.rs new file mode 100644 index 0000000000000..75b9e12684165 --- /dev/null +++ b/src/test/ui/issue-49257.rs @@ -0,0 +1,23 @@ +// Copyright 2018 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 for #49257: +// emits good diagnostics for `..` pattern fragments not in the last position. + +#![allow(unused)] + +struct Point { x: u8, y: u8 } + +fn main() { + let p = Point { x: 0, y: 0 }; + let Point { .., y } = p; //~ ERROR expected `}`, found `,` + //~^ pattern does not mention field `x` + //~^^ pattern does not mention field `y` +} diff --git a/src/test/ui/issue-49257.stderr b/src/test/ui/issue-49257.stderr new file mode 100644 index 0000000000000..ecaf36520aec9 --- /dev/null +++ b/src/test/ui/issue-49257.stderr @@ -0,0 +1,21 @@ +error: expected `}`, found `,` + --> $DIR/issue-49257.rs:20:19 + | +LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` + | ^ `..` must be in the last position, and cannot have a trailing comma + +error[E0027]: pattern does not mention field `x` + --> $DIR/issue-49257.rs:20:9 + | +LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` + | ^^^^^^^^^^^^^^^ missing field `x` + +error[E0027]: pattern does not mention field `y` + --> $DIR/issue-49257.rs:20:9 + | +LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` + | ^^^^^^^^^^^^^^^ missing field `y` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0027`. From f8fc5c0523c174e27e670525f5fa22d087315507 Mon Sep 17 00:00:00 2001 From: Hidehito Yabuuchi Date: Fri, 23 Mar 2018 01:15:27 +0900 Subject: [PATCH 46/48] Fix error annotations in test --- src/test/ui/issue-49257.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issue-49257.rs b/src/test/ui/issue-49257.rs index 75b9e12684165..61883294594bc 100644 --- a/src/test/ui/issue-49257.rs +++ b/src/test/ui/issue-49257.rs @@ -18,6 +18,6 @@ struct Point { x: u8, y: u8 } fn main() { let p = Point { x: 0, y: 0 }; let Point { .., y } = p; //~ ERROR expected `}`, found `,` - //~^ pattern does not mention field `x` - //~^^ pattern does not mention field `y` + //~| ERROR pattern does not mention field `x` + //~| ERROR pattern does not mention field `y` } From 3d0ccb2a22a229ddee842c0c1bf4ca231e77c78b Mon Sep 17 00:00:00 2001 From: Hidehito Yabuuchi Date: Sat, 24 Mar 2018 08:10:51 +0900 Subject: [PATCH 47/48] Fix test for PR #49268 --- src/test/ui/issue-49257.rs | 3 +-- src/test/ui/issue-49257.stderr | 12 +++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/test/ui/issue-49257.rs b/src/test/ui/issue-49257.rs index 61883294594bc..a319849223740 100644 --- a/src/test/ui/issue-49257.rs +++ b/src/test/ui/issue-49257.rs @@ -18,6 +18,5 @@ struct Point { x: u8, y: u8 } fn main() { let p = Point { x: 0, y: 0 }; let Point { .., y } = p; //~ ERROR expected `}`, found `,` - //~| ERROR pattern does not mention field `x` - //~| ERROR pattern does not mention field `y` + //~| ERROR pattern does not mention fields `x`, `y` } diff --git a/src/test/ui/issue-49257.stderr b/src/test/ui/issue-49257.stderr index ecaf36520aec9..fec990764bb14 100644 --- a/src/test/ui/issue-49257.stderr +++ b/src/test/ui/issue-49257.stderr @@ -4,18 +4,12 @@ error: expected `}`, found `,` LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` | ^ `..` must be in the last position, and cannot have a trailing comma -error[E0027]: pattern does not mention field `x` +error[E0027]: pattern does not mention fields `x`, `y` --> $DIR/issue-49257.rs:20:9 | LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` - | ^^^^^^^^^^^^^^^ missing field `x` + | ^^^^^^^^^^^^^^^ missing fields `x`, `y` -error[E0027]: pattern does not mention field `y` - --> $DIR/issue-49257.rs:20:9 - | -LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,` - | ^^^^^^^^^^^^^^^ missing field `y` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0027`. From 36322d00dfc11cb67814b3992d4432adc396edea Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 23 Mar 2018 23:29:52 +0100 Subject: [PATCH 48/48] update books for next release --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/book b/src/doc/book index 98921e9de849a..b889e1e30c5e9 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d +Subproject commit b889e1e30c5e9953834aa9fa6c982bb28df46ac9 diff --git a/src/doc/nomicon b/src/doc/nomicon index ad5ddd62c098d..6a8f0a27e9a58 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit ad5ddd62c098d5b424151beda574ae7df2154df1 +Subproject commit 6a8f0a27e9a58c55c89d07bc43a176fdae5e051c diff --git a/src/doc/reference b/src/doc/reference index 254df654a9b75..76296346e97c3 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 254df654a9b75abf6ca08806535dbe1fad41be3f +Subproject commit 76296346e97c3702974d3398fdb94af9e10111a2 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ebb28c95b2ea6..d5ec87eabe573 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ebb28c95b2ea68b96eddb9e71aff4d32eacc74f0 +Subproject commit d5ec87eabe5733cc2348c7dada89fc67c086f391