From 175ca98fde94e12c48a21c5fca7ed6cacfda6047 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Dec 2019 10:28:16 -0500 Subject: [PATCH 01/38] Switch to bootstrapping from dev-static stable --- src/ci/run.sh | 2 +- src/stage0.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 38d1d2baf2507..42f3b50d07d75 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -43,7 +43,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=nightly +export RUST_RELEASE_CHANNEL=beta if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" diff --git a/src/stage0.txt b/src/stage0.txt index 3c84890158381..ab3f5a78cb0a3 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,9 +12,9 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2019-11-06 -rustc: beta -cargo: beta +date: 2019-12-16 +rustc: 1.40.0 +cargo: 0.41.0 # When making a stable release the process currently looks like: # @@ -34,4 +34,4 @@ cargo: beta # looking at a beta source tarball and it's uncommented we'll shortly comment it # out. -#dev: 1 +dev: 1 From 50132c4ae36fe6fb0124c44700ce0cb576bf7e15 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 10 Dec 2019 23:32:52 -0800 Subject: [PATCH 02/38] Fix up Command Debug output when arg0 is specified. PR https://github.com/rust-lang/rust/pull/66512 added the ability to set argv[0] on Command. As a side effect, it changed the Debug output to print both the program and argv[0], which in practice results in stuttery output ("echo echo foo"). This PR reverts the behaviour to the the old one, so that the command is only printed once - unless arg0 has been set. In that case it emits "[command] arg0 arg1 ...". --- src/libstd/sys/unix/process/process_common.rs | 8 +++++-- src/test/ui/command-argv0-debug.rs | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/command-argv0-debug.rs diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index c9109b0c9d4d7..e66d6fdc56ac6 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -375,8 +375,12 @@ impl ChildStdio { impl fmt::Debug for Command { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { + if self.program != self.args[0] { + write!(f, "[{:?}] ", self.program)?; + } + write!(f, "{:?}", self.args[0])?; + + for arg in &self.args[1..] { write!(f, " {:?}", arg)?; } Ok(()) diff --git a/src/test/ui/command-argv0-debug.rs b/src/test/ui/command-argv0-debug.rs new file mode 100644 index 0000000000000..133d2ada2b263 --- /dev/null +++ b/src/test/ui/command-argv0-debug.rs @@ -0,0 +1,24 @@ +// run-pass + +// ignore-windows - this is a unix-specific test +// ignore-cloudabi no processes +// ignore-emscripten no processes +// ignore-sgx no processes +#![feature(process_set_argv0)] + +use std::os::unix::process::CommandExt; +use std::process::Command; + +fn main() { + let mut command = Command::new("some-boring-name"); + + assert_eq!(format!("{:?}", command), r#""some-boring-name""#); + + command.args(&["1", "2", "3"]); + + assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#); + + command.arg0("exciting-name"); + + assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#); +} From 9efb92de719707fc3d6f7b50c7b15d705a300084 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 11 Dec 2019 21:39:57 -0800 Subject: [PATCH 03/38] Move command-related tests into command/ --- src/test/ui/{ => command}/command-argv0-debug.rs | 0 src/test/ui/{ => command}/command-argv0.rs | 0 src/test/ui/{ => command}/command-exec.rs | 0 src/test/ui/{ => command}/command-pre-exec.rs | 0 src/test/ui/{ => command}/command-uid-gid.rs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => command}/command-argv0-debug.rs (100%) rename src/test/ui/{ => command}/command-argv0.rs (100%) rename src/test/ui/{ => command}/command-exec.rs (100%) rename src/test/ui/{ => command}/command-pre-exec.rs (100%) rename src/test/ui/{ => command}/command-uid-gid.rs (100%) diff --git a/src/test/ui/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs similarity index 100% rename from src/test/ui/command-argv0-debug.rs rename to src/test/ui/command/command-argv0-debug.rs diff --git a/src/test/ui/command-argv0.rs b/src/test/ui/command/command-argv0.rs similarity index 100% rename from src/test/ui/command-argv0.rs rename to src/test/ui/command/command-argv0.rs diff --git a/src/test/ui/command-exec.rs b/src/test/ui/command/command-exec.rs similarity index 100% rename from src/test/ui/command-exec.rs rename to src/test/ui/command/command-exec.rs diff --git a/src/test/ui/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs similarity index 100% rename from src/test/ui/command-pre-exec.rs rename to src/test/ui/command/command-pre-exec.rs diff --git a/src/test/ui/command-uid-gid.rs b/src/test/ui/command/command-uid-gid.rs similarity index 100% rename from src/test/ui/command-uid-gid.rs rename to src/test/ui/command/command-uid-gid.rs From 72b9452a4e82320f8f16375efa43f521e74860ee Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 15 Dec 2019 11:08:43 +0000 Subject: [PATCH 04/38] Don't suppress move errors for union fields --- .../dataflow/move_paths/builder.rs | 31 +++++++++++++------ .../move-from-union-field-issue-66500.rs | 30 ++++++++++++++++++ .../move-from-union-field-issue-66500.stderr | 27 ++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.rs create mode 100644 src/test/ui/borrowck/move-from-union-field-issue-66500.stderr diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index fa0864e0de760..971e9a1b3b281 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } }; + // The move path index of the first union that we find. Once this is + // some we stop creating child move paths, since moves from unions + // move the whole thing. + // We continue looking for other move errors though so that moving + // from `*(u.f: &_)` isn't allowed. + let mut union_path = None; + for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; let body = self.builder.body; @@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { InteriorOfTypeWithDestructor { container_ty: place_ty }, )); } - // move out of union - always move the entire union ty::Adt(adt, _) if adt.is_union() => { - return Err(MoveError::UnionMove { path: base }); + union_path.get_or_insert(base); } ty::Slice(_) => { return Err(MoveError::cannot_move_out_of( @@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { _ => {} }; - base = self.add_move_path(base, elem, |tcx| { - Place { - base: place.base.clone(), - projection: tcx.intern_place_elems(&place.projection[..i+1]), - } - }); + if union_path.is_none() { + base = self.add_move_path(base, elem, |tcx| { + Place { + base: place.base.clone(), + projection: tcx.intern_place_elems(&place.projection[..i+1]), + } + }); + } } - Ok(base) + if let Some(base) = union_path { + // Move out of union - always move the entire union. + Err(MoveError::UnionMove { path: base }) + } else { + Ok(base) + } } fn add_move_path( diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs new file mode 100644 index 0000000000000..8fbf120fc1c78 --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs @@ -0,0 +1,30 @@ +// Moving from a reference/raw pointer should be an error, even when they're +// the field of a union. + +#![feature(untagged_unions)] + +union Pointers { + a: &'static String, + b: &'static mut String, + c: *const String, + d: *mut String, +} + +unsafe fn move_ref(u: Pointers) -> String { + *u.a + //~^ ERROR cannot move out of `*u.a` +} +unsafe fn move_ref_mut(u: Pointers) -> String { + *u.b + //~^ ERROR cannot move out of `*u.b` +} +unsafe fn move_ptr(u: Pointers) -> String { + *u.c + //~^ ERROR cannot move out of `*u.c` +} +unsafe fn move_ptr_mut(u: Pointers) -> String { + *u.d + //~^ ERROR cannot move out of `*u.d` +} + +fn main() {} diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr new file mode 100644 index 0000000000000..a7cb1c9e22135 --- /dev/null +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of `*u.a` which is behind a shared reference + --> $DIR/move-from-union-field-issue-66500.rs:14:5 + | +LL | *u.a + | ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.b` which is behind a mutable reference + --> $DIR/move-from-union-field-issue-66500.rs:18:5 + | +LL | *u.b + | ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.c` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:22:5 + | +LL | *u.c + | ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.d` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:26:5 + | +LL | *u.d + | ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. From 03436b7d01284e2fb219328d2ff4a9cebd572b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 18 Dec 2019 22:48:24 +0100 Subject: [PATCH 05/38] Reenable static linking of libstdc++ on windows-gnu --- src/bootstrap/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index baf9aabed00af..831053bc0f7e2 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -563,7 +563,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne // not for MSVC or macOS if builder.config.llvm_static_stdcpp && !target.contains("freebsd") && - !target.contains("windows") && + !target.contains("msvc") && !target.contains("apple") { let file = compiler_file(builder, builder.cxx(target).unwrap(), From 7c4f9132e761e2fea099cb42f0930c2f114af920 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 25 Dec 2019 21:09:51 +0000 Subject: [PATCH 06/38] Use the correct type for static qualifs --- .../transform/check_consts/qualifs.rs | 16 ++++++++-------- src/test/ui/consts/const-eval/promote-static.rs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/consts/const-eval/promote-static.rs diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 223a5f8d605fc..56acd736f10cf 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -33,12 +33,6 @@ pub trait Qualif { /// of the type. fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> bool; - fn in_static(cx: &ConstCx<'_, 'tcx>, def_id: DefId) -> bool { - // `mir_const_qualif` does return the qualifs in the final value of a `static`, so we could - // use value-based qualification here, but we shouldn't do this without a good reason. - Self::in_any_value_of_ty(cx, cx.tcx.type_of(def_id)) - } - fn in_projection_structurally( cx: &ConstCx<'_, 'tcx>, per_local: &impl Fn(Local) -> bool, @@ -108,8 +102,14 @@ pub trait Qualif { Operand::Move(ref place) => Self::in_place(cx, per_local, place.as_ref()), Operand::Constant(ref constant) => { - if let Some(static_) = constant.check_static_ptr(cx.tcx) { - Self::in_static(cx, static_) + if constant.check_static_ptr(cx.tcx).is_some() { + // `mir_const_qualif` does return the qualifs in the final value of a `static`, + // so we could use value-based qualification here, but we shouldn't do this + // without a good reason. + // + // Note: this uses `constant.literal.ty` which is a reference or pointer to the + // type of the actual `static` item. + Self::in_any_value_of_ty(cx, constant.literal.ty) } else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val { // Don't peek inside trait associated constants. if cx.tcx.trait_of_item(def_id).is_some() { diff --git a/src/test/ui/consts/const-eval/promote-static.rs b/src/test/ui/consts/const-eval/promote-static.rs new file mode 100644 index 0000000000000..d3c663c53e905 --- /dev/null +++ b/src/test/ui/consts/const-eval/promote-static.rs @@ -0,0 +1,14 @@ +// regression test for #67609. + +// check-pass + +static NONE: Option = None; + +static NONE_REF_REF: &&Option = { + let x = &&NONE; + x +}; + +fn main() { + println!("{:?}", NONE_REF_REF); +} From e7809333730bbdbe9264beff84a1a38df3e16062 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Dec 2019 14:50:40 +0100 Subject: [PATCH 07/38] Treat extern statics just like statics in the "const pointer to static" representation --- src/librustc/ty/util.rs | 2 - .../mir-opt/const-promotion-extern-static.rs | 71 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/test/mir-opt/const-promotion-extern-static.rs diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 0b11a9efd81d7..2b83cecf1ed43 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -692,8 +692,6 @@ impl<'tcx> TyCtxt<'tcx> { if self.is_mutable_static(def_id) { self.mk_mut_ptr(static_ty) - } else if self.is_foreign_item(def_id) { - self.mk_imm_ptr(static_ty) } else { self.mk_imm_ref(self.lifetimes.re_erased, static_ty) } diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs new file mode 100644 index 0000000000000..d611ec22c38ec --- /dev/null +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -0,0 +1,71 @@ +extern "C" { + static X: i32; +} + +static Y: i32 = 42; + +static mut BAR: *const &'static i32 = [&Y].as_ptr(); + +static mut FOO: *const &'static i32 = [unsafe { &X }].as_ptr(); + +fn main() {} + +// END RUST SOURCE +// START rustc.FOO.PromoteTemps.before.mir +// bb0: { +// ... +// _5 = const Scalar(AllocId(1).0x0) : &i32; +// _4 = &(*_5); +// _3 = [move _4]; +// _2 = &_3; +// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// } +// ... +// bb2: { +// StorageDead(_5); +// StorageDead(_3); +// return; +// } +// END rustc.FOO.PromoteTemps.before.mir +// START rustc.BAR.PromoteTemps.before.mir +// bb0: { +// ... +// _5 = const Scalar(AllocId(0).0x0) : &i32; +// _4 = &(*_5); +// _3 = [move _4]; +// _2 = &_3; +// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// } +// ... +// bb2: { +// StorageDead(_5); +// StorageDead(_3); +// return; +// } +// END rustc.BAR.PromoteTemps.before.mir +// START rustc.BAR.PromoteTemps.after.mir +// bb0: { +// ... +// _2 = &(promoted[0]: [&'static i32; 1]); +// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// } +// ... +// bb2: { +// return; +// } +// END rustc.BAR.PromoteTemps.after.mir +// START rustc.FOO.PromoteTemps.after.mir +// bb0: { +// ... +// _2 = &(promoted[0]: [&'static i32; 1]); +// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// } +// ... +// bb2: { +// return; +// } +// END rustc.FOO.PromoteTemps.after.mir From 097240b1103e80e1e7228448e1330ec1c309a538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 28 Dec 2019 13:51:29 -0800 Subject: [PATCH 08/38] Do not ICE on lifetime error involving closures --- .../diagnostics/conflict_errors.rs | 22 +++++++++++++++++-- ...ure-doesnt-life-long-enough-issue-67634.rs | 3 +++ ...doesnt-life-long-enough-issue-67634.stderr | 15 +++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs create mode 100644 src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 1cd43d4fdd411..d2aaee4d20fb5 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -951,9 +951,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( drop_span, format!( - "...but `{}` will be dropped here, when the function `{}` returns", + "...but `{}` will be dropped here, when the {} returns", name, - self.infcx.tcx.hir().name(fn_hir_id), + self.infcx + .tcx + .hir() + .opt_name(fn_hir_id) + .map(|name| format!("function `{}`", name)) + .unwrap_or_else(|| { + match &self + .infcx + .tcx + .typeck_tables_of(self.mir_def_id) + .node_type(fn_hir_id) + .kind + { + ty::Closure(..) => "enclosing closure", + ty::Generator(..) => "enclosing generator", + kind => bug!("expected closure or generator, found {:?}", kind), + } + .to_string() + }) ), ); diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs new file mode 100644 index 0000000000000..19d7f0190479e --- /dev/null +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs @@ -0,0 +1,3 @@ +fn main() { + [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR `a` does not live long enough +} diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr new file mode 100644 index 0000000000000..cb0b481e74876 --- /dev/null +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr @@ -0,0 +1,15 @@ +error[E0597]: `a` does not live long enough + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:49 + | +LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); + | - ^- ...but `a` will be dropped here, when the enclosing closure returns + | | | + | | `a` would have to be valid for `'_`... + | has type `&i32` + | + = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From 289cd177abd3af63748b602530f10bafd9a747a7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 13 Jan 2020 22:42:58 +0100 Subject: [PATCH 09/38] Fix rebase damage --- src/librustc_mir/transform/check_consts/qualifs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 56acd736f10cf..1f58a05302589 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -2,7 +2,6 @@ use rustc::mir::*; use rustc::ty::{self, Ty}; -use rustc::hir::def_id::DefId; use syntax_pos::DUMMY_SP; use super::Item as ConstCx; From 2aff5b81f4344287acf9db36762aa90b3406c301 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 9 Jan 2020 23:00:28 +0100 Subject: [PATCH 10/38] expect `fn` after `const unsafe` / `const extern` (cherry picked from commit 915db7ae6430baef99f186ba40f08e105b7694fe) --- src/librustc_parse/parser/item.rs | 2 +- ...onst-extern-fns-dont-need-fn-specifier-2.rs | 7 +++++++ ...-extern-fns-dont-need-fn-specifier-2.stderr | 8 ++++++++ ...-const-extern-fns-dont-need-fn-specifier.rs | 8 ++++++++ ...st-extern-fns-dont-need-fn-specifier.stderr | 18 ++++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs create mode 100644 src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 34ef12e818c57..88aee15ff111a 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -144,7 +144,7 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); } let ext = self.parse_extern()?; - self.bump(); // `fn` + self.expect_keyword(kw::Fn)?; let header = FnHeader { unsafety, diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs new file mode 100644 index 0000000000000..7ced24808bf6e --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs @@ -0,0 +1,7 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const unsafe WhereIsFerris Now() {} + //~^ ERROR expected one of `extern` or `fn` +} diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr new file mode 100644 index 0000000000000..5ec9e2a91f1dc --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.stderr @@ -0,0 +1,8 @@ +error: expected one of `extern` or `fn`, found `WhereIsFerris` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs:5:18 + | +LL | const unsafe WhereIsFerris Now() {} + | ^^^^^^^^^^^^^ expected one of `extern` or `fn` + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs new file mode 100644 index 0000000000000..1886bfccb4e3e --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs @@ -0,0 +1,8 @@ +fn main() {} + +#[cfg(FALSE)] +fn container() { + const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + //~^ ERROR expected `fn` + //~| ERROR `const extern fn` definitions are unstable +} diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr new file mode 100644 index 0000000000000..cf71ed4d59765 --- /dev/null +++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr @@ -0,0 +1,18 @@ +error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE` + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:25 + | +LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn` + +error[E0658]: `const extern fn` definitions are unstable + --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5 + | +LL | const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 } + | ^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/64926 + = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 9b23f7cfc0dd88203f447e40ae0ac63356d5c991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 9 Jan 2020 22:10:18 -0800 Subject: [PATCH 11/38] Do not ICE on unicode next point Use `shrink_to_hi` instead of `next_point` Fix #68000. (cherry picked from commit fcd850fc5db2501d14b2e0cbfac8aa890d700e55) --- src/librustc_parse/parser/item.rs | 2 +- ...e-68000-unicode-ident-after-missing-comma.rs | 6 ++++++ ...000-unicode-ident-after-missing-comma.stderr | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs create mode 100644 src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 88aee15ff111a..b842fec29c074 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1572,7 +1572,7 @@ impl<'a> Parser<'a> { } } _ => { - let sp = self.sess.source_map().next_point(self.prev_span); + let sp = self.prev_span.shrink_to_hi(); let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found {}", self.this_token_descr())); if self.token.is_ident() { diff --git a/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs new file mode 100644 index 0000000000000..3c49a5a975209 --- /dev/null +++ b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.rs @@ -0,0 +1,6 @@ +pub struct Foo { + pub bar: Vecö + //~^ ERROR expected `,`, or `}`, found `ö` +} //~ ERROR expected `:`, found `}` + +fn main() {} diff --git a/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr new file mode 100644 index 0000000000000..ef365a616437b --- /dev/null +++ b/src/test/ui/issues/issue-68000-unicode-ident-after-missing-comma.stderr @@ -0,0 +1,17 @@ +error: expected `,`, or `}`, found `ö` + --> $DIR/issue-68000-unicode-ident-after-missing-comma.rs:2:22 + | +LL | pub bar: Vecö + | ^ help: try adding a comma: `,` + +error: expected `:`, found `}` + --> $DIR/issue-68000-unicode-ident-after-missing-comma.rs:4:1 + | +LL | pub bar: Vecö + | - expected `:` +LL | +LL | } + | ^ unexpected token + +error: aborting due to 2 previous errors + From 28e0b42fd445ad7a552569478f3c30adbc9127ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 10 Jan 2020 11:02:47 -0800 Subject: [PATCH 12/38] Fix `next_point` to be unicode aware (cherry picked from commit 3250057da983fa4d5bfd0799adaa41cb038f0e25) --- src/libsyntax_pos/source_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax_pos/source_map.rs b/src/libsyntax_pos/source_map.rs index b597fad080fa0..b252dabfa3cf9 100644 --- a/src/libsyntax_pos/source_map.rs +++ b/src/libsyntax_pos/source_map.rs @@ -739,7 +739,7 @@ impl SourceMap { pub fn next_point(&self, sp: Span) -> Span { let start_of_next_point = sp.hi().0; - let width = self.find_width_of_character_at_span(sp, true); + let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true); // If the width is 1, then the next span should point to the same `lo` and `hi`. However, // in the case of a multibyte character, where the width != 1, the next span should // span multiple bytes to include the whole character. From 89c526a6b711d6af9192946911d9701ff9075f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 10 Jan 2020 11:03:26 -0800 Subject: [PATCH 13/38] Fix invalid bounding box (cherry picked from commit d558f6a570a782cd1c2e54de790f4f968b0de5f1) --- src/librustc_errors/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index ae5876848185b..c2c9f0374ee6d 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -181,7 +181,7 @@ impl CodeSuggestion { // Find the bounding span. let lo = substitution.parts.iter().map(|part| part.span.lo()).min().unwrap(); - let hi = substitution.parts.iter().map(|part| part.span.hi()).min().unwrap(); + let hi = substitution.parts.iter().map(|part| part.span.hi()).max().unwrap(); let bounding_span = Span::with_root_ctxt(lo, hi); let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); From ec4a464d153f9e663712a8f1f62d9ca75890655a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 10 Jan 2020 11:22:33 -0800 Subject: [PATCH 14/38] Change `next_point` when `shrink_to_hi` is more appropriate (cherry picked from commit b93ef68245807bac97cd17ea9eaa13169380d815) --- src/librustc_parse/parser/diagnostics.rs | 10 ++++------ src/librustc_parse/parser/expr.rs | 2 +- src/librustc_parse/parser/item.rs | 4 ++-- src/librustc_parse/parser/mod.rs | 2 +- src/librustc_typeck/check/callee.rs | 5 ++--- src/librustc_typeck/check/mod.rs | 3 +-- src/libsyntax_expand/mbe/macro_parser.rs | 2 +- src/libsyntax_ext/assert.rs | 2 +- 8 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index ba125cacab48b..60a6fc5ed7bbf 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -300,15 +300,13 @@ impl<'a> Parser<'a> { expect.clone() }; (format!("expected one of {}, found {}", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected one of {}", short_expect))) + (self.prev_span.shrink_to_hi(), format!("expected one of {}", short_expect))) } else if expected.is_empty() { (format!("unexpected token: {}", actual), (self.prev_span, "unexpected token after this".to_string())) } else { (format!("expected {}, found {}", expect, actual), - (self.sess.source_map().next_point(self.prev_span), - format!("expected {}", expect))) + (self.prev_span.shrink_to_hi(), format!("expected {}", expect))) }; self.last_unexpected_token_span = Some(self.token.span); let mut err = self.fatal(&msg_exp); @@ -871,7 +869,7 @@ impl<'a> Parser<'a> { _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), // EOF, don't want to point at the following char, but rather the last token. (token::Eof, None) => (self.prev_span, self.token.span), - _ => (self.sess.source_map().next_point(self.prev_span), self.token.span), + _ => (self.prev_span.shrink_to_hi(), self.token.span), }; let msg = format!( "expected `{}`, found {}", @@ -1179,7 +1177,7 @@ impl<'a> Parser<'a> { err.span_label(sp, "unclosed delimiter"); } err.span_suggestion_short( - self.sess.source_map().next_point(self.prev_span), + self.prev_span.shrink_to_hi(), &format!("{} may belong here", delim.to_string()), delim.to_string(), Applicability::MaybeIncorrect, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 3cd4988ce0be5..b84e9cab5f4e1 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1647,7 +1647,7 @@ impl<'a> Parser<'a> { // | | // | parsed until here as `"y" & X` err.span_suggestion_short( - cm.next_point(arm_start_span), + arm_start_span.shrink_to_hi(), "missing a comma here to end this `match` arm", ",".to_owned(), Applicability::MachineApplicable diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index b842fec29c074..130ce1348229c 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1706,7 +1706,7 @@ impl<'a> Parser<'a> { // it's safe to peel off one character only when it has the close delim self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)) } else { - self.sess.source_map().next_point(self.prev_span) + self.prev_span.shrink_to_hi() }; self.struct_span_err( @@ -1720,7 +1720,7 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ).span_suggestion( - self.sess.source_map().next_point(self.prev_span), + self.prev_span.shrink_to_hi(), "add a semicolon", ';'.to_string(), Applicability::MaybeIncorrect, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 07e99cfe01292..d6878411073ab 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -803,7 +803,7 @@ impl<'a> Parser<'a> { break; } Err(mut expect_err) => { - let sp = self.sess.source_map().next_point(self.prev_span); + let sp = self.prev_span.shrink_to_hi(); let token_str = pprust::token_kind_to_string(t); // Attempt to keep parsing if it was a similar separator. diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 1b3af48ea83bf..bfc615639486f 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::Block(..), ) = (parent_node, callee_node) { let start = sp.shrink_to_lo(); - let end = self.tcx.sess.source_map().next_point(callee_span); + let end = callee_span.shrink_to_hi(); err.multipart_suggestion( "if you meant to create this closure and immediately call it, surround the \ closure with parenthesis", @@ -332,9 +332,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span); if call_is_multiline { - let span = self.tcx.sess.source_map().next_point(callee.span); err.span_suggestion( - span, + callee.span.shrink_to_hi(), "try adding a semicolon", ";".to_owned(), Applicability::MaybeIncorrect, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 09771bb762536..8fb0858bfec3a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4834,9 +4834,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => { - let sp = self.tcx.sess.source_map().next_point(cause_span); err.span_suggestion( - sp, + cause_span.shrink_to_hi(), "try adding a semicolon", ";".to_string(), Applicability::MachineApplicable); diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs index 1e2f3f9d1e53e..50718d51be901 100644 --- a/src/libsyntax_expand/mbe/macro_parser.rs +++ b/src/libsyntax_expand/mbe/macro_parser.rs @@ -708,7 +708,7 @@ pub(super) fn parse( Token::new(token::Eof, if parser.token.span.is_dummy() { parser.token.span } else { - sess.source_map().next_point(parser.token.span) + parser.token.span.shrink_to_hi() }), "missing tokens in macro arguments", ); diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index c788d06299405..1bae4743320f1 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -105,7 +105,7 @@ fn parse_assert<'a>( let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { let mut err = cx.struct_span_warn(parser.token.span, "unexpected string literal"); - let comma_span = cx.source_map().next_point(parser.prev_span); + let comma_span = parser.prev_span.shrink_to_hi(); err.span_suggestion_short( comma_span, "try adding a comma", From 84eb3b27bfe540375b16c93bda0dd552661a27d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 10 Jan 2020 11:22:57 -0800 Subject: [PATCH 15/38] Add ICE regression tests (cherry picked from commit f6e9fd037a7b55f8f4fe78694b77d9788b18dfeb) --- src/test/ui/issues/issue-68091-unicode-ident-after-if.rs | 9 +++++++++ .../ui/issues/issue-68091-unicode-ident-after-if.stderr | 8 ++++++++ .../issue-68092-unicode-ident-after-incomplete-expr.rs | 9 +++++++++ ...ssue-68092-unicode-ident-after-incomplete-expr.stderr | 8 ++++++++ 4 files changed, 34 insertions(+) create mode 100644 src/test/ui/issues/issue-68091-unicode-ident-after-if.rs create mode 100644 src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr create mode 100644 src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs create mode 100644 src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs b/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs new file mode 100644 index 0000000000000..99d69d2199596 --- /dev/null +++ b/src/test/ui/issues/issue-68091-unicode-ident-after-if.rs @@ -0,0 +1,9 @@ +macro_rules! x { + ($($c:tt)*) => { + $($c)ö* {} //~ ERROR missing condition for `if` expression + }; +} + +fn main() { + x!(if); +} diff --git a/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr b/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr new file mode 100644 index 0000000000000..aac04f4b747bc --- /dev/null +++ b/src/test/ui/issues/issue-68091-unicode-ident-after-if.stderr @@ -0,0 +1,8 @@ +error: missing condition for `if` expression + --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14 + | +LL | $($c)ö* {} + | ^ expected if condition here + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs new file mode 100644 index 0000000000000..1a90b4724d49d --- /dev/null +++ b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.rs @@ -0,0 +1,9 @@ +macro_rules! x { + ($($c:tt)*) => { + $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression + }; +} + +fn main() { + x!(!); +} diff --git a/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr new file mode 100644 index 0000000000000..0b9c364f1f1fb --- /dev/null +++ b/src/test/ui/issues/issue-68092-unicode-ident-after-incomplete-expr.stderr @@ -0,0 +1,8 @@ +error: macro expansion ends with an incomplete expression: expected expression + --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14 + | +LL | $($c)ö* + | ^ expected expression + +error: aborting due to previous error + From 076095b04907091f20ed6a915dbdbb23652d1520 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 7 Jan 2020 23:21:24 +0000 Subject: [PATCH 16/38] rustdoc: Don't allow `#![feature(...)]` on stable or beta (cherry picked from commit 40571995984a0f2c466f77955e7d147887c2179b) --- src/librustdoc/core.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a524801bea6bf..dd2e1144301ec 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -318,8 +318,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt cg: codegen_options, externs, target_triple: target, - // Ensure that rustdoc works even if rustc is feature-staged - unstable_features: UnstableFeatures::Allow, + unstable_features: UnstableFeatures::from_environment(), actually_rustdoc: true, debugging_opts: debugging_options, error_format, From 5d4b63926fe1eea0d36828c05693a91a0dd2fc15 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:08:09 -0500 Subject: [PATCH 17/38] fmt data data structures --- .../obligation_forest/mod.rs | 119 ++++++++---------- 1 file changed, 51 insertions(+), 68 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index b1931ca459f61..92bd196aaa3cf 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -85,19 +85,20 @@ mod graphviz; #[cfg(test)] mod tests; -pub trait ForestObligation : Clone + Debug { - type Predicate : Clone + hash::Hash + Eq + Debug; +pub trait ForestObligation: Clone + Debug { + type Predicate: Clone + hash::Hash + Eq + Debug; fn as_predicate(&self) -> &Self::Predicate; } pub trait ObligationProcessor { - type Obligation : ForestObligation; - type Error : Debug; + type Obligation: ForestObligation; + type Error: Debug; - fn process_obligation(&mut self, - obligation: &mut Self::Obligation) - -> ProcessResult; + fn process_obligation( + &mut self, + obligation: &mut Self::Obligation, + ) -> ProcessResult; /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts @@ -107,10 +108,9 @@ pub trait ObligationProcessor { /// In other words, if we had O1 which required O2 which required /// O3 which required O1, we would give an iterator yielding O1, /// O2, O3 (O1 is not yielded twice). - fn process_backedge<'c, I>(&mut self, - cycle: I, - _marker: PhantomData<&'c Self::Obligation>) - where I: Clone + Iterator; + fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>) + where + I: Clone + Iterator; } /// The result type used by `process_obligation`. @@ -185,20 +185,11 @@ struct Node { } impl Node { - fn new( - parent: Option, - obligation: O, - obligation_tree_id: ObligationTreeId - ) -> Node { + fn new(parent: Option, obligation: O, obligation_tree_id: ObligationTreeId) -> Node { Node { obligation, state: Cell::new(NodeState::Pending), - dependents: - if let Some(parent_index) = parent { - vec![parent_index] - } else { - vec![] - }, + dependents: if let Some(parent_index) = parent { vec![parent_index] } else { vec![] }, has_parent: parent.is_some(), obligation_tree_id, } @@ -339,11 +330,7 @@ impl ObligationForest { node.dependents.push(parent_index); } } - if let NodeState::Error = node.state.get() { - Err(()) - } else { - Ok(()) - } + if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) } } Entry::Vacant(v) => { let obligation_tree_id = match parent { @@ -351,12 +338,12 @@ impl ObligationForest { None => self.obligation_tree_id_generator.next().unwrap(), }; - let already_failed = - parent.is_some() - && self.error_cache - .get(&obligation_tree_id) - .map(|errors| errors.contains(obligation.as_predicate())) - .unwrap_or(false); + let already_failed = parent.is_some() + && self + .error_cache + .get(&obligation_tree_id) + .map(|errors| errors.contains(obligation.as_predicate())) + .unwrap_or(false); if already_failed { Err(()) @@ -372,14 +359,12 @@ impl ObligationForest { /// Converts all remaining obligations to the given error. pub fn to_errors(&mut self, error: E) -> Vec> { - let errors = self.nodes.iter().enumerate() + let errors = self + .nodes + .iter() + .enumerate() .filter(|(_index, node)| node.state.get() == NodeState::Pending) - .map(|(index, _node)| { - Error { - error: error.clone(), - backtrace: self.error_at(index), - } - }) + .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); let successful_obligations = self.compress(DoCompleted::Yes); @@ -389,9 +374,11 @@ impl ObligationForest { /// Returns the set of obligations that are in a pending state. pub fn map_pending_obligations(&self, f: F) -> Vec

- where F: Fn(&O) -> P + where + F: Fn(&O) -> P, { - self.nodes.iter() + self.nodes + .iter() .filter(|node| node.state.get() == NodeState::Pending) .map(|node| f(&node.obligation)) .collect() @@ -421,9 +408,13 @@ impl ObligationForest { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). - pub fn process_obligations

(&mut self, processor: &mut P, do_completed: DoCompleted) - -> Outcome - where P: ObligationProcessor + pub fn process_obligations

( + &mut self, + processor: &mut P, + do_completed: DoCompleted, + ) -> Outcome + where + P: ObligationProcessor, { self.gen += 1; @@ -462,10 +453,7 @@ impl ObligationForest { node.state.set(NodeState::Success(Self::not_waiting())); for child in children { - let st = self.register_obligation_at( - child, - Some(index) - ); + let st = self.register_obligation_at(child, Some(index)); if let Err(()) = st { // Error already reported - propagate it // to our node. @@ -475,10 +463,7 @@ impl ObligationForest { } ProcessResult::Error(err) => { stalled = false; - errors.push(Error { - error: err, - backtrace: self.error_at(index), - }); + errors.push(Error { error: err, backtrace: self.error_at(index) }); } } index += 1; @@ -498,11 +483,7 @@ impl ObligationForest { self.process_cycles(processor); let completed = self.compress(do_completed); - Outcome { - completed, - errors, - stalled, - } + Outcome { completed, errors, stalled } } /// Returns a vector of obligations for `p` and all of its @@ -574,7 +555,8 @@ impl ObligationForest { /// Report cycles between all `Success` nodes that aren't still waiting. /// This must be called after `mark_still_waiting_nodes`. fn process_cycles

(&self, processor: &mut P) - where P: ObligationProcessor + where + P: ObligationProcessor, { let mut stack = vec![]; @@ -592,9 +574,14 @@ impl ObligationForest { debug_assert!(stack.is_empty()); } - fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, min_index: usize, - index: usize) - where P: ObligationProcessor + fn find_cycles_from_node

( + &self, + stack: &mut Vec, + processor: &mut P, + min_index: usize, + index: usize, + ) where + P: ObligationProcessor, { let node = &self.nodes[index]; if let NodeState::Success(waiting) = node.state.get() { @@ -614,7 +601,7 @@ impl ObligationForest { // Cycle detected. processor.process_backedge( stack[rpos..].iter().map(GetObligation(&self.nodes)), - PhantomData + PhantomData, ); } } @@ -697,11 +684,7 @@ impl ObligationForest { node_rewrites.truncate(0); self.node_rewrites.replace(node_rewrites); - if do_completed == DoCompleted::Yes { - Some(removed_success_obligations) - } else { - None - } + if do_completed == DoCompleted::Yes { Some(removed_success_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { From 6a835ea8658be7c8f3109503dbbf7f90a60a3eb2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 21 Dec 2019 10:53:41 +1100 Subject: [PATCH 18/38] Revert parts of #66405. Because it caused major performance regressions in some cases. That PR had five commits, two of which affected performance, and three of which were refactorings. This change undoes the performance-affecting changes, while keeping the refactorings in place. Fixes #67454. --- .../obligation_forest/mod.rs | 191 ++++++++---------- 1 file changed, 80 insertions(+), 111 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 92bd196aaa3cf..974d9dcfae408 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -129,7 +129,7 @@ type ObligationTreeIdGenerator = pub struct ObligationForest { /// The list of obligations. In between calls to `process_obligations`, - /// this list only contains nodes in the `Pending` or `Success` state. + /// this list only contains nodes in the `Pending` or `Waiting` state. /// /// `usize` indices are used here and throughout this module, rather than /// `rustc_index::newtype_index!` indices, because this code is hot enough @@ -137,10 +137,6 @@ pub struct ObligationForest { /// significant, and space considerations are not important. nodes: Vec>, - /// The process generation is 1 on the first call to `process_obligations`, - /// 2 on the second call, etc. - gen: u32, - /// A cache of predicates that have been successfully completed. done_cache: FxHashSet, @@ -196,9 +192,9 @@ impl Node { } } -/// The state of one node in some tree within the forest. This -/// represents the current state of processing for the obligation (of -/// type `O`) associated with this node. +/// The state of one node in some tree within the forest. This represents the +/// current state of processing for the obligation (of type `O`) associated +/// with this node. /// /// The non-`Error` state transitions are as follows. /// ``` @@ -210,51 +206,47 @@ impl Node { /// | /// | process_obligations() /// v -/// Success(not_waiting()) -/// | | -/// | | mark_still_waiting_nodes() +/// Success +/// | ^ +/// | | mark_successes() /// | v -/// | Success(still_waiting()) -/// | | -/// | | compress() -/// v v +/// | Waiting +/// | +/// | process_cycles() +/// v +/// Done +/// | +/// | compress() +/// v /// (Removed) /// ``` /// The `Error` state can be introduced in several places, via `error_at()`. /// /// Outside of `ObligationForest` methods, nodes should be either `Pending` or -/// `Success`. +/// `Waiting`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum NodeState { /// This obligation has not yet been selected successfully. Cannot have /// subobligations. Pending, - /// This obligation was selected successfully, but it may be waiting on one - /// or more pending subobligations, as indicated by the `WaitingState`. - Success(WaitingState), + /// This obligation was selected successfully, but may or may not have + /// subobligations. + Success, + + /// This obligation was selected successfully, but it has a pending + /// subobligation. + Waiting, + + /// This obligation, along with its subobligations, are complete, and will + /// be removed in the next collection. + Done, /// This obligation was resolved to an error. It will be removed by the /// next compression step. Error, } -/// Indicates when a `Success` node was last (if ever) waiting on one or more -/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`. -/// - 0: "Not waiting". This is a special value, set by `process_obligation`, -/// and usable because generation counting starts at 1. -/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but -/// waiting no longer. In other words, finished. -/// - ObligationForest::gen: "Still waiting" in this generation. -/// -/// Things to note about this encoding: -/// - Every time `ObligationForest::gen` is incremented, all the "still -/// waiting" nodes automatically become "was waiting". -/// - `ObligationForest::is_still_waiting` is very cheap. -/// -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)] -struct WaitingState(u32); - #[derive(Debug)] pub struct Outcome { /// Obligations that were completely evaluated, including all @@ -291,7 +283,6 @@ impl ObligationForest { pub fn new() -> ObligationForest { ObligationForest { nodes: vec![], - gen: 0, done_cache: Default::default(), active_cache: Default::default(), node_rewrites: RefCell::new(vec![]), @@ -392,18 +383,6 @@ impl ObligationForest { .insert(node.obligation.as_predicate().clone()); } - fn not_waiting() -> WaitingState { - WaitingState(0) - } - - fn still_waiting(&self) -> WaitingState { - WaitingState(self.gen) - } - - fn is_still_waiting(&self, waiting: WaitingState) -> bool { - waiting.0 == self.gen - } - /// Performs a pass through the obligation list. This must /// be called in a loop until `outcome.stalled` is false. /// @@ -416,8 +395,6 @@ impl ObligationForest { where P: ObligationProcessor, { - self.gen += 1; - let mut errors = vec![]; let mut stalled = true; @@ -450,7 +427,7 @@ impl ObligationForest { ProcessResult::Changed(children) => { // We are not (yet) stalled. stalled = false; - node.state.set(NodeState::Success(Self::not_waiting())); + node.state.set(NodeState::Success); for child in children { let st = self.register_obligation_at(child, Some(index)); @@ -479,7 +456,7 @@ impl ObligationForest { }; } - self.mark_still_waiting_nodes(); + self.mark_successes(); self.process_cycles(processor); let completed = self.compress(do_completed); @@ -519,41 +496,50 @@ impl ObligationForest { trace } - /// Mark all `Success` nodes that depend on a pending node as still - /// waiting. Upon completion, any `Success` nodes that aren't still waiting - /// can be removed by `compress`. - fn mark_still_waiting_nodes(&self) { + /// Mark all `Waiting` nodes as `Success`, except those that depend on a + /// pending node. + fn mark_successes(&self) { + // Convert all `Waiting` nodes to `Success`. + for node in &self.nodes { + if node.state.get() == NodeState::Waiting { + node.state.set(NodeState::Success); + } + } + + // Convert `Success` nodes that depend on a pending node back to + // `Waiting`. for node in &self.nodes { if node.state.get() == NodeState::Pending { // This call site is hot. - self.inlined_mark_dependents_as_still_waiting(node); + self.inlined_mark_dependents_as_waiting(node); } } } // This always-inlined function is for the hot call site. #[inline(always)] - fn inlined_mark_dependents_as_still_waiting(&self, node: &Node) { + fn inlined_mark_dependents_as_waiting(&self, node: &Node) { for &index in node.dependents.iter() { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - node.state.set(NodeState::Success(self.still_waiting())); - // This call site is cold. - self.uninlined_mark_dependents_as_still_waiting(node); - } + let state = node.state.get(); + if state == NodeState::Success { + node.state.set(NodeState::Waiting); + // This call site is cold. + self.uninlined_mark_dependents_as_waiting(node); + } else { + debug_assert!(state == NodeState::Waiting || state == NodeState::Error) } } } // This never-inlined function is for the cold call site. #[inline(never)] - fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node) { - self.inlined_mark_dependents_as_still_waiting(node) + fn uninlined_mark_dependents_as_waiting(&self, node: &Node) { + self.inlined_mark_dependents_as_waiting(node) } - /// Report cycles between all `Success` nodes that aren't still waiting. - /// This must be called after `mark_still_waiting_nodes`. + /// Report cycles between all `Success` nodes, and convert all `Success` + /// nodes to `Done`. This must be called after `mark_successes`. fn process_cycles

(&self, processor: &mut P) where P: ObligationProcessor, @@ -564,46 +550,35 @@ impl ObligationForest { // For some benchmarks this state test is extremely hot. It's a win // to handle the no-op cases immediately to avoid the cost of the // function call. - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - self.find_cycles_from_node(&mut stack, processor, index, index); - } + if node.state.get() == NodeState::Success { + self.find_cycles_from_node(&mut stack, processor, index); } } debug_assert!(stack.is_empty()); } - fn find_cycles_from_node

( - &self, - stack: &mut Vec, - processor: &mut P, - min_index: usize, - index: usize, - ) where + fn find_cycles_from_node

(&self, stack: &mut Vec, processor: &mut P, index: usize) + where P: ObligationProcessor, { let node = &self.nodes[index]; - if let NodeState::Success(waiting) = node.state.get() { - if !self.is_still_waiting(waiting) { - match stack.iter().rposition(|&n| n == index) { - None => { - stack.push(index); - for &dep_index in node.dependents.iter() { - // The index check avoids re-considering a node. - if dep_index >= min_index { - self.find_cycles_from_node(stack, processor, min_index, dep_index); - } - } - stack.pop(); - } - Some(rpos) => { - // Cycle detected. - processor.process_backedge( - stack[rpos..].iter().map(GetObligation(&self.nodes)), - PhantomData, - ); + if node.state.get() == NodeState::Success { + match stack.iter().rposition(|&n| n == index) { + None => { + stack.push(index); + for &dep_index in node.dependents.iter() { + self.find_cycles_from_node(stack, processor, dep_index); } + stack.pop(); + node.state.set(NodeState::Done); + } + Some(rpos) => { + // Cycle detected. + processor.process_backedge( + stack[rpos..].iter().map(GetObligation(&self.nodes)), + PhantomData, + ); } } } @@ -611,8 +586,7 @@ impl ObligationForest { /// Compresses the vector, removing all popped nodes. This adjusts the /// indices and hence invalidates any outstanding indices. `process_cycles` - /// must be run beforehand to remove any cycles on not-still-waiting - /// `Success` nodes. + /// must be run beforehand to remove any cycles on `Success` nodes. #[inline(never)] fn compress(&mut self, do_completed: DoCompleted) -> Option> { let orig_nodes_len = self.nodes.len(); @@ -620,7 +594,7 @@ impl ObligationForest { debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; - let mut removed_success_obligations: Vec = vec![]; + let mut removed_done_obligations: Vec = vec![]; // Move removable nodes to the end, preserving the order of the // remaining nodes. @@ -632,19 +606,13 @@ impl ObligationForest { for index in 0..orig_nodes_len { let node = &self.nodes[index]; match node.state.get() { - NodeState::Pending => { - if dead_nodes > 0 { - self.nodes.swap(index, index - dead_nodes); - node_rewrites[index] -= dead_nodes; - } - } - NodeState::Success(waiting) if self.is_still_waiting(waiting) => { + NodeState::Pending | NodeState::Waiting => { if dead_nodes > 0 { self.nodes.swap(index, index - dead_nodes); node_rewrites[index] -= dead_nodes; } } - NodeState::Success(_) => { + NodeState::Done => { // This lookup can fail because the contents of // `self.active_cache` are not guaranteed to match those of // `self.nodes`. See the comment in `process_obligation` @@ -658,7 +626,7 @@ impl ObligationForest { } if do_completed == DoCompleted::Yes { // Extract the success stories. - removed_success_obligations.push(node.obligation.clone()); + removed_done_obligations.push(node.obligation.clone()); } node_rewrites[index] = orig_nodes_len; dead_nodes += 1; @@ -672,6 +640,7 @@ impl ObligationForest { node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } + NodeState::Success => unreachable!(), } } @@ -684,7 +653,7 @@ impl ObligationForest { node_rewrites.truncate(0); self.node_rewrites.replace(node_rewrites); - if do_completed == DoCompleted::Yes { Some(removed_success_obligations) } else { None } + if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { From 5386cbdca4200b50572bbe7b5869584efaf62476 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:10:46 -0500 Subject: [PATCH 19/38] format librustdoc --- src/librustdoc/config.rs | 129 +++-- src/librustdoc/core.rs | 440 +++++++++--------- src/librustdoc/lib.rs | 420 +++++++++-------- .../passes/calculate_doc_coverage.rs | 36 +- .../passes/check_code_block_syntax.rs | 8 +- src/librustdoc/passes/collapse_docs.rs | 20 +- .../passes/collect_intra_doc_links.rs | 410 +++++++++------- src/librustdoc/passes/collect_trait_impls.rs | 33 +- src/librustdoc/passes/mod.rs | 55 +-- .../passes/private_items_doc_tests.rs | 4 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 4 +- src/librustdoc/passes/strip_priv_imports.rs | 4 +- src/librustdoc/passes/strip_private.rs | 4 +- src/librustdoc/passes/unindent_comments.rs | 45 +- 15 files changed, 839 insertions(+), 775 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 0db3d28bf0e37..7a3cf88f65e21 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -7,10 +7,12 @@ use errors; use getopts; use rustc::lint::Level; use rustc::session; -use rustc::session::config::{CrateType, parse_crate_types_from_list, parse_externs}; +use rustc::session::config::{ + build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple, + nightly_options, +}; +use rustc::session::config::{parse_crate_types_from_list, parse_externs, CrateType}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; -use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, - get_cmd_lint_options, host_triple}; use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; @@ -19,8 +21,8 @@ use syntax::edition::{Edition, DEFAULT_EDITION}; use crate::core::new_handler; use crate::externalfiles::ExternalHtml; use crate::html; -use crate::html::{static_files}; -use crate::html::markdown::{IdMap}; +use crate::html::markdown::IdMap; +use crate::html::static_files; use crate::opts; use crate::passes::{self, DefaultPassOption}; use crate::theme; @@ -29,7 +31,6 @@ use crate::theme; #[derive(Clone)] pub struct Options { // Basic options / Options passed directly to rustc - /// The crate root or Markdown file to load. pub input: PathBuf, /// The name of the crate being documented. @@ -72,7 +73,6 @@ pub struct Options { pub lint_cap: Option, // Options specific to running doctests - /// Whether we should run doctests instead of generating docs. pub should_test: bool, /// List of arguments to pass to the test harness, if running tests. @@ -94,7 +94,6 @@ pub struct Options { pub test_builder: Option, // Options that affect the documentation process - /// The selected default set of passes to use. /// /// Be aware: This option can come both from the CLI and from crate attributes! @@ -111,7 +110,6 @@ pub struct Options { pub show_coverage: bool, // Options that alter generated documentation pages - /// Crate version to note on the sidebar of generated docs. pub crate_version: Option, /// Collected options specific to outputting final pages. @@ -124,9 +122,7 @@ impl fmt::Debug for Options { impl<'a> fmt::Debug for FmtExterns<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_map() - .entries(self.0.iter()) - .finish() + f.debug_map().entries(self.0.iter()).finish() } } @@ -208,7 +204,6 @@ pub struct RenderOptions { pub static_root_path: Option, // Options specific to reading standalone Markdown files - /// Whether to generate a table of contents on the output file when reading a standalone /// Markdown file. pub markdown_no_toc: bool, @@ -274,10 +269,12 @@ impl Options { let codegen_options = build_codegen_options(matches, error_format); let debugging_options = build_debugging_options(matches, error_format); - let diag = new_handler(error_format, - None, - debugging_options.treat_err_as_bug, - debugging_options.ui_testing); + let diag = new_handler( + error_format, + None, + debugging_options.treat_err_as_bug, + debugging_options.ui_testing, + ); // check for deprecated options check_deprecated_options(&matches, &diag); @@ -317,7 +314,9 @@ impl Options { } let input = PathBuf::from(&matches.free[0]); - let libs = matches.opt_strs("L").iter() + let libs = matches + .opt_strs("L") + .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); let externs = parse_externs(&matches, &debugging_options, error_format); @@ -330,16 +329,13 @@ impl Options { }; let test_args = matches.opt_strs("test-args"); - let test_args: Vec = test_args.iter() - .flat_map(|s| s.split_whitespace()) - .map(|s| s.to_string()) - .collect(); + let test_args: Vec = + test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect(); let should_test = matches.opt_present("test"); - let output = matches.opt_str("o") - .map(|s| PathBuf::from(&s)) - .unwrap_or_else(|| PathBuf::from("doc")); + let output = + matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc")); let cfgs = matches.opt_strs("cfg"); let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); @@ -355,9 +351,9 @@ impl Options { if matches.opt_present("theme") { let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); - for (theme_file, theme_s) in matches.opt_strs("theme") - .iter() - .map(|s| (PathBuf::from(&s), s.to_owned())) { + for (theme_file, theme_s) in + matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned())) + { if !theme_file.is_file() { diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)) .help("arguments to --theme must be files") @@ -365,8 +361,7 @@ impl Options { return Err(1); } if theme_file.extension() != Some(OsStr::new("css")) { - diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)) - .emit(); + diag.struct_err(&format!("invalid argument: \"{}\"", theme_s)).emit(); return Err(1); } let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag); @@ -374,12 +369,18 @@ impl Options { diag.struct_err(&format!("error loading theme file: \"{}\"", theme_s)).emit(); return Err(1); } else if !ret.is_empty() { - diag.struct_warn(&format!("theme file \"{}\" is missing CSS rules from the \ - default theme", theme_s)) - .warn("the theme may appear incorrect when loaded") - .help(&format!("to see what rules are missing, call `rustdoc \ - --check-theme \"{}\"`", theme_s)) - .emit(); + diag.struct_warn(&format!( + "theme file \"{}\" is missing CSS rules from the \ + default theme", + theme_s + )) + .warn("the theme may appear incorrect when loaded") + .help(&format!( + "to see what rules are missing, call `rustdoc \ + --check-theme \"{}\"`", + theme_s + )) + .emit(); } themes.push(theme_file); } @@ -400,12 +401,16 @@ impl Options { let mut id_map = html::markdown::IdMap::new(); id_map.populate(html::render::initial_ids()); let external_html = match ExternalHtml::load( - &matches.opt_strs("html-in-header"), - &matches.opt_strs("html-before-content"), - &matches.opt_strs("html-after-content"), - &matches.opt_strs("markdown-before-content"), - &matches.opt_strs("markdown-after-content"), - &diag, &mut id_map, edition, &None) { + &matches.opt_strs("html-in-header"), + &matches.opt_strs("html-before-content"), + &matches.opt_strs("html-after-content"), + &matches.opt_strs("markdown-before-content"), + &matches.opt_strs("markdown-after-content"), + &diag, + &mut id_map, + edition, + &None, + ) { Some(eh) => eh, None => return Err(3), }; @@ -434,15 +439,14 @@ impl Options { } } - let target = matches.opt_str("target").map_or( - TargetTriple::from_triple(host_triple()), - |target| { - if target.ends_with(".json") { - TargetTriple::TargetPath(PathBuf::from(target)) - } else { - TargetTriple::TargetTriple(target) - } - }); + let target = + matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| { + if target.ends_with(".json") { + TargetTriple::TargetPath(PathBuf::from(target)) + } else { + TargetTriple::TargetTriple(target) + } + }); let show_coverage = matches.opt_present("show-coverage"); let document_private = matches.opt_present("document-private-items"); @@ -462,7 +466,7 @@ impl Options { let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { Ok(types) => types, - Err(e) =>{ + Err(e) => { diag.struct_err(&format!("unknown crate type: {}", e)).emit(); return Err(1); } @@ -547,30 +551,24 @@ impl Options { markdown_playground_url, generate_search_filter, generate_redirect_pages, - } + }, }) } /// Returns `true` if the file given as `self.input` is a Markdown file. pub fn markdown_input(&self) -> bool { - self.input.extension() - .map_or(false, |e| e == "md" || e == "markdown") + self.input.extension().map_or(false, |e| e == "md" || e == "markdown") } } /// Prints deprecation warnings for deprecated options fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) { - let deprecated_flags = [ - "input-format", - "output-format", - "no-defaults", - "passes", - ]; + let deprecated_flags = ["input-format", "output-format", "no-defaults", "passes"]; for flag in deprecated_flags.iter() { if matches.opt_present(flag) { - let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", - flag)); + let mut err = + diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag)); err.warn("please see https://github.com/rust-lang/rust/issues/44136"); if *flag == "no-defaults" { @@ -581,10 +579,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) } } - let removed_flags = [ - "plugins", - "plugin-path", - ]; + let removed_flags = ["plugins", "plugin-path"]; for &flag in removed_flags.iter() { if matches.opt_present(flag) { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index dd2e1144301ec..80dd9ad7739b2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,47 +1,46 @@ -use rustc_lint; -use rustc::session::{self, config}; use rustc::hir::def::Namespace::TypeNS; -use rustc::hir::def_id::{DefId, DefIndex, CrateNum, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::hir::HirId; +use rustc::lint; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{Ty, TyCtxt}; -use rustc::lint; use rustc::session::config::ErrorOutputType; use rustc::session::DiagnosticOutput; +use rustc::session::{self, config}; +use rustc::ty::{Ty, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc_interface::interface; use rustc_driver::abort_on_err; use rustc_feature::UnstableFeatures; +use rustc_interface::interface; +use rustc_lint; use rustc_resolve as resolve; +use errors::emitter::{Emitter, EmitterWriter}; +use errors::json::JsonEmitter; use syntax::ast::CRATE_NODE_ID; -use syntax::source_map; use syntax::attr; -use errors::json::JsonEmitter; +use syntax::source_map; use syntax::symbol::sym; use syntax_pos::DUMMY_SP; -use errors::emitter::{Emitter, EmitterWriter}; +use rustc_data_structures::sync::{self, Lrc}; use std::cell::RefCell; use std::mem; -use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; -use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{MAX_DEF_ID, AttributesExt}; +use crate::clean::{AttributesExt, MAX_DEF_ID}; +use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::html::render::RenderInfo; use crate::passes; -pub use rustc::session::config::{Input, Options, CodegenOptions}; +pub use rustc::session::config::{CodegenOptions, Input, Options}; pub use rustc::session::search_paths::SearchPath; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'tcx> { - pub tcx: TyCtxt<'tcx>, pub resolver: Rc>, /// Later on moved into `html::render::CACHE_KEY` @@ -53,7 +52,6 @@ pub struct DocContext<'tcx> { pub active_extern_traits: RefCell>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: - /// Table `DefId` of type parameter -> substituted type pub ty_substs: RefCell>, /// Table `DefId` of lifetime parameter -> substituted lifetime @@ -76,18 +74,24 @@ impl<'tcx> DocContext<'tcx> { } pub fn enter_resolver(&self, f: F) -> R - where F: FnOnce(&mut resolve::Resolver<'_>) -> R { + where + F: FnOnce(&mut resolve::Resolver<'_>) -> R, + { self.resolver.borrow_mut().access(f) } /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. - pub fn enter_alias(&self, - ty_substs: FxHashMap, - lt_substs: FxHashMap, - ct_substs: FxHashMap, - f: F) -> R - where F: FnOnce() -> R { + pub fn enter_alias( + &self, + ty_substs: FxHashMap, + lt_substs: FxHashMap, + ct_substs: FxHashMap, + f: F, + ) -> R + where + F: FnOnce() -> R, + { let (old_tys, old_lts, old_cts) = ( mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs), mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs), @@ -111,19 +115,12 @@ impl<'tcx> DocContext<'tcx> { pub fn next_def_id(&self, crate_num: CrateNum) -> DefId { let start_def_id = { let next_id = if crate_num == LOCAL_CRATE { - self.tcx - .hir() - .definitions() - .def_path_table() - .next_id() + self.tcx.hir().definitions().def_path_table().next_id() } else { self.enter_resolver(|r| r.cstore().def_path_table(crate_num).next_id()) }; - DefId { - krate: crate_num, - index: next_id, - } + DefId { krate: crate_num, index: next_id } }; let mut fake_ids = self.fake_def_ids.borrow_mut(); @@ -131,16 +128,11 @@ impl<'tcx> DocContext<'tcx> { let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone(); fake_ids.insert( crate_num, - DefId { - krate: crate_num, - index: DefIndex::from(def_id.index.index() + 1), - }, + DefId { krate: crate_num, index: DefIndex::from(def_id.index.index() + 1) }, ); MAX_DEF_ID.with(|m| { - m.borrow_mut() - .entry(def_id.krate.clone()) - .or_insert(start_def_id); + m.borrow_mut().entry(def_id.krate.clone()).or_insert(start_def_id); }); self.all_fake_def_ids.borrow_mut().insert(def_id); @@ -159,13 +151,15 @@ impl<'tcx> DocContext<'tcx> { } pub fn stability(&self, id: HirId) -> Option { - self.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_stability(def_id)).cloned() + self.tcx + .hir() + .opt_local_def_id(id) + .and_then(|def_id| self.tcx.lookup_stability(def_id)) + .cloned() } pub fn deprecation(&self, id: HirId) -> Option { - self.tcx.hir().opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_deprecation(def_id)) + self.tcx.hir().opt_local_def_id(id).and_then(|def_id| self.tcx.lookup_deprecation(def_id)) } } @@ -173,10 +167,11 @@ impl<'tcx> DocContext<'tcx> { /// /// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one /// will be created for the handler. -pub fn new_handler(error_format: ErrorOutputType, - source_map: Option>, - treat_err_as_bug: Option, - ui_testing: bool, +pub fn new_handler( + error_format: ErrorOutputType, + source_map: Option>, + treat_err_as_bug: Option, + ui_testing: bool, ) -> errors::Handler { // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so // stick to the defaults @@ -192,22 +187,19 @@ pub fn new_handler(error_format: ErrorOutputType, sessopts.debugging_opts.teach, sessopts.debugging_opts.terminal_width, false, - ).ui_testing(ui_testing) + ) + .ui_testing(ui_testing), ) - }, + } ErrorOutputType::Json { pretty, json_rendered } => { - let source_map = source_map.unwrap_or_else( - || Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()))); + let source_map = source_map.unwrap_or_else(|| { + Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())) + }); Box::new( - JsonEmitter::stderr( - None, - source_map, - pretty, - json_rendered, - false, - ).ui_testing(ui_testing) + JsonEmitter::stderr(None, source_map, pretty, json_rendered, false) + .ui_testing(ui_testing), ) - }, + } }; errors::Handler::with_emitter_and_flags( @@ -248,9 +240,12 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .. } = options; - let extern_names: Vec = externs.iter() + let extern_names: Vec = externs + .iter() .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| name).cloned().collect(); + .map(|(name, _)| name) + .cloned() + .collect(); // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -266,11 +261,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // In addition to those specific lints, we also need to whitelist those given through // command line, otherwise they'll get ignored and we don't want that. - let mut whitelisted_lints = vec![warnings_lint_name.to_owned(), - intra_link_resolution_failure_name.to_owned(), - missing_docs.to_owned(), - missing_doc_example.to_owned(), - private_doc_tests.to_owned()]; + let mut whitelisted_lints = vec![ + warnings_lint_name.to_owned(), + intra_link_resolution_failure_name.to_owned(), + missing_docs.to_owned(), + missing_doc_example.to_owned(), + private_doc_tests.to_owned(), + ]; whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); @@ -280,24 +277,28 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .chain(rustc_lint::SoftLints::get_lints().into_iter()) }; - let lint_opts = lints().filter_map(|lint| { - if lint.name == warnings_lint_name || - lint.name == intra_link_resolution_failure_name { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }).chain(lint_opts.into_iter()).collect::>(); - - let lint_caps = lints().filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }).collect(); + let lint_opts = lints() + .filter_map(|lint| { + if lint.name == warnings_lint_name || lint.name == intra_link_resolution_failure_name { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }) + .chain(lint_opts.into_iter()) + .collect::>(); + + let lint_caps = lints() + .filter_map(|lint| { + // We don't want to whitelist *all* lints so let's + // ignore those ones. + if whitelisted_lints.iter().any(|l| &lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }) + .collect(); let crate_types = if proc_macro_crate { vec![config::CrateType::ProcMacro] @@ -309,11 +310,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt maybe_sysroot, search_paths: libs, crate_types, - lint_opts: if !display_warnings { - lint_opts - } else { - vec![] - }, + lint_opts: if !display_warnings { lint_opts } else { vec![] }, lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), cg: codegen_options, externs, @@ -344,151 +341,164 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt registry: rustc_driver::diagnostics_registry(), }; - interface::run_compiler_in_existing_thread_pool(config, |compiler| compiler.enter(|queries| { - let sess = compiler.session(); - - // We need to hold on to the complete resolver, so we cause everything to be - // cloned for the analysis passes to use. Suboptimal, but necessary in the - // current architecture. - let resolver = { - let parts = abort_on_err(queries.expansion(), sess).peek(); - let resolver = parts.1.borrow(); - - // Before we actually clone it, let's force all the extern'd crates to - // actually be loaded, just in case they're only referred to inside - // intra-doc-links - resolver.borrow_mut().access(|resolver| { - for extern_name in &extern_names { - resolver.resolve_str_path_error( - DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID - ).unwrap_or_else( - |()| panic!("Unable to resolve external crate {}", extern_name) - ); - } - }); - - // Now we're good to clone the resolver because everything should be loaded - resolver.clone() - }; - - if sess.has_errors() { - sess.fatal("Compilation failed, aborting rustdoc"); - } - - let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); - - global_ctxt.enter(|tcx| { - tcx.analysis(LOCAL_CRATE).ok(); - - // Abort if there were any errors so far - sess.abort_if_errors(); - - let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); - // Convert from a HirId set to a DefId set since we don't always have easy access - // to the map from defid -> hirid - let access_levels = AccessLevels { - map: access_levels.map.iter() - .map(|(&k, &v)| (tcx.hir().local_def_id(k), v)) - .collect() - }; + interface::run_compiler_in_existing_thread_pool(config, |compiler| { + compiler.enter(|queries| { + let sess = compiler.session(); + + // We need to hold on to the complete resolver, so we cause everything to be + // cloned for the analysis passes to use. Suboptimal, but necessary in the + // current architecture. + let resolver = { + let parts = abort_on_err(queries.expansion(), sess).peek(); + let resolver = parts.1.borrow(); + + // Before we actually clone it, let's force all the extern'd crates to + // actually be loaded, just in case they're only referred to inside + // intra-doc-links + resolver.borrow_mut().access(|resolver| { + for extern_name in &extern_names { + resolver + .resolve_str_path_error(DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID) + .unwrap_or_else(|()| { + panic!("Unable to resolve external crate {}", extern_name) + }); + } + }); - let mut renderinfo = RenderInfo::default(); - renderinfo.access_levels = access_levels; - - let mut ctxt = DocContext { - tcx, - resolver, - external_traits: Default::default(), - active_extern_traits: Default::default(), - renderinfo: RefCell::new(renderinfo), - ty_substs: Default::default(), - lt_substs: Default::default(), - ct_substs: Default::default(), - impl_trait_bounds: Default::default(), - fake_def_ids: Default::default(), - all_fake_def_ids: Default::default(), - generated_synthetics: Default::default(), - auto_traits: tcx.all_traits(LOCAL_CRATE).iter().cloned().filter(|trait_def_id| { - tcx.trait_is_auto(*trait_def_id) - }).collect(), + // Now we're good to clone the resolver because everything should be loaded + resolver.clone() }; - debug!("crate: {:?}", tcx.hir().krate()); - let mut krate = clean::krate(&mut ctxt); + if sess.has_errors() { + sess.fatal("Compilation failed, aborting rustdoc"); + } - fn report_deprecated_attr(name: &str, diag: &errors::Handler) { - let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ - considered deprecated", name)); - msg.warn("please see https://github.com/rust-lang/rust/issues/44136"); + let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); + + global_ctxt.enter(|tcx| { + tcx.analysis(LOCAL_CRATE).ok(); + + // Abort if there were any errors so far + sess.abort_if_errors(); + + let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); + // Convert from a HirId set to a DefId set since we don't always have easy access + // to the map from defid -> hirid + let access_levels = AccessLevels { + map: access_levels + .map + .iter() + .map(|(&k, &v)| (tcx.hir().local_def_id(k), v)) + .collect(), + }; + + let mut renderinfo = RenderInfo::default(); + renderinfo.access_levels = access_levels; + + let mut ctxt = DocContext { + tcx, + resolver, + external_traits: Default::default(), + active_extern_traits: Default::default(), + renderinfo: RefCell::new(renderinfo), + ty_substs: Default::default(), + lt_substs: Default::default(), + ct_substs: Default::default(), + impl_trait_bounds: Default::default(), + fake_def_ids: Default::default(), + all_fake_def_ids: Default::default(), + generated_synthetics: Default::default(), + auto_traits: tcx + .all_traits(LOCAL_CRATE) + .iter() + .cloned() + .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) + .collect(), + }; + debug!("crate: {:?}", tcx.hir().krate()); + + let mut krate = clean::krate(&mut ctxt); + + fn report_deprecated_attr(name: &str, diag: &errors::Handler) { + let mut msg = diag.struct_warn(&format!( + "the `#![doc({})]` attribute is \ + considered deprecated", + name + )); + msg.warn("please see https://github.com/rust-lang/rust/issues/44136"); + + if name == "no_default_passes" { + msg.help("you may want to use `#![doc(document_private_items)]`"); + } - if name == "no_default_passes" { - msg.help("you may want to use `#![doc(document_private_items)]`"); + msg.emit(); } - msg.emit(); - } - - // Process all of the crate attributes, extracting plugin metadata along - // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { - let diag = ctxt.sess().diagnostic(); - - let name = attr.name_or_empty(); - if attr.is_word() { - if name == sym::no_default_passes { - report_deprecated_attr("no_default_passes", diag); - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::None; + // Process all of the crate attributes, extracting plugin metadata along + // with the passes which we are supposed to run. + for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { + let diag = ctxt.sess().diagnostic(); + + let name = attr.name_or_empty(); + if attr.is_word() { + if name == sym::no_default_passes { + report_deprecated_attr("no_default_passes", diag); + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::None; + } + } + } else if let Some(value) = attr.value_str() { + let sink = match name { + sym::passes => { + report_deprecated_attr("passes = \"...\"", diag); + &mut manual_passes + } + sym::plugins => { + report_deprecated_attr("plugins = \"...\"", diag); + eprintln!( + "WARNING: `#![doc(plugins = \"...\")]` \ + no longer functions; see CVE-2018-1000622" + ); + continue; + } + _ => continue, + }; + for name in value.as_str().split_whitespace() { + sink.push(name.to_string()); } } - } else if let Some(value) = attr.value_str() { - let sink = match name { - sym::passes => { - report_deprecated_attr("passes = \"...\"", diag); - &mut manual_passes - }, - sym::plugins => { - report_deprecated_attr("plugins = \"...\"", diag); - eprintln!("WARNING: `#![doc(plugins = \"...\")]` \ - no longer functions; see CVE-2018-1000622"); - continue - }, - _ => continue, - }; - for name in value.as_str().split_whitespace() { - sink.push(name.to_string()); - } - } - if attr.is_word() && name == sym::document_private_items { - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::Private; + if attr.is_word() && name == sym::document_private_items { + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::Private; + } } } - } - let passes = passes::defaults(default_passes).iter().chain(manual_passes.into_iter() - .flat_map(|name| { - if let Some(pass) = passes::find_pass(&name) { - Some(pass) - } else { - error!("unknown pass {}, skipping", name); - None - } - })); + let passes = passes::defaults(default_passes).iter().chain( + manual_passes.into_iter().flat_map(|name| { + if let Some(pass) = passes::find_pass(&name) { + Some(pass) + } else { + error!("unknown pass {}, skipping", name); + None + } + }), + ); - info!("Executing passes"); + info!("Executing passes"); - for pass in passes { - debug!("running pass {}", pass.name); - krate = (pass.pass)(krate, &ctxt); - } + for pass in passes { + debug!("running pass {}", pass.name); + krate = (pass.pass)(krate, &ctxt); + } - ctxt.sess().abort_if_errors(); + ctxt.sess().abort_if_errors(); - (krate, ctxt.renderinfo.into_inner(), render_options) + (krate, ctxt.renderinfo.into_inner(), render_options) + }) }) - })) + }) } /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 11d50cb7ce628..0b4abe0a22e3b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,6 +1,7 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/")] - +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/" +)] #![feature(rustc_private)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] @@ -16,30 +17,30 @@ #![feature(drain_filter)] #![feature(never_type)] #![feature(unicode_internals)] +#![recursion_limit = "256"] -#![recursion_limit="256"] - -extern crate getopts; extern crate env_logger; +extern crate getopts; extern crate rustc; extern crate rustc_data_structures; extern crate rustc_driver; -extern crate rustc_feature; extern crate rustc_error_codes; +extern crate rustc_feature; extern crate rustc_index; -extern crate rustc_resolve; -extern crate rustc_lint; extern crate rustc_interface; +extern crate rustc_lexer; +extern crate rustc_lint; extern crate rustc_metadata; extern crate rustc_parse; +extern crate rustc_resolve; extern crate rustc_target; extern crate rustc_typeck; -extern crate rustc_lexer; extern crate syntax; extern crate syntax_expand; extern crate syntax_pos; extern crate test as testing; -#[macro_use] extern crate log; +#[macro_use] +extern crate log; extern crate rustc_errors as errors; use std::default::Default; @@ -47,8 +48,8 @@ use std::env; use std::panic; use std::process; -use rustc::session::{early_warn, early_error}; -use rustc::session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; +use rustc::session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; +use rustc::session::{early_error, early_warn}; #[macro_use] mod externalfiles; @@ -60,23 +61,23 @@ mod docfs; mod doctree; mod fold; pub mod html { - crate mod highlight; crate mod escape; - crate mod item_type; crate mod format; + crate mod highlight; + crate mod item_type; crate mod layout; pub mod markdown; crate mod render; + crate mod sources; crate mod static_files; crate mod toc; - crate mod sources; } mod markdown; mod passes; -mod visit_ast; -mod visit_lib; mod test; mod theme; +mod visit_ast; +mod visit_lib; struct Output { krate: clean::Crate, @@ -92,29 +93,41 @@ pub fn main() { }; rustc_driver::set_sigpipe_handler(); env_logger::init_from_env("RUSTDOC_LOG"); - let res = std::thread::Builder::new().stack_size(thread_stack_size).spawn(move || { - get_args().map(|args| main_args(&args)).unwrap_or(1) - }).unwrap().join().unwrap_or(rustc_driver::EXIT_FAILURE); + let res = std::thread::Builder::new() + .stack_size(thread_stack_size) + .spawn(move || get_args().map(|args| main_args(&args)).unwrap_or(1)) + .unwrap() + .join() + .unwrap_or(rustc_driver::EXIT_FAILURE); process::exit(res); } fn get_args() -> Option> { - env::args_os().enumerate() - .map(|(i, arg)| arg.into_string().map_err(|arg| { - early_warn(ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg)); - }).ok()) + env::args_os() + .enumerate() + .map(|(i, arg)| { + arg.into_string() + .map_err(|arg| { + early_warn( + ErrorOutputType::default(), + &format!("Argument {} is not valid Unicode: {:?}", i, arg), + ); + }) + .ok() + }) .collect() } fn stable(name: &'static str, f: F) -> RustcOptGroup - where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static +where + F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup::stable(name, f) } fn unstable(name: &'static str, f: F) -> RustcOptGroup - where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static +where + F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup::unstable(name, f) } @@ -125,118 +138,127 @@ fn opts() -> Vec { stable("V", |o| o.optflag("V", "version", "print rustdoc's version")), stable("v", |o| o.optflag("v", "verbose", "use verbose output")), stable("r", |o| { - o.optopt("r", "input-format", "the input type of the specified file", - "[rust]") - }), - stable("w", |o| { - o.optopt("w", "output-format", "the output type to write", "[html]") + o.optopt("r", "input-format", "the input type of the specified file", "[rust]") }), + stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")), stable("o", |o| o.optopt("o", "output", "where to place the output", "PATH")), stable("crate-name", |o| { o.optopt("", "crate-name", "specify the name of this crate", "NAME") }), make_crate_type_option(), stable("L", |o| { - o.optmulti("L", "library-path", "directory to add to crate search path", - "DIR") + o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") }), stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), - stable("extern", |o| { - o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]") - }), + stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")), unstable("extern-html-root-url", |o| { - o.optmulti("", "extern-html-root-url", - "base URL to use for dependencies", "NAME=URL") - }), - stable("plugin-path", |o| { - o.optmulti("", "plugin-path", "removed", "DIR") + o.optmulti("", "extern-html-root-url", "base URL to use for dependencies", "NAME=URL") }), + stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")), stable("C", |o| { o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]") }), stable("passes", |o| { - o.optmulti("", "passes", - "list of passes to also run, you might want \ + o.optmulti( + "", + "passes", + "list of passes to also run, you might want \ to pass it multiple times; a value of `list` \ will print available passes", - "PASSES") - }), - stable("plugins", |o| { - o.optmulti("", "plugins", "removed", - "PLUGINS") - }), - stable("no-default", |o| { - o.optflag("", "no-defaults", "don't run the default passes") + "PASSES", + ) }), + stable("plugins", |o| o.optmulti("", "plugins", "removed", "PLUGINS")), + stable("no-default", |o| o.optflag("", "no-defaults", "don't run the default passes")), stable("document-private-items", |o| { o.optflag("", "document-private-items", "document private items") }), stable("test", |o| o.optflag("", "test", "run code examples as tests")), stable("test-args", |o| { - o.optmulti("", "test-args", "arguments to pass to the test runner", - "ARGS") + o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") }), stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), stable("markdown-css", |o| { - o.optmulti("", "markdown-css", - "CSS files to include via in a rendered Markdown file", - "FILES") + o.optmulti( + "", + "markdown-css", + "CSS files to include via in a rendered Markdown file", + "FILES", + ) }), - stable("html-in-header", |o| { - o.optmulti("", "html-in-header", - "files to include inline in the section of a rendered Markdown file \ + stable("html-in-header", |o| { + o.optmulti( + "", + "html-in-header", + "files to include inline in the section of a rendered Markdown file \ or generated documentation", - "FILES") + "FILES", + ) }), stable("html-before-content", |o| { - o.optmulti("", "html-before-content", - "files to include inline between and the content of a rendered \ + o.optmulti( + "", + "html-before-content", + "files to include inline between and the content of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), stable("html-after-content", |o| { - o.optmulti("", "html-after-content", - "files to include inline between the content and of a rendered \ + o.optmulti( + "", + "html-after-content", + "files to include inline between the content and of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), unstable("markdown-before-content", |o| { - o.optmulti("", "markdown-before-content", - "files to include inline between and the content of a rendered \ + o.optmulti( + "", + "markdown-before-content", + "files to include inline between and the content of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), unstable("markdown-after-content", |o| { - o.optmulti("", "markdown-after-content", - "files to include inline between the content and of a rendered \ + o.optmulti( + "", + "markdown-after-content", + "files to include inline between the content and of a rendered \ Markdown file or generated documentation", - "FILES") + "FILES", + ) }), stable("markdown-playground-url", |o| { - o.optopt("", "markdown-playground-url", - "URL to send code snippets to", "URL") + o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL") }), stable("markdown-no-toc", |o| { o.optflag("", "markdown-no-toc", "don't include table of contents") }), stable("e", |o| { - o.optopt("e", "extend-css", - "To add some CSS rules with a given file to generate doc with your \ + o.optopt( + "e", + "extend-css", + "To add some CSS rules with a given file to generate doc with your \ own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", "PATH") + changes, so be careful!", + "PATH", + ) }), unstable("Z", |o| { - o.optmulti("Z", "", - "internal and debugging options (only on nightly build)", "FLAG") - }), - stable("sysroot", |o| { - o.optopt("", "sysroot", "Override the system root", "PATH") + o.optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG") }), + stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")), unstable("playground-url", |o| { - o.optopt("", "playground-url", - "URL to send code snippets to, may be reset by --markdown-playground-url \ + o.optopt( + "", + "playground-url", + "URL to send code snippets to, may be reset by --markdown-playground-url \ or `#![doc(html_playground_url=...)]`", - "URL") + "URL", + ) }), unstable("display-warnings", |o| { o.optflag("", "display-warnings", "to print code warnings when testing doc") @@ -245,69 +267,70 @@ fn opts() -> Vec { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), unstable("sort-modules-by-appearance", |o| { - o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \ - program, rather than alphabetically") + o.optflag( + "", + "sort-modules-by-appearance", + "sort modules by where they appear in the \ + program, rather than alphabetically", + ) }), stable("theme", |o| { - o.optmulti("", "theme", - "additional themes which will be added to the generated docs", - "FILES") + o.optmulti( + "", + "theme", + "additional themes which will be added to the generated docs", + "FILES", + ) }), stable("check-theme", |o| { - o.optmulti("", "check-theme", - "check if given theme is valid", - "FILES") + o.optmulti("", "check-theme", "check if given theme is valid", "FILES") }), unstable("resource-suffix", |o| { - o.optopt("", - "resource-suffix", - "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ + o.optopt( + "", + "resource-suffix", + "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ \"light-suffix.css\"", - "PATH") + "PATH", + ) }), stable("edition", |o| { - o.optopt("", "edition", - "edition to use when compiling rust code (default: 2015)", - "EDITION") + o.optopt( + "", + "edition", + "edition to use when compiling rust code (default: 2015)", + "EDITION", + ) }), stable("color", |o| { - o.optopt("", - "color", - "Configure coloring of output: + o.optopt( + "", + "color", + "Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output", - "auto|always|never") + "auto|always|never", + ) }), stable("error-format", |o| { - o.optopt("", - "error-format", - "How errors and other messages are produced", - "human|json|short") + o.optopt( + "", + "error-format", + "How errors and other messages are produced", + "human|json|short", + ) }), stable("json", |o| { - o.optopt("", - "json", - "Configure the structure of JSON diagnostics", - "CONFIG") + o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG") }), unstable("disable-minification", |o| { - o.optflag("", - "disable-minification", - "Disable minification applied on JS files") - }), - stable("warn", |o| { - o.optmulti("W", "warn", "Set lint warnings", "OPT") - }), - stable("allow", |o| { - o.optmulti("A", "allow", "Set lint allowed", "OPT") - }), - stable("deny", |o| { - o.optmulti("D", "deny", "Set lint denied", "OPT") - }), - stable("forbid", |o| { - o.optmulti("F", "forbid", "Set lint forbidden", "OPT") + o.optflag("", "disable-minification", "Disable minification applied on JS files") }), + stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "OPT")), + stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "OPT")), + stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "OPT")), + stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "OPT")), stable("cap-lints", |o| { o.optmulti( "", @@ -319,65 +342,78 @@ fn opts() -> Vec { ) }), unstable("index-page", |o| { - o.optopt("", - "index-page", - "Markdown file to be used as index page", - "PATH") + o.optopt("", "index-page", "Markdown file to be used as index page", "PATH") }), unstable("enable-index-page", |o| { - o.optflag("", - "enable-index-page", - "To enable generation of the index page") + o.optflag("", "enable-index-page", "To enable generation of the index page") }), unstable("static-root-path", |o| { - o.optopt("", - "static-root-path", - "Path string to force loading static files from in output pages. \ + o.optopt( + "", + "static-root-path", + "Path string to force loading static files from in output pages. \ If not set, uses combinations of '../' to reach the documentation root.", - "PATH") + "PATH", + ) }), unstable("disable-per-crate-search", |o| { - o.optflag("", - "disable-per-crate-search", - "disables generating the crate selector on the search box") + o.optflag( + "", + "disable-per-crate-search", + "disables generating the crate selector on the search box", + ) }), unstable("persist-doctests", |o| { - o.optopt("", - "persist-doctests", - "Directory to persist doctest executables into", - "PATH") + o.optopt( + "", + "persist-doctests", + "Directory to persist doctest executables into", + "PATH", + ) }), unstable("generate-redirect-pages", |o| { - o.optflag("", - "generate-redirect-pages", - "Generate extra pages to support legacy URLs and tool links") + o.optflag( + "", + "generate-redirect-pages", + "Generate extra pages to support legacy URLs and tool links", + ) }), unstable("show-coverage", |o| { - o.optflag("", - "show-coverage", - "calculate percentage of public items with documentation") + o.optflag( + "", + "show-coverage", + "calculate percentage of public items with documentation", + ) }), unstable("enable-per-target-ignores", |o| { - o.optflag("", - "enable-per-target-ignores", - "parse ignore-foo for ignoring doctests on a per-target basis") + o.optflag( + "", + "enable-per-target-ignores", + "parse ignore-foo for ignoring doctests on a per-target basis", + ) }), unstable("runtool", |o| { - o.optopt("", - "runtool", - "", - "The tool to run tests with when building for a different target than host") + o.optopt( + "", + "runtool", + "", + "The tool to run tests with when building for a different target than host", + ) }), unstable("runtool-arg", |o| { - o.optmulti("", - "runtool-arg", - "", - "One (of possibly many) arguments to pass to the runtool") + o.optmulti( + "", + "runtool-arg", + "", + "One (of possibly many) arguments to pass to the runtool", + ) }), unstable("test-builder", |o| { - o.optflag("", - "test-builder", - "specified the rustc-like binary to use as the test builder") + o.optflag( + "", + "test-builder", + "specified the rustc-like binary to use as the test builder", + ) }), ] } @@ -405,33 +441,34 @@ fn main_args(args: &[String]) -> i32 { Ok(opts) => opts, Err(code) => return code, }; - rustc_interface::interface::default_thread_pool(options.edition, move || { - main_options(options) - }) + rustc_interface::interface::default_thread_pool(options.edition, move || main_options(options)) } fn main_options(options: config::Options) -> i32 { - let diag = core::new_handler(options.error_format, - None, - options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing); + let diag = core::new_handler( + options.error_format, + None, + options.debugging_options.treat_err_as_bug, + options.debugging_options.ui_testing, + ); match (options.should_test, options.markdown_input()) { (true, true) => return markdown::test(options, &diag), (true, false) => return test::run(options), - (false, true) => return markdown::render(options.input, - options.render_options, - &diag, - options.edition), + (false, true) => { + return markdown::render(options.input, options.render_options, &diag, options.edition); + } (false, false) => {} } // need to move these items separately because we lose them by the time the closure is called, // but we can't crates the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, - options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing, - options.edition); + let diag_opts = ( + options.error_format, + options.debugging_options.treat_err_as_bug, + options.debugging_options.ui_testing, + options.edition, + ); let show_coverage = options.show_coverage; rust_input(options, move |out| { if show_coverage { @@ -444,13 +481,7 @@ fn main_options(options: config::Options) -> i32 { info!("going to format"); let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts; let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing); - match html::render::run( - krate, - renderopts, - renderinfo, - &diag, - edition, - ) { + match html::render::run(krate, renderopts, renderinfo, &diag, edition) { Ok(_) => rustc_driver::EXIT_SUCCESS, Err(e) => { diag.struct_err(&format!("couldn't generate documentation: {}", e.error)) @@ -468,8 +499,9 @@ fn main_options(options: config::Options) -> i32 { /// /// This form of input will run all of the plug/cleaning passes fn rust_input(options: config::Options, f: F) -> R -where R: 'static + Send, - F: 'static + Send + FnOnce(Output) -> R +where + R: 'static + Send, + F: 'static + Send + FnOnce(Output) -> R, { // First, parse the crate and extract all relevant information. info!("starting to run rustc"); @@ -487,11 +519,7 @@ where R: 'static + Send, krate.version = crate_version; - f(Output { - krate, - renderinfo, - renderopts, - }) + f(Output { krate, renderinfo, renderopts }) }); match result { diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index dc1ca8d7668ae..75f874d83274e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -4,8 +4,8 @@ use crate::fold::{self, DocFolder}; use crate::passes::Pass; use syntax::attr; -use syntax_pos::FileName; use syntax::symbol::sym; +use syntax_pos::FileName; use std::collections::BTreeMap; use std::ops; @@ -53,10 +53,7 @@ impl ops::Sub for ItemCount { type Output = Self; fn sub(self, rhs: Self) -> Self { - ItemCount { - total: self.total - rhs.total, - with_docs: self.with_docs - rhs.with_docs, - } + ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs } } } @@ -81,13 +78,17 @@ impl CoverageCalculator { } fn print_table_record(name: &str, count: ItemCount, percentage: f64) { - println!("| {:<35} | {:>10} | {:>10} | {:>9.1}% |", - name, count.with_docs, count.total, percentage); + println!( + "| {:<35} | {:>10} | {:>10} | {:>9.1}% |", + name, count.with_docs, count.total, percentage + ); } print_table_line(); - println!("| {:<35} | {:>10} | {:>10} | {:>10} |", - "File", "Documented", "Total", "Percentage"); + println!( + "| {:<35} | {:>10} | {:>10} | {:>10} |", + "File", "Documented", "Total", "Percentage" + ); print_table_line(); for (file, &count) in &self.items { @@ -97,7 +98,7 @@ impl CoverageCalculator { // FIXME(misdreavus): this needs to count graphemes, and probably also track // double-wide characters... if name.len() > 35 { - name = "...".to_string() + &name[name.len()-32..]; + name = "...".to_string() + &name[name.len() - 32..]; } print_table_record(&name, count, percentage); @@ -133,7 +134,8 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived) - || impl_.synthetic || impl_.blanket_impl.is_some() => + || impl_.synthetic + || impl_.blanket_impl.is_some() => { // built-in derives get the `#[automatically_derived]` attribute, and // synthetic/blanket impls are made up by rustdoc and can't be documented @@ -142,8 +144,12 @@ impl fold::DocFolder for CoverageCalculator { } clean::ImplItem(ref impl_) => { if let Some(ref tr) = impl_.trait_ { - debug!("impl {:#} for {:#} in {}", - tr.print(), impl_.for_.print(), i.source.filename); + debug!( + "impl {:#} for {:#} in {}", + tr.print(), + impl_.for_.print(), + i.source.filename + ); // don't count trait impls, the missing-docs lint doesn't so we shouldn't // either @@ -157,9 +163,7 @@ impl fold::DocFolder for CoverageCalculator { } _ => { debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); - self.items.entry(i.source.filename.clone()) - .or_default() - .count_item(has_docs); + self.items.entry(i.source.filename.clone()).or_default().count_item(has_docs); } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 8d5463ddbd764..7bbed4af23838 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,9 +1,9 @@ use errors::Applicability; -use rustc_parse::lexer::{StringReader as Lexer}; -use syntax::token; +use rustc_parse::lexer::StringReader as Lexer; use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; -use syntax_pos::{InnerSpan, FileName}; +use syntax::token; +use syntax_pos::{FileName, InnerSpan}; use crate::clean; use crate::core::DocContext; @@ -38,7 +38,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { let mut only_whitespace = true; // even if there is a syntax error, we need to run the lexer over the whole file let mut lexer = Lexer::new(&sess, source_file, None); - loop { + loop { match lexer.next_token().kind { token::Eof => break, token::Whitespace => (), diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 31288345ce57b..c6b22883e9723 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -1,7 +1,7 @@ use crate::clean::{self, DocFragment, Item}; use crate::core::DocContext; use crate::fold; -use crate::fold::{DocFolder}; +use crate::fold::DocFolder; use crate::passes::Pass; use std::mem::take; @@ -56,10 +56,10 @@ fn collapse(doc_strings: &mut Vec) { if curr_kind == DocFragmentKind::Include || curr_kind != new_kind { match curr_frag { DocFragment::SugaredDoc(_, _, ref mut doc_string) - | DocFragment::RawDoc(_, _, ref mut doc_string) => { - // add a newline for extra padding between segments - doc_string.push('\n'); - } + | DocFragment::RawDoc(_, _, ref mut doc_string) => { + // add a newline for extra padding between segments + doc_string.push('\n'); + } _ => {} } docs.push(curr_frag); @@ -67,11 +67,11 @@ fn collapse(doc_strings: &mut Vec) { } else { match curr_frag { DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string) - | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { - doc_string.push('\n'); - doc_string.push_str(frag.as_str()); - *span = span.to(frag.span()); - } + | DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { + doc_string.push('\n'); + doc_string.push_str(frag.as_str()); + *span = span.to(frag.span()); + } _ => unreachable!(), } last_frag = Some(curr_frag); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3c021ae746523..af850a3446799 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,23 +1,27 @@ use errors::Applicability; -use rustc::hir::def::{Res, DefKind, Namespace::{self, *}, PerNS}; -use rustc::hir::def_id::DefId; use rustc::hir; -use rustc::lint as lint; +use rustc::hir::def::{ + DefKind, + Namespace::{self, *}, + PerNS, Res, +}; +use rustc::hir::def_id::DefId; +use rustc::lint; use rustc::ty; -use rustc_resolve::ParentScope; use rustc_feature::UnstableFeatures; +use rustc_resolve::ParentScope; use syntax; use syntax::ast::{self, Ident}; -use syntax_expand::base::SyntaxExtensionKind; use syntax::symbol::Symbol; +use syntax_expand::base::SyntaxExtensionKind; use syntax_pos::DUMMY_SP; use std::ops::Range; +use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; -use crate::clean::*; use crate::passes::{look_for_tests, Pass}; use super::span_of_attrs; @@ -50,10 +54,7 @@ struct LinkCollector<'a, 'tcx> { impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - LinkCollector { - cx, - mod_ids: Vec::new(), - } + LinkCollector { cx, mod_ids: Vec::new() } } fn variant_field( @@ -65,44 +66,51 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let cx = self.cx; let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = split + let variant_field_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let variant_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let path = split .next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let variant_name = split - .next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let path = split.next().map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); + } } - } - f.to_owned() - }).ok_or(ErrorKind::ResolutionFailure)?; - let (_, ty_res) = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }).map_err(|_| ErrorKind::ResolutionFailure)?; + f.to_owned() + }) + .ok_or(ErrorKind::ResolutionFailure)?; + let (_, ty_res) = cx + .enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + }) + .map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { return Err(ErrorKind::ResolutionFailure); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { Res::Def(DefKind::Enum, did) => { - if cx.tcx.inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) - .any(|item| item.ident.name == variant_name) { + if cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp)) + .any(|item| item.ident.name == variant_name) + { return Err(ErrorKind::ResolutionFailure); } match cx.tcx.type_of(did).kind { ty::Adt(def, _) if def.is_enum() => { - if def.all_fields() - .any(|item| item.ident.name == variant_field_name) { - Ok((ty_res, - Some(format!("variant.{}.field.{}", - variant_name, variant_field_name)))) + if def.all_fields().any(|item| item.ident.name == variant_field_name) { + Ok(( + ty_res, + Some(format!( + "variant.{}.field.{}", + variant_name, variant_field_name + )), + )) } else { Err(ErrorKind::ResolutionFailure) } @@ -110,7 +118,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => Err(ErrorKind::ResolutionFailure), } } - _ => Err(ErrorKind::ResolutionFailure) + _ => Err(ErrorKind::ResolutionFailure), } } @@ -150,50 +158,55 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Not a trait item; just return what we found. Res::PrimTy(..) => { if extra_fragment.is_some() { - return Err( - ErrorKind::AnchorFailure( - "primitive types cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure( + "primitive types cannot be followed by anchors", + )); } return Ok((res, Some(path_str.to_owned()))); } - _ => return Ok((res, extra_fragment.clone())) + _ => return Ok((res, extra_fragment.clone())), }; if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure) + return Err(ErrorKind::ResolutionFailure); } } else if let Some(prim) = is_primitive(path_str, ns) { if extra_fragment.is_some() { - return Err( - ErrorKind::AnchorFailure("primitive types cannot be followed by anchors")); + return Err(ErrorKind::AnchorFailure( + "primitive types cannot be followed by anchors", + )); } - return Ok((prim, Some(path_str.to_owned()))) + return Ok((prim, Some(path_str.to_owned()))); } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver // If so, bail when we're not looking for a value. if ns != ValueNS { - return Err(ErrorKind::ResolutionFailure) + return Err(ErrorKind::ResolutionFailure); } } // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); - let item_name = split.next() - .map(|f| Symbol::intern(f)) - .ok_or(ErrorKind::ResolutionFailure)?; - let path = split.next().map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); + let item_name = + split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let path = split + .next() + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); + } } - } - f.to_owned() - }).ok_or(ErrorKind::ResolutionFailure)?; + f.to_owned() + }) + .ok_or(ErrorKind::ResolutionFailure)?; if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?; - return cx.tcx.associated_items(did) + return cx + .tcx + .associated_items(did) .find(|item| item.ident.name == item_name) .and_then(|item| match item.kind { ty::AssocKind::Method => Some("method"), @@ -203,9 +216,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .ok_or(ErrorKind::ResolutionFailure); } - let (_, ty_res) = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }).map_err(|_| ErrorKind::ResolutionFailure)?; + let (_, ty_res) = cx + .enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) + }) + .map_err(|_| ErrorKind::ResolutionFailure)?; if let Res::Err = ty_res { return self.variant_field(path_str, current_item, module_id); } @@ -215,10 +230,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { | Res::Def(DefKind::Union, did) | Res::Def(DefKind::Enum, did) | Res::Def(DefKind::TyAlias, did) => { - let item = cx.tcx.inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) - .find(|item| item.ident.name == item_name); + let item = cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp)) + .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { ty::AssocKind::Method if ns == ValueNS => "method", @@ -226,12 +243,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => return self.variant_field(path_str, current_item, module_id), }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if item.kind == ty::AssocKind::Method { - "methods cannot be followed by anchors" - } else { - "associated constants cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Method { + "methods cannot be followed by anchors" + } else { + "associated constants cannot be followed by anchors" + })) } else { Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } @@ -242,26 +258,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { def.all_fields().find(|item| item.ident.name == item_name) } else { def.non_enum_variant() - .fields - .iter() - .find(|item| item.ident.name == item_name) + .fields + .iter() + .find(|item| item.ident.name == item_name) } { if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if def.is_enum() { - "enum variants cannot be followed by anchors" - } else { - "struct fields cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if def.is_enum() { + "enum variants cannot be followed by anchors" + } else { + "struct fields cannot be followed by anchors" + })) } else { - Ok((ty_res, - Some(format!("{}.{}", - if def.is_enum() { - "variant" - } else { - "structfield" - }, - item.ident)))) + Ok(( + ty_res, + Some(format!( + "{}.{}", + if def.is_enum() { + "variant" + } else { + "structfield" + }, + item.ident + )), + )) } } else { self.variant_field(path_str, current_item, module_id) @@ -272,32 +291,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } Res::Def(DefKind::Trait, did) => { - let item = cx.tcx.associated_item_def_ids(did).iter() - .map(|item| cx.tcx.associated_item(*item)) - .find(|item| item.ident.name == item_name); + let item = cx + .tcx + .associated_item_def_ids(did) + .iter() + .map(|item| cx.tcx.associated_item(*item)) + .find(|item| item.ident.name == item_name); if let Some(item) = item { let kind = match item.kind { ty::AssocKind::Const if ns == ValueNS => "associatedconstant", ty::AssocKind::Type if ns == TypeNS => "associatedtype", ty::AssocKind::Method if ns == ValueNS => { - if item.defaultness.has_value() { - "method" - } else { - "tymethod" - } + if item.defaultness.has_value() { "method" } else { "tymethod" } } _ => return self.variant_field(path_str, current_item, module_id), }; if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure( - if item.kind == ty::AssocKind::Const { - "associated constants cannot be followed by anchors" - } else if item.kind == ty::AssocKind::Type { - "associated types cannot be followed by anchors" - } else { - "methods cannot be followed by anchors" - })) + Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { + "associated constants cannot be followed by anchors" + } else if item.kind == ty::AssocKind::Type { + "associated types cannot be followed by anchors" + } else { + "methods cannot be followed by anchors" + })) } else { Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) } @@ -344,11 +361,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let current_item = match item.inner { ModuleItem(..) => { if item.attrs.inner_docs { - if item_hir_id.unwrap() != hir::CRATE_HIR_ID { - item.name.clone() - } else { - None - } + if item_hir_id.unwrap() != hir::CRATE_HIR_ID { item.name.clone() } else { None } } else { match parent_node.or(self.mod_ids.last().cloned()) { Some(parent) if parent != hir::CRATE_HIR_ID => { @@ -392,10 +405,16 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let link = ori_link.replace("`", ""); let parts = link.split('#').collect::>(); let (link, extra_fragment) = if parts.len() > 2 { - build_diagnostic(cx, &item, &link, &dox, link_range, - "has an issue with the link anchor.", - "only one `#` is allowed in a link", - None); + build_diagnostic( + cx, + &item, + &link, + &dox, + link_range, + "has an issue with the link anchor.", + "only one `#` is allowed in a link", + None, + ); continue; } else if parts.len() == 2 { if parts[0].trim().is_empty() { @@ -409,16 +428,25 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let (res, fragment) = { let mut kind = None; let path_str = if let Some(prefix) = - ["struct@", "enum@", "type@", - "trait@", "union@"].iter() - .find(|p| link.starts_with(**p)) { + ["struct@", "enum@", "type@", "trait@", "union@"] + .iter() + .find(|p| link.starts_with(**p)) + { kind = Some(TypeNS); link.trim_start_matches(prefix) - } else if let Some(prefix) = - ["const@", "static@", - "value@", "function@", "mod@", - "fn@", "module@", "method@"] - .iter().find(|p| link.starts_with(**p)) { + } else if let Some(prefix) = [ + "const@", + "static@", + "value@", + "function@", + "mod@", + "fn@", + "module@", + "method@", + ] + .iter() + .find(|p| link.starts_with(**p)) + { kind = Some(ValueNS); link.trim_start_matches(prefix) } else if link.ends_with("()") { @@ -432,10 +460,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { link.trim_end_matches('!') } else { &link[..] - }.trim(); + } + .trim(); - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || - ch == ':' || ch == '_')) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { continue; } @@ -450,16 +478,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // we've already pushed this node onto the resolution stack but // for outer comments we explicitly try and resolve against the // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - None - } else { - parent_node - }; + let base_node = + if item.is_mod() && item.attrs.inner_docs { None } else { parent_node }; match kind { Some(ns @ ValueNS) => { - match self.resolve(path_str, ns, ¤t_item, base_node, - &extra_fragment) { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -470,13 +495,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue + continue; } } } Some(ns @ TypeNS) => { - match self.resolve(path_str, ns, ¤t_item, base_node, - &extra_fragment) { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) + { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { resolution_failure(cx, &item, path_str, &dox, link_range); @@ -485,7 +510,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue + continue; } } } @@ -493,17 +518,27 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // Try everything! let candidates = PerNS { macro_ns: macro_resolve(cx, path_str) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve(path_str, TypeNS, ¤t_item, base_node, - &extra_fragment) { + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; } x => x.ok(), }, - value_ns: match self.resolve(path_str, ValueNS, ¤t_item, - base_node, &extra_fragment) { + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); continue; @@ -553,7 +588,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { (res, extra_fragment) } else { resolution_failure(cx, &item, path_str, &dox, link_range); - continue + continue; } } } @@ -597,7 +632,11 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { if let Ok((Some(ext), res)) = resolver.resolve_macro_path( - &path, None, &ParentScope::module(resolver.graph_root()), false, false + &path, + None, + &ParentScope::module(resolver.graph_root()), + false, + false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { return Some(res.map_id(|_| panic!("unexpected id"))); @@ -652,10 +691,10 @@ fn build_diagnostic( diag.note(&format!( "the link appears in this line:\n\n{line}\n\ {indicator: >, ) { - build_diagnostic(cx, item, path_str, dox, link_range, - "cannot be resolved, ignoring it.", - "cannot be resolved, ignoring", - Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`")); + build_diagnostic( + cx, + item, + path_str, + dox, + link_range, + "cannot be resolved, ignoring it.", + "cannot be resolved, ignoring", + Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"), + ); } fn anchor_failure( @@ -691,10 +736,16 @@ fn anchor_failure( link_range: Option>, msg: &str, ) { - build_diagnostic(cx, item, path_str, dox, link_range, - "has an issue with the link anchor.", - msg, - None); + build_diagnostic( + cx, + item, + path_str, + dox, + link_range, + "has an issue with the link anchor.", + msg, + None, + ); } fn ambiguity_error( @@ -717,9 +768,10 @@ fn ambiguity_error( let mut msg = format!("`{}` is ", path_str); - let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| { - candidates[ns].map(|res| (res, ns)) - }).collect::>(); + let candidates = [TypeNS, ValueNS, MacroNS] + .iter() + .filter_map(|&ns| candidates[ns].map(|res| (res, ns))) + .collect::>(); match candidates.as_slice() { [(first_def, _), (second_def, _)] => { msg += &format!( @@ -804,10 +856,10 @@ fn ambiguity_error( diag.note(&format!( "the link appears in this line:\n\n{line}\n\ {indicator: Option { - if ns == TypeNS { - PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) - } else { - None - } + if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None } } fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option { diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 28c64d0b9638e..4e0d1a101917d 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -1,10 +1,10 @@ +use super::Pass; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use super::Pass; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::util::nodemap::FxHashSet; -use rustc::hir::def_id::{LOCAL_CRATE, DefId}; use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { @@ -17,8 +17,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut synth = SyntheticImplCollector::new(cx); let mut krate = synth.fold_crate(krate); - let prims: FxHashSet = - krate.primitives.iter().map(|p| p.1).collect(); + let prims: FxHashSet = krate.primitives.iter().map(|p| p.1).collect(); let crate_items = { let mut coll = ItemCollector::new(); @@ -80,21 +79,20 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { } } - let mut cleaner = BadImplStripper { - prims, - items: crate_items, - }; + let mut cleaner = BadImplStripper { prims, items: crate_items }; // scan through included items ahead of time to splice in Deref targets to the "valid" sets for it in &new_items { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner { if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() { - let target = items.iter().filter_map(|item| { - match item.inner { + let target = items + .iter() + .filter_map(|item| match item.inner { TypedefItem(ref t, true) => Some(&t.type_), _ => None, - } - }).next().expect("Deref impl without Target type"); + }) + .next() + .expect("Deref impl without Target type"); if let Some(prim) = target.primitive_type() { cleaner.prims.insert(prim); @@ -107,9 +105,9 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { new_items.retain(|it| { if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner { - cleaner.keep_item(for_) || - trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) || - blanket_impl.is_some() + cleaner.keep_item(for_) + || trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) + || blanket_impl.is_some() } else { true } @@ -145,10 +143,7 @@ struct SyntheticImplCollector<'a, 'tcx> { impl<'a, 'tcx> SyntheticImplCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - SyntheticImplCollector { - cx, - impls: Vec::new(), - } + SyntheticImplCollector { cx, impls: Vec::new() } } } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 0a95d4209ac6a..b69207be3fb36 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -2,12 +2,12 @@ //! process. use rustc::hir::def_id::DefId; -use rustc::lint as lint; +use rustc::lint; use rustc::middle::privacy::AccessLevels; use rustc::util::nodemap::DefIdSet; use std::mem; -use syntax_pos::{DUMMY_SP, InnerSpan, Span}; use std::ops::Range; +use syntax_pos::{InnerSpan, Span, DUMMY_SP}; use crate::clean::{self, GetDefId, Item}; use crate::core::DocContext; @@ -57,7 +57,6 @@ pub struct Pass { pub description: &'static str, } - /// The full list of passes. pub const PASSES: &[Pass] = &[ CHECK_PRIVATE_ITEMS_DOC_TESTS, @@ -99,19 +98,12 @@ pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[ ]; /// The list of default passes run when `--doc-coverage` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - STRIP_HIDDEN, - STRIP_PRIVATE, - CALCULATE_DOC_COVERAGE, -]; +pub const DEFAULT_COVERAGE_PASSES: &[Pass] = + &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE]; /// The list of default passes run when `--doc-coverage --document-private-items` is passed to /// rustdoc. -pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - CALCULATE_DOC_COVERAGE, -]; +pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE]; /// A shorthand way to refer to which set of passes to use, based on the presence of /// `--no-defaults` or `--document-private-items`. @@ -229,9 +221,7 @@ impl<'a> DocFolder for Stripper<'a> { // implementations of traits are always public. clean::ImplItem(ref imp) if imp.trait_.is_some() => true, // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant { - kind: clean::VariantKind::Struct(..), - }) => true, + clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, _ => false, }; @@ -281,8 +271,10 @@ impl<'a> DocFolder for ImplStripper<'a> { for typaram in generics { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { - debug!("ImplStripper: stripped item in trait's generics; \ - removing impl"); + debug!( + "ImplStripper: stripped item in trait's generics; \ + removing impl" + ); return None; } } @@ -298,9 +290,7 @@ struct ImportStripper; impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.inner { - clean::ExternCrateItem(..) | clean::ImportItem(..) - if i.visibility != clean::Public => - { + clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { None } _ => self.fold_item_recur(i), @@ -332,9 +322,7 @@ pub fn look_for_tests<'tcx>( } } - let mut tests = Tests { - found_tests: 0, - }; + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false); @@ -344,16 +332,19 @@ pub fn look_for_tests<'tcx>( lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, - "missing code example in this documentation"); + "missing code example in this documentation", + ); diag.emit(); - } else if check_missing_code == false && - tests.found_tests > 0 && - !cx.renderinfo.borrow().access_levels.is_public(item.def_id) { + } else if check_missing_code == false + && tests.found_tests > 0 + && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) + { let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, hir_id, span_of_attrs(&item.attrs).unwrap_or(item.source.span()), - "documentation test in private item"); + "documentation test in private item", + ); diag.emit(); } } @@ -391,11 +382,7 @@ crate fn source_span_for_markdown_range( return None; } - let snippet = cx - .sess() - .source_map() - .span_to_snippet(span_of_attrs(attrs)?) - .ok()?; + let snippet = cx.sess().source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?; let starting_line = markdown[..md_range.start].matches('\n').count(); let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count(); diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 5560ebed9ae69..23e272709705d 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -15,9 +15,7 @@ struct PrivateItemDocTestLinter<'a, 'tcx> { impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { - PrivateItemDocTestLinter { - cx, - } + PrivateItemDocTestLinter { cx } } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index a71a1e001fc69..a296e73e3b5fd 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -1,7 +1,7 @@ use std::sync::Arc; -use crate::clean::{Crate, Item}; use crate::clean::cfg::Cfg; +use crate::clean::{Crate, Item}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 0159e03f6f299..379e2496a0a41 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,8 +2,8 @@ use rustc::util::nodemap::DefIdSet; use std::mem; use syntax::symbol::sym; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::clean::Item; +use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; use crate::passes::{ImplStripper, Pass}; @@ -20,7 +20,7 @@ pub fn strip_hidden(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { // strip all #[doc(hidden)] items let krate = { - let mut stripper = Stripper{ retained: &mut retained, update_retained: true }; + let mut stripper = Stripper { retained: &mut retained, update_retained: true }; stripper.fold_crate(krate) }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 516760ade6667..af34842ad0f89 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -1,6 +1,6 @@ use crate::clean; -use crate::fold::{DocFolder}; use crate::core::DocContext; +use crate::fold::DocFolder; use crate::passes::{ImportStripper, Pass}; pub const STRIP_PRIV_IMPORTS: Pass = Pass { @@ -9,6 +9,6 @@ pub const STRIP_PRIV_IMPORTS: Pass = Pass { description: "strips all private import statements (`use`, `extern crate`) from a crate", }; -pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { +pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { ImportStripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index fc742bf74d006..5113afa48402c 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -1,9 +1,9 @@ use rustc::util::nodemap::DefIdSet; use crate::clean; -use crate::fold::{DocFolder}; use crate::core::DocContext; -use crate::passes::{ImplStripper, ImportStripper, Stripper, Pass}; +use crate::fold::DocFolder; +use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper}; pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 7ad98242fdc92..3212af055efc5 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -38,34 +38,28 @@ impl clean::Attributes { fn unindent_fragments(docs: &mut Vec) { for fragment in docs { match *fragment { - DocFragment::SugaredDoc(_, _, ref mut doc_string) | - DocFragment::RawDoc(_, _, ref mut doc_string) | - DocFragment::Include(_, _, _, ref mut doc_string) => - *doc_string = unindent(doc_string), + DocFragment::SugaredDoc(_, _, ref mut doc_string) + | DocFragment::RawDoc(_, _, ref mut doc_string) + | DocFragment::Include(_, _, _, ref mut doc_string) => { + *doc_string = unindent(doc_string) + } } } } fn unindent(s: &str) -> String { - let lines = s.lines().collect:: >(); + let lines = s.lines().collect::>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { - // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = - saw_first_line && - !saw_second_line && - !line.chars().all(|c| c.is_whitespace()); + saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); - let min_indent = if ignore_previous_indents { - usize::MAX - } else { - min_indent - }; + let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; if saw_first_line { saw_second_line = true; @@ -91,15 +85,20 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim_start().to_string() ]; - unindented.extend_from_slice(&lines[1..].iter().map(|&line| { - if line.chars().all(|c| c.is_whitespace()) { - line.to_string() - } else { - assert!(line.len() >= min_indent); - line[min_indent..].to_string() - } - }).collect::>()); + let mut unindented = vec![lines[0].trim_start().to_string()]; + unindented.extend_from_slice( + &lines[1..] + .iter() + .map(|&line| { + if line.chars().all(|c| c.is_whitespace()) { + line.to_string() + } else { + assert!(line.len() >= min_indent); + line[min_indent..].to_string() + } + }) + .collect::>(), + ); unindented.join("\n") } else { s.to_string() From 4bed1c7b9e98babe6de07ed075a7ee354dd18c28 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 4 Jan 2020 10:58:32 -0800 Subject: [PATCH 20/38] Distinguish between private items and hidden items in rustdoc I believe rustdoc should not be conflating private items (visibility lower than `pub`) and hidden items (attribute `doc(hidden)`). This matters now that Cargo is passing --document-private-items by default for bin crates. In bin crates that rely on macros, intentionally hidden implementation details of the macros can overwhelm the actual useful internal API that one would want to document. This PR restores the strip-hidden pass when documenting private items, and introduces a separate unstable --document-hidden-items option to skip the strip-hidden pass. The two options are orthogonal to one another. --- src/librustdoc/config.rs | 43 +++++---- src/librustdoc/core.rs | 26 ++++-- src/librustdoc/lib.rs | 3 + .../passes/calculate_doc_coverage.rs | 2 +- .../passes/check_code_block_syntax.rs | 2 +- src/librustdoc/passes/collapse_docs.rs | 2 +- .../passes/collect_intra_doc_links.rs | 2 +- src/librustdoc/passes/collect_trait_impls.rs | 2 +- src/librustdoc/passes/mod.rs | 87 +++++++++++-------- .../passes/private_items_doc_tests.rs | 2 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/passes/unindent_comments.rs | 2 +- src/test/rustdoc/issue-46380.rs | 5 -- src/test/rustdoc/issue-67851-both.rs | 8 ++ src/test/rustdoc/issue-67851-hidden.rs | 8 ++ src/test/rustdoc/issue-67851-neither.rs | 6 ++ src/test/rustdoc/issue-67851-private.rs | 8 ++ 20 files changed, 138 insertions(+), 78 deletions(-) delete mode 100644 src/test/rustdoc/issue-46380.rs create mode 100644 src/test/rustdoc/issue-67851-both.rs create mode 100644 src/test/rustdoc/issue-67851-hidden.rs create mode 100644 src/test/rustdoc/issue-67851-neither.rs create mode 100644 src/test/rustdoc/issue-67851-private.rs diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7a3cf88f65e21..eec1ffd75c502 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -24,7 +24,7 @@ use crate::html; use crate::html::markdown::IdMap; use crate::html::static_files; use crate::opts; -use crate::passes::{self, DefaultPassOption}; +use crate::passes::{self, Condition, DefaultPassOption}; use crate::theme; /// Configuration options for rustdoc. @@ -98,6 +98,10 @@ pub struct Options { /// /// Be aware: This option can come both from the CLI and from crate attributes! pub default_passes: DefaultPassOption, + /// Document items that have lower than `pub` visibility. + pub document_private: bool, + /// Document items that have `doc(hidden)`. + pub document_hidden: bool, /// Any passes manually selected by the user. /// /// Be aware: This option can come both from the CLI and from crate attributes! @@ -146,6 +150,8 @@ impl fmt::Debug for Options { .field("test_args", &self.test_args) .field("persist_doctests", &self.persist_doctests) .field("default_passes", &self.default_passes) + .field("document_private", &self.document_private) + .field("document_hidden", &self.document_hidden) .field("manual_passes", &self.manual_passes) .field("display_warnings", &self.display_warnings) .field("show_coverage", &self.show_coverage) @@ -240,22 +246,26 @@ impl Options { println!("{:>20} - {}", pass.name, pass.description); } println!("\nDefault passes for rustdoc:"); - for pass in passes::DEFAULT_PASSES { - println!("{:>20}", pass.name); - } - println!("\nPasses run with `--document-private-items`:"); - for pass in passes::DEFAULT_PRIVATE_PASSES { - println!("{:>20}", pass.name); + for p in passes::DEFAULT_PASSES { + print!("{:>20}", p.pass.name); + println_condition(p.condition); } if nightly_options::is_nightly_build() { println!("\nPasses run with `--show-coverage`:"); - for pass in passes::DEFAULT_COVERAGE_PASSES { - println!("{:>20}", pass.name); + for p in passes::COVERAGE_PASSES { + print!("{:>20}", p.pass.name); + println_condition(p.condition); } - println!("\nPasses run with `--show-coverage --document-private-items`:"); - for pass in passes::PRIVATE_COVERAGE_PASSES { - println!("{:>20}", pass.name); + } + + fn println_condition(condition: Condition) { + use Condition::*; + match condition { + Always => println!(), + WhenDocumentPrivate => println!(" (when --document-private-items)"), + WhenNotDocumentPrivate => println!(" (when not --document-private-items)"), + WhenNotDocumentHidden => println!(" (when not --document-hidden-items)"), } } @@ -449,16 +459,11 @@ impl Options { }); let show_coverage = matches.opt_present("show-coverage"); - let document_private = matches.opt_present("document-private-items"); let default_passes = if matches.opt_present("no-defaults") { passes::DefaultPassOption::None - } else if show_coverage && document_private { - passes::DefaultPassOption::PrivateCoverage } else if show_coverage { passes::DefaultPassOption::Coverage - } else if document_private { - passes::DefaultPassOption::Private } else { passes::DefaultPassOption::Default }; @@ -497,6 +502,8 @@ impl Options { let runtool = matches.opt_str("runtool"); let runtool_args = matches.opt_strs("runtool-arg"); let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); + let document_private = matches.opt_present("document-private-items"); + let document_hidden = matches.opt_present("document-hidden-items"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -523,6 +530,8 @@ impl Options { should_test, test_args, default_passes, + document_private, + document_hidden, manual_passes, display_warnings, show_coverage, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 80dd9ad7739b2..9dab2b82cb68e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -33,7 +33,7 @@ use crate::clean::{AttributesExt, MAX_DEF_ID}; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::html::render::RenderInfo; -use crate::passes; +use crate::passes::{self, Condition::*, ConditionalPass}; pub use rustc::session::config::{CodegenOptions, Input, Options}; pub use rustc::session::search_paths::SearchPath; @@ -234,6 +234,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt describe_lints, lint_cap, mut default_passes, + mut document_private, + document_hidden, mut manual_passes, display_warnings, render_options, @@ -469,16 +471,14 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } if attr.is_word() && name == sym::document_private_items { - if default_passes == passes::DefaultPassOption::Default { - default_passes = passes::DefaultPassOption::Private; - } + document_private = true; } } - let passes = passes::defaults(default_passes).iter().chain( + let passes = passes::defaults(default_passes).iter().copied().chain( manual_passes.into_iter().flat_map(|name| { if let Some(pass) = passes::find_pass(&name) { - Some(pass) + Some(ConditionalPass::always(pass)) } else { error!("unknown pass {}, skipping", name); None @@ -488,9 +488,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt info!("Executing passes"); - for pass in passes { - debug!("running pass {}", pass.name); - krate = (pass.pass)(krate, &ctxt); + for p in passes { + let run = match p.condition { + Always => true, + WhenDocumentPrivate => document_private, + WhenNotDocumentPrivate => !document_private, + WhenNotDocumentHidden => !document_hidden, + }; + if run { + debug!("running pass {}", p.pass.name); + krate = (p.pass.run)(krate, &ctxt); + } } ctxt.sess().abort_if_errors(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0b4abe0a22e3b..0a71deca0dc61 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -173,6 +173,9 @@ fn opts() -> Vec { stable("document-private-items", |o| { o.optflag("", "document-private-items", "document private items") }), + unstable("document-hidden-items", |o| { + o.optflag("", "document-hidden-items", "document items that have doc(hidden)") + }), stable("test", |o| o.optflag("", "test", "run code examples as tests")), stable("test-args", |o| { o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 75f874d83274e..72f98026f8b2d 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -12,7 +12,7 @@ use std::ops; pub const CALCULATE_DOC_COVERAGE: Pass = Pass { name: "calculate-doc-coverage", - pass: calculate_doc_coverage, + run: calculate_doc_coverage, description: "counts the number of items with and without documentation", }; diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 7bbed4af23838..3cb3a8003cee0 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -13,7 +13,7 @@ use crate::passes::Pass; pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass { name: "check-code-block-syntax", - pass: check_code_block_syntax, + run: check_code_block_syntax, description: "validates syntax inside Rust code blocks", }; diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index c6b22883e9723..c2185592d1483 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -8,7 +8,7 @@ use std::mem::take; pub const COLLAPSE_DOCS: Pass = Pass { name: "collapse-docs", - pass: collapse_docs, + run: collapse_docs, description: "concatenates all document attributes into one document attribute", }; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index af850a3446799..a92a6152c726a 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -28,7 +28,7 @@ use super::span_of_attrs; pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { name: "collect-intra-doc-links", - pass: collect_intra_doc_links, + run: collect_intra_doc_links, description: "reads a crate's documentation to resolve intra-doc-links", }; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 4e0d1a101917d..bec352fe1558f 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -9,7 +9,7 @@ use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { name: "collect-trait-impls", - pass: collect_trait_impls, + run: collect_trait_impls, description: "retrieves trait impls for items in the crate", }; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index b69207be3fb36..985aaa66b31d0 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -9,6 +9,7 @@ use std::mem; use std::ops::Range; use syntax_pos::{InnerSpan, Span, DUMMY_SP}; +use self::Condition::*; use crate::clean::{self, GetDefId, Item}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; @@ -53,10 +54,29 @@ pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE; #[derive(Copy, Clone)] pub struct Pass { pub name: &'static str, - pub pass: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, + pub run: fn(clean::Crate, &DocContext<'_>) -> clean::Crate, pub description: &'static str, } +/// In a list of passes, a pass that may or may not need to be run depending on options. +#[derive(Copy, Clone)] +pub struct ConditionalPass { + pub pass: Pass, + pub condition: Condition, +} + +/// How to decide whether to run a conditional pass. +#[derive(Copy, Clone)] +pub enum Condition { + Always, + /// When `--document-private-items` is passed. + WhenDocumentPrivate, + /// When `--document-private-items` is not passed. + WhenNotDocumentPrivate, + /// When `--document-hidden-items` is not passed. + WhenNotDocumentHidden, +} + /// The full list of passes. pub const PASSES: &[Pass] = &[ CHECK_PRIVATE_ITEMS_DOC_TESTS, @@ -73,63 +93,58 @@ pub const PASSES: &[Pass] = &[ ]; /// The list of passes run by default. -pub const DEFAULT_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - COLLAPSE_DOCS, - UNINDENT_COMMENTS, - CHECK_PRIVATE_ITEMS_DOC_TESTS, - STRIP_HIDDEN, - STRIP_PRIVATE, - COLLECT_INTRA_DOC_LINKS, - CHECK_CODE_BLOCK_SYNTAX, - PROPAGATE_DOC_CFG, +pub const DEFAULT_PASSES: &[ConditionalPass] = &[ + ConditionalPass::always(COLLECT_TRAIT_IMPLS), + ConditionalPass::always(COLLAPSE_DOCS), + ConditionalPass::always(UNINDENT_COMMENTS), + ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS), + ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), + ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), + ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), + ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), + ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX), + ConditionalPass::always(PROPAGATE_DOC_CFG), ]; -/// The list of default passes run with `--document-private-items` is passed to rustdoc. -pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[ - COLLECT_TRAIT_IMPLS, - COLLAPSE_DOCS, - UNINDENT_COMMENTS, - CHECK_PRIVATE_ITEMS_DOC_TESTS, - STRIP_PRIV_IMPORTS, - COLLECT_INTRA_DOC_LINKS, - CHECK_CODE_BLOCK_SYNTAX, - PROPAGATE_DOC_CFG, +/// The list of default passes run when `--doc-coverage` is passed to rustdoc. +pub const COVERAGE_PASSES: &[ConditionalPass] = &[ + ConditionalPass::always(COLLECT_TRAIT_IMPLS), + ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), + ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), + ConditionalPass::always(CALCULATE_DOC_COVERAGE), ]; -/// The list of default passes run when `--doc-coverage` is passed to rustdoc. -pub const DEFAULT_COVERAGE_PASSES: &[Pass] = - &[COLLECT_TRAIT_IMPLS, STRIP_HIDDEN, STRIP_PRIVATE, CALCULATE_DOC_COVERAGE]; +impl ConditionalPass { + pub const fn always(pass: Pass) -> Self { + Self::new(pass, Always) + } -/// The list of default passes run when `--doc-coverage --document-private-items` is passed to -/// rustdoc. -pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[COLLECT_TRAIT_IMPLS, CALCULATE_DOC_COVERAGE]; + pub const fn new(pass: Pass, condition: Condition) -> Self { + ConditionalPass { pass, condition } + } +} /// A shorthand way to refer to which set of passes to use, based on the presence of -/// `--no-defaults` or `--document-private-items`. +/// `--no-defaults` and `--show-coverage`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DefaultPassOption { Default, - Private, Coverage, - PrivateCoverage, None, } /// Returns the given default set of passes. -pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] { +pub fn defaults(default_set: DefaultPassOption) -> &'static [ConditionalPass] { match default_set { DefaultPassOption::Default => DEFAULT_PASSES, - DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES, - DefaultPassOption::Coverage => DEFAULT_COVERAGE_PASSES, - DefaultPassOption::PrivateCoverage => PRIVATE_COVERAGE_PASSES, + DefaultPassOption::Coverage => COVERAGE_PASSES, DefaultPassOption::None => &[], } } /// If the given name matches a known pass, returns its information. -pub fn find_pass(pass_name: &str) -> Option<&'static Pass> { - PASSES.iter().find(|p| p.name == pass_name) +pub fn find_pass(pass_name: &str) -> Option { + PASSES.iter().find(|p| p.name == pass_name).copied() } struct Stripper<'a> { diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 23e272709705d..aec5a6bd4e221 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -5,7 +5,7 @@ use crate::passes::{look_for_tests, Pass}; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { name: "check-private-items-doc-tests", - pass: check_private_items_doc_tests, + run: check_private_items_doc_tests, description: "check private items doc tests", }; diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index a296e73e3b5fd..64b0c45ba65d3 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -8,7 +8,7 @@ use crate::passes::Pass; pub const PROPAGATE_DOC_CFG: Pass = Pass { name: "propagate-doc-cfg", - pass: propagate_doc_cfg, + run: propagate_doc_cfg, description: "propagates `#[doc(cfg(...))]` to child items", }; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 379e2496a0a41..2b4de3c063f38 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -10,7 +10,7 @@ use crate::passes::{ImplStripper, Pass}; pub const STRIP_HIDDEN: Pass = Pass { name: "strip-hidden", - pass: strip_hidden, + run: strip_hidden, description: "strips all doc(hidden) items from the output", }; diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index af34842ad0f89..35b26fb8ab0be 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -5,7 +5,7 @@ use crate::passes::{ImportStripper, Pass}; pub const STRIP_PRIV_IMPORTS: Pass = Pass { name: "strip-priv-imports", - pass: strip_priv_imports, + run: strip_priv_imports, description: "strips all private import statements (`use`, `extern crate`) from a crate", }; diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 5113afa48402c..e0379d7ffe2c5 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -7,7 +7,7 @@ use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper}; pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", - pass: strip_private, + run: strip_private, description: "strips all private items from a crate which cannot be seen externally, \ implies strip-priv-imports", }; diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 3212af055efc5..d4e09ce47a3c1 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -12,7 +12,7 @@ mod tests; pub const UNINDENT_COMMENTS: Pass = Pass { name: "unindent-comments", - pass: unindent_comments, + run: unindent_comments, description: "removes excess indentation on comments in order for markdown to like it", }; diff --git a/src/test/rustdoc/issue-46380.rs b/src/test/rustdoc/issue-46380.rs deleted file mode 100644 index 8837a6b463e88..0000000000000 --- a/src/test/rustdoc/issue-46380.rs +++ /dev/null @@ -1,5 +0,0 @@ -// compile-flags: --document-private-items - -// @has issue_46380/struct.Hidden.html -#[doc(hidden)] -pub struct Hidden; diff --git a/src/test/rustdoc/issue-67851-both.rs b/src/test/rustdoc/issue-67851-both.rs new file mode 100644 index 0000000000000..d69b943173412 --- /dev/null +++ b/src/test/rustdoc/issue-67851-both.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-private-items --document-hidden-items + +// @has issue_67851_both/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_both/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-hidden.rs b/src/test/rustdoc/issue-67851-hidden.rs new file mode 100644 index 0000000000000..8a3cafe4c3dc7 --- /dev/null +++ b/src/test/rustdoc/issue-67851-hidden.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zunstable-options --document-hidden-items + +// @has issue_67851_hidden/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_hidden/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-neither.rs b/src/test/rustdoc/issue-67851-neither.rs new file mode 100644 index 0000000000000..4e3cd83285388 --- /dev/null +++ b/src/test/rustdoc/issue-67851-neither.rs @@ -0,0 +1,6 @@ +// @!has issue_67851_neither/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @!has issue_67851_neither/struct.Private.html +struct Private; diff --git a/src/test/rustdoc/issue-67851-private.rs b/src/test/rustdoc/issue-67851-private.rs new file mode 100644 index 0000000000000..8addc7f3e4b53 --- /dev/null +++ b/src/test/rustdoc/issue-67851-private.rs @@ -0,0 +1,8 @@ +// compile-flags: --document-private-items + +// @!has issue_67851_private/struct.Hidden.html +#[doc(hidden)] +pub struct Hidden; + +// @has issue_67851_private/struct.Private.html +struct Private; From d97ae997a4f60efcc04030e9b0ea2e9509475fc3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 23 Jan 2020 16:12:53 -0500 Subject: [PATCH 21/38] format librustc_errors --- src/librustc_errors/emitter.rs | 603 +++++++++++++++++---------------- src/librustc_errors/lib.rs | 222 ++++++------ 2 files changed, 421 insertions(+), 404 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 451913757482a..985fd54449e9e 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -9,26 +9,25 @@ use Destination::*; -use syntax_pos::{SourceFile, Span, MultiSpan}; use syntax_pos::source_map::SourceMap; +use syntax_pos::{MultiSpan, SourceFile, Span}; +use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; +use crate::styled_buffer::StyledBuffer; +use crate::Level::Error; use crate::{ - Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralize, - SuggestionStyle, DiagnosticId, + pluralize, CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle, }; -use crate::Level::Error; -use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; -use crate::styled_buffer::StyledBuffer; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::borrow::Cow; -use std::io::prelude::*; +use std::cmp::{max, min, Reverse}; use std::io; -use std::cmp::{min, max, Reverse}; +use std::io::prelude::*; use std::path::Path; -use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; -use termcolor::{WriteColor, Color, Buffer}; +use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; +use termcolor::{Buffer, Color, WriteColor}; /// Describes the way the content of the `rendered` field of the json output is generated #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -57,8 +56,15 @@ impl HumanReadableErrorType { ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); - EmitterWriter::new(dst, source_map, short, teach, color, terminal_width, - external_macro_backtrace) + EmitterWriter::new( + dst, + source_map, + short, + teach, + color, + terminal_width, + external_macro_backtrace, + ) } } @@ -117,15 +123,15 @@ impl Margin { } fn was_cut_right(&self, line_len: usize) -> bool { - let right = if self.computed_right == self.span_right || - self.computed_right == self.label_right - { - // Account for the "..." padding given above. Otherwise we end up with code lines that - // do fit but end in "..." as if they were trimmed. - self.computed_right - 6 - } else { - self.computed_right - }; + let right = + if self.computed_right == self.span_right || self.computed_right == self.label_right { + // Account for the "..." padding given above. Otherwise we end + // up with code lines that do fit but end in "..." as if they + // were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; right < line_len && self.computed_left + self.column_width < line_len } @@ -156,7 +162,8 @@ impl Margin { let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; self.computed_left = self.span_left.saturating_sub(padding_left); self.computed_right = self.computed_left + self.column_width; - } else { // Mostly give up but still don't show the full line. + } else { + // Mostly give up but still don't show the full line. self.computed_left = self.span_left; self.computed_right = self.span_right; } @@ -240,11 +247,15 @@ pub trait Emitter { format!( "help: {}{}: `{}`", sugg.msg, - if self.source_map().map(|sm| is_case_difference( - &**sm, - substitution, - sugg.substitutions[0].parts[0].span, - )).unwrap_or(false) { + if self + .source_map() + .map(|sm| is_case_difference( + &**sm, + substitution, + sugg.substitutions[0].parts[0].span, + )) + .unwrap_or(false) + { " (notice the capitalization)" } else { "" @@ -271,37 +282,35 @@ pub trait Emitter { // This does a small "fix" for multispans by looking to see if it can find any that // point directly at <*macros>. Since these are often difficult to read, this // will change the span to point at the use site. - fn fix_multispans_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool) { + fn fix_multispans_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + children: &mut Vec, + level: &Level, + backtrace: bool, + ) { let mut spans_updated = self.fix_multispan_in_std_macros(source_map, span, backtrace); for child in children.iter_mut() { - spans_updated |= self.fix_multispan_in_std_macros( - source_map, - &mut child.span, - backtrace - ); + spans_updated |= + self.fix_multispan_in_std_macros(source_map, &mut child.span, backtrace); } let msg = if level == &Error { "this error originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() } else { "this warning originates in a macro outside of the current crate \ (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() + for more info)" + .to_string() }; if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message: vec![ - (msg, - Style::NoStyle), - ], + message: vec![(msg, Style::NoStyle)], span: MultiSpan::new(), render_span: None, }); @@ -311,10 +320,12 @@ pub trait Emitter { // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of // <*macros>. Since these locations are often difficult to read, we move these Spans from // <*macros> to their corresponding use site. - fn fix_multispan_in_std_macros(&self, - source_map: &Option>, - span: &mut MultiSpan, - always_backtrace: bool) -> bool { + fn fix_multispan_in_std_macros( + &self, + source_map: &Option>, + span: &mut MultiSpan, + always_backtrace: bool, + ) -> bool { let sm = match source_map { Some(ref sm) => sm, None => return false, @@ -340,31 +351,40 @@ pub trait Emitter { continue; } if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); + new_labels.push(( + trace.def_site_span, + format!( + "in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); } // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); + if !sm.span_to_filename(trace.def_site_span).is_macros() + && !trace.macro_decl_name.starts_with("desugaring of ") + && !trace.macro_decl_name.starts_with("#[") + || always_backtrace + { + new_labels.push(( + trace.call_site, + format!( + "in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + } + ), + )); if !always_backtrace { break; } @@ -378,9 +398,7 @@ pub trait Emitter { if sp_label.span.is_dummy() { continue; } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { + if sm.span_to_filename(sp_label.span.clone()).is_macros() && !always_backtrace { let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); @@ -406,18 +424,22 @@ impl Emitter for EmitterWriter { let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag); - self.fix_multispans_in_std_macros(&self.sm, - &mut primary_span, - &mut children, - &diag.level, - self.external_macro_backtrace); - - self.emit_messages_default(&diag.level, - &diag.styled_message(), - &diag.code, - &primary_span, - &children, - &suggestions); + self.fix_multispans_in_std_macros( + &self.sm, + &mut primary_span, + &mut children, + &diag.level, + self.external_macro_backtrace, + ); + + self.emit_messages_default( + &diag.level, + &diag.styled_message(), + &diag.code, + &primary_span, + &children, + &suggestions, + ); } fn should_show_explain(&self) -> bool { @@ -429,7 +451,9 @@ impl Emitter for EmitterWriter { pub struct SilentEmitter; impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { None } + fn source_map(&self) -> Option<&Lrc> { + None + } fn emit_diagnostic(&mut self, _: &Diagnostic) {} } @@ -458,17 +482,13 @@ impl ColorConfig { } } ColorConfig::Never => ColorChoice::Never, - ColorConfig::Auto if atty::is(atty::Stream::Stderr) => { - ColorChoice::Auto - } + ColorConfig::Auto if atty::is(atty::Stream::Stderr) => ColorChoice::Auto, ColorConfig::Auto => ColorChoice::Never, } } fn suggests_using_colors(self) -> bool { match self { - | ColorConfig::Always - | ColorConfig::Auto - => true, + ColorConfig::Always | ColorConfig::Auto => true, ColorConfig::Never => false, } } @@ -540,11 +560,7 @@ impl EmitterWriter { } fn maybe_anonymized(&self, line_num: usize) -> String { - if self.ui_testing { - ANONYMIZED_LINE_NUM.to_string() - } else { - line_num.to_string() - } + if self.ui_testing { ANONYMIZED_LINE_NUM.to_string() } else { line_num.to_string() } } fn draw_line( @@ -563,17 +579,22 @@ impl EmitterWriter { let right = margin.right(line_len); // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; - let code: String = source_string.chars().skip(left).take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. - // For now, just accept that sometimes the code line will be longer than desired. - let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); - if taken + next > right - left { - return false; - } - taken += next; - true - }).collect(); + let code: String = source_string + .chars() + .skip(left) + .take_while(|ch| { + // Make sure that the trimming on the right will fall within the + // terminal width. FIXME: `unicode_width` sometimes disagrees + // with terminals on how wide a `char` is. For now, just accept + // that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }) + .collect(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. @@ -624,7 +645,9 @@ impl EmitterWriter { let left = margin.left(source_string.len()); // Left trim // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left) + let left = source_string + .chars() + .take(left) .map(|ch| unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1)) .sum(); @@ -773,13 +796,14 @@ impl EmitterWriter { if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). - && p == 0 // We're currently on the first line, move the label one line down + && p == 0 + // We're currently on the first line, move the label one line down { // If we're overlapping with an un-labelled annotation with the same span // we can just merge them in the output if next.start_col == annotation.start_col - && next.end_col == annotation.end_col - && !next.has_label() + && next.end_col == annotation.end_col + && !next.has_label() { continue; } @@ -791,7 +815,7 @@ impl EmitterWriter { } annotations_position.push((p, annotation)); for (j, next) in annotations.iter().enumerate() { - if j > i { + if j > i { let l = next.label.as_ref().map_or(0, |label| label.len() + 2); if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to @@ -814,7 +838,8 @@ impl EmitterWriter { || (overlaps(next, annotation, l) && next.end_col <= annotation.end_col && next.has_label() - && p == 0) // Avoid #42595. + && p == 0) + // Avoid #42595. { // This annotation needs a new line in the output. p += 1; @@ -848,10 +873,7 @@ impl EmitterWriter { // | for pos in 0..=line_len { draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2); - buffer.putc(line_offset + pos + 1, - width_offset - 2, - '|', - Style::LineNumber); + buffer.putc(line_offset + pos + 1, width_offset - 2, '|', Style::LineNumber); } // Write the horizontal lines for multiline annotations @@ -874,8 +896,7 @@ impl EmitterWriter { }; let pos = pos + 1; match annotation.annotation_type { - AnnotationType::MultilineStart(depth) | - AnnotationType::MultilineEnd(depth) => { + AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { draw_range( buffer, '_', @@ -919,27 +940,23 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { - buffer.putc(p, - (code_offset + annotation.start_col).saturating_sub(left), - '|', - style); + buffer.putc( + p, + (code_offset + annotation.start_col).saturating_sub(left), + '|', + style, + ); } } match annotation.annotation_type { AnnotationType::MultilineStart(depth) => { for p in line_offset + pos + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } AnnotationType::MultilineEnd(depth) => { for p in line_offset..=line_offset + pos { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); + buffer.putc(p, width_offset + depth - 1, '|', style); } } _ => (), @@ -958,11 +975,8 @@ impl EmitterWriter { // 4 | } // | _ test for &(pos, annotation) in &annotations_position { - let style = if annotation.is_primary { - Style::LabelPrimary - } else { - Style::LabelSecondary - }; + let style = + if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { (pos + 1, (annotation.end_col + 1).saturating_sub(left)) } else { @@ -1012,8 +1026,9 @@ impl EmitterWriter { ); } } - annotations_position.iter().filter_map(|&(_, annotation)| { - match annotation.annotation_type { + annotations_position + .iter() + .filter_map(|&(_, annotation)| match annotation.annotation_type { AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { let style = if annotation.is_primary { Style::LabelPrimary @@ -1022,10 +1037,9 @@ impl EmitterWriter { }; Some((p, style)) } - _ => None - } - - }).collect::>() + _ => None, + }) + .collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { @@ -1055,7 +1069,8 @@ impl EmitterWriter { fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { let primary = self.get_multispan_max_line_num(span); - children.iter() + children + .iter() .map(|sub| self.get_multispan_max_line_num(&sub.span)) .max() .unwrap_or(0) @@ -1064,13 +1079,14 @@ impl EmitterWriter { /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. - fn msg_to_buffer(&self, - buffer: &mut StyledBuffer, - msg: &[(String, Style)], - padding: usize, - label: &str, - override_style: Option