diff --git a/Cargo.lock b/Cargo.lock index 940608975c5ec..d4d3ca75b8d92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1529,9 +1529,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "compiler_builtins", "libc", diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index d60388b31c13c..42333dc29bc7c 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -63,7 +63,7 @@ pub trait TraitEngine<'tcx>: 'tcx { infcx: &InferCtxt<'_, 'tcx>, ) -> Result<(), Vec>>; - // FIXME this should not provide a default body for chalk as chalk should be updated + // FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated fn select_with_constness_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index ec53625f10525..ee66a948dd93c 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -101,7 +101,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc let mut l = lint.build("panic message is not a string literal"); l.note("this usage of panic!() is deprecated; it will be a hard error in Rust 2021"); l.note("for more information, see "); - if !span.contains(arg_span) { + if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. l.emit(); return; @@ -120,13 +120,26 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ); } } else { + let ty = cx.typeck_results().expr_ty(arg); + // If this is a &str or String, we can confidently give the `"{}", ` suggestion. + let is_str = matches!( + ty.kind(), + ty::Ref(_, r, _) if *r.kind() == ty::Str, + ) || matches!( + ty.ty_adt_def(), + Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did), + ); l.span_suggestion_verbose( arg_span.shrink_to_lo(), "add a \"{}\" format string to Display the message", "\"{}\", ".into(), - Applicability::MaybeIncorrect, + if is_str { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }, ); - if panic == sym::std_panic_macro { + if !is_str && panic == sym::std_panic_macro { if let Some((open, close, del)) = find_delimiters(cx, span) { l.multipart_suggestion( "or use std::panic::panic_any instead", @@ -191,7 +204,7 @@ fn check_panic_str<'tcx>( _ => "panic message contains unused formatting placeholders", }); l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021"); - if span.contains(arg.span) { + if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_hi(), &format!("add the missing argument{}", pluralize!(n_arguments)), @@ -222,7 +235,7 @@ fn check_panic_str<'tcx>( cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| { let mut l = lint.build(msg); l.note("this message is not used as a format string, but will be in Rust 2021"); - if span.contains(arg.span) { + if is_arg_inside_call(arg.span, span) { l.span_suggestion( arg.span.shrink_to_lo(), "add a \"{}\" format string to use the message literally", @@ -270,3 +283,11 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind { symbol } else { sym::panic }; (expn.call_site, panic_macro, macro_symbol.as_str()) } + +fn is_arg_inside_call(arg: Span, call: Span) -> bool { + // We only add suggestions if the argument we're looking at appears inside the + // panic call in the source file, to avoid invalid suggestions when macros are involved. + // We specifically check for the spans to not be identical, as that happens sometimes when + // proc_macros lie about spans and apply the same span to all the tokens they produce. + call.contains(arg) && !call.source_equal(&arg) +} diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 012d97ef106c7..96e9a40df3685 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -139,6 +139,7 @@ impl ExprVisitor<'tcx> { reg: InlineAsmRegOrRegClass, expr: &hir::Expr<'tcx>, template: &[InlineAsmTemplatePiece], + is_input: bool, tied_input: Option<(&hir::Expr<'tcx>, Option)>, ) -> Option { // Check the type against the allowed types for inline asm. @@ -150,7 +151,9 @@ impl ExprVisitor<'tcx> { _ => unreachable!(), }; let asm_ty = match *ty.kind() { - ty::Never | ty::Error(_) => return None, + // `!` is allowed for input but not for output (issue #87802) + ty::Never if is_input => return None, + ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32), @@ -350,24 +353,26 @@ impl ExprVisitor<'tcx> { for (idx, (op, _)) in asm.operands.iter().enumerate() { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); } hir::InlineAsmOperand::Out { reg, late: _, ref expr } => { if let Some(expr) = expr { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } } hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => { - self.check_asm_operand_type(idx, reg, expr, asm.template, None); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => { - let in_ty = self.check_asm_operand_type(idx, reg, in_expr, asm.template, None); + let in_ty = + self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, reg, out_expr, asm.template, + false, Some((in_expr, in_ty)), ); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index dcf5ac63b78ea..38dbacbf2ae6c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -316,7 +316,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - /// returns `true` if the predicate is considered `const` to + /// Returns `true` if the predicate is considered `const` to /// this selection context. pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool { match pred.kind().skip_binder() { diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index f4a0cc6767f09..bd0acb0e53b6c 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -6,9 +6,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; -use rustc_middle::ty::{ - self, FnSig, Lift, PolyFnSig, PredicateKind, Ty, TyCtxt, TypeFoldable, Variance, -}; +use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance}; use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -87,16 +85,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { Ok(()) } - fn prove_predicate(&mut self, mut predicate: Predicate<'tcx>) { - if let PredicateKind::Trait(mut tr) = predicate.kind().skip_binder() { - if let hir::Constness::Const = tr.constness { - // FIXME check if we actually want to prove const predicates inside AscribeUserType - tr.constness = hir::Constness::NotConst; - predicate = - predicate.kind().rebind(PredicateKind::Trait(tr)).to_predicate(self.tcx()); - } - } - + fn prove_predicate(&mut self, predicate: Predicate<'tcx>) { self.fulfill_cx.register_predicate_obligation( self.infcx, Obligation::new(ObligationCause::dummy(), self.param_env, predicate), diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs index 02e8f8f40228f..b6ef3eee291fb 100644 --- a/library/alloc/tests/const_fns.rs +++ b/library/alloc/tests/const_fns.rs @@ -10,7 +10,7 @@ pub const MY_VEC: Vec = Vec::new(); #[allow(dead_code)] pub const MY_STRING: String = String::new(); -// FIXME remove this struct once we put `K: ?const Ord` on BTreeMap::new. +// FIXME(fee1-dead) remove this struct once we put `K: ?const Ord` on BTreeMap::new. #[derive(PartialEq, Eq, PartialOrd)] pub struct MyType; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f7d68b5a89e99..7284c05d5ff16 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -25,8 +25,6 @@ #![feature(string_remove_matches)] #![feature(const_btree_new)] #![feature(const_trait_impl)] -// FIXME remove this when const_trait_impl is not incomplete anymore -#![allow(incomplete_features)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 64f413acd9709..7e260aaa4289e 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -42,7 +42,7 @@ dlmalloc = { version = "0.2.1", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies] -hermit-abi = { version = "0.1.17", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs index b45e8718f088e..fa8ef8fc37a95 100644 --- a/library/std/src/sys/hermit/condvar.rs +++ b/library/std/src/sys/hermit/condvar.rs @@ -14,7 +14,7 @@ pub struct Condvar { sem2: *const c_void, } -pub type MovableCondvar = Box; +pub type MovableCondvar = Condvar; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index 4221799114b53..691e7e07902d8 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -156,7 +156,7 @@ pub struct Mutex { inner: Spinlock, } -pub type MovableMutex = Box; +pub type MovableMutex = Mutex; unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index d2058180121dc..64eaa2fc482dc 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -8,7 +8,7 @@ pub struct RWLock { state: UnsafeCell, } -pub type MovableRWLock = Box; +pub type MovableRWLock = RWLock; enum State { Unlocked, diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 489c3d7660195..e42b4748fdc78 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -220,11 +220,13 @@ else fi if [ "$CI" != "" ]; then - # Get some needed information for $BASE_COMMIT - git fetch "https://github.com/$GITHUB_REPOSITORY" "$GITHUB_BASE_REF" - BASE_COMMIT="$(git merge-base FETCH_HEAD HEAD)" + # Get some needed information for $BASE_COMMIT + # + # This command gets the last merge commit which we'll use as base to list + # deleted files since then. + BASE_COMMIT="$(git log --author=bors@rust-lang.org -n 2 --pretty=format:%H | tail -n 1)" else - BASE_COMMIT="" + BASE_COMMIT="" fi docker \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0bfe35ea86189..6da0703beacc9 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -73,6 +73,8 @@ Tier Policy. All tier 2 targets with host tools support the full standard library. +**NOTE:** Tier 2 targets currently do not build the `rust-docs` component. + target | notes -------|------- `aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+) @@ -112,6 +114,8 @@ The `std` column in the table below has the following meanings: [`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html +**NOTE:** Tier 2 targets currently do not build the `rust-docs` component. + target | std | notes -------|:---:|------- `aarch64-apple-ios` | ✓ | ARM64 iOS diff --git a/src/test/ui/asm/issue-87802.rs b/src/test/ui/asm/issue-87802.rs new file mode 100644 index 0000000000000..989173c23e86c --- /dev/null +++ b/src/test/ui/asm/issue-87802.rs @@ -0,0 +1,17 @@ +// needs-asm-support +// Make sure rustc doesn't ICE on asm! when output type is !. + +#![feature(asm)] + +fn hmm() -> ! { + let x; + unsafe { + asm!("/* {0} */", out(reg) x); + //~^ ERROR cannot use value of type `!` for inline assembly + } + x +} + +fn main() { + hmm(); +} diff --git a/src/test/ui/asm/issue-87802.stderr b/src/test/ui/asm/issue-87802.stderr new file mode 100644 index 0000000000000..1eb72b68a7f04 --- /dev/null +++ b/src/test/ui/asm/issue-87802.stderr @@ -0,0 +1,10 @@ +error: cannot use value of type `!` for inline assembly + --> $DIR/issue-87802.rs:9:36 + | +LL | asm!("/* {0} */", out(reg) x); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: aborting due to previous error + diff --git a/src/test/ui/non-fmt-panic.fixed b/src/test/ui/non-fmt-panic.fixed new file mode 100644 index 0000000000000..c85e1887d9603 --- /dev/null +++ b/src/test/ui/non-fmt-panic.fixed @@ -0,0 +1,54 @@ +// run-rustfix +// rustfix-only-machine-applicable +// build-pass (FIXME(62277): should be check-pass) +// aux-build:fancy-panic.rs + +extern crate fancy_panic; + +const C: &str = "abc {}"; +static S: &str = "{bla}"; + +#[allow(unreachable_code)] +fn main() { + panic!("{}", "here's a brace: {"); //~ WARN panic message contains a brace + std::panic!("{}", "another one: }"); //~ WARN panic message contains a brace + core::panic!("{}", "Hello {}"); //~ WARN panic message contains an unused formatting placeholder + assert!(false, "{}", "{:03x} {test} bla"); + //~^ WARN panic message contains unused formatting placeholders + assert!(false, "{}", S); + //~^ WARN panic message is not a string literal + debug_assert!(false, "{}", "{{}} bla"); //~ WARN panic message contains braces + panic!("{}", C); //~ WARN panic message is not a string literal + panic!("{}", S); //~ WARN panic message is not a string literal + std::panic::panic_any(123); //~ WARN panic message is not a string literal + core::panic!("{}", &*"abc"); //~ WARN panic message is not a string literal + panic!("{}", concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder + panic!("{}", concat!("{", "{")); //~ WARN panic message contains braces + + fancy_panic::fancy_panic!("test {} 123"); + //~^ WARN panic message contains an unused formatting placeholder + + fancy_panic::fancy_panic!(); // OK + fancy_panic::fancy_panic!(S); // OK + + macro_rules! a { + () => { 123 }; + } + + std::panic::panic_any(a!()); //~ WARN panic message is not a string literal + + panic!("{}", 1); //~ WARN panic message is not a string literal + assert!(false, "{}", 1); //~ WARN panic message is not a string literal + debug_assert!(false, "{}", 1); //~ WARN panic message is not a string literal + + std::panic::panic_any(123); //~ WARN panic message is not a string literal + std::panic::panic_any(123); //~ WARN panic message is not a string literal + + // Check that the lint only triggers for std::panic and core::panic, + // not any panic macro: + macro_rules! panic { + ($e:expr) => (); + } + panic!("{}"); // OK + panic!(S); // OK +} diff --git a/src/test/ui/non-fmt-panic.rs b/src/test/ui/non-fmt-panic.rs index 0de424ce279f3..020bcf00a016d 100644 --- a/src/test/ui/non-fmt-panic.rs +++ b/src/test/ui/non-fmt-panic.rs @@ -1,3 +1,5 @@ +// run-rustfix +// rustfix-only-machine-applicable // build-pass (FIXME(62277): should be check-pass) // aux-build:fancy-panic.rs diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr index 4b18f5546b9b8..513ffd37dc3c8 100644 --- a/src/test/ui/non-fmt-panic.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -1,5 +1,5 @@ warning: panic message contains a brace - --> $DIR/non-fmt-panic.rs:11:29 + --> $DIR/non-fmt-panic.rs:13:29 | LL | panic!("here's a brace: {"); | ^ @@ -12,7 +12,7 @@ LL | panic!("{}", "here's a brace: {"); | +++++ warning: panic message contains a brace - --> $DIR/non-fmt-panic.rs:12:31 + --> $DIR/non-fmt-panic.rs:14:31 | LL | std::panic!("another one: }"); | ^ @@ -24,7 +24,7 @@ LL | std::panic!("{}", "another one: }"); | +++++ warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:13:25 + --> $DIR/non-fmt-panic.rs:15:25 | LL | core::panic!("Hello {}"); | ^^ @@ -40,7 +40,7 @@ LL | core::panic!("{}", "Hello {}"); | +++++ warning: panic message contains unused formatting placeholders - --> $DIR/non-fmt-panic.rs:14:21 + --> $DIR/non-fmt-panic.rs:16:21 | LL | assert!(false, "{:03x} {test} bla"); | ^^^^^^ ^^^^^^ @@ -56,7 +56,7 @@ LL | assert!(false, "{}", "{:03x} {test} bla"); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:16:20 + --> $DIR/non-fmt-panic.rs:18:20 | LL | assert!(false, S); | ^ @@ -69,7 +69,7 @@ LL | assert!(false, "{}", S); | +++++ warning: panic message contains braces - --> $DIR/non-fmt-panic.rs:18:27 + --> $DIR/non-fmt-panic.rs:20:27 | LL | debug_assert!(false, "{{}} bla"); | ^^^^ @@ -81,7 +81,7 @@ LL | debug_assert!(false, "{}", "{{}} bla"); | +++++ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:19:12 + --> $DIR/non-fmt-panic.rs:21:12 | LL | panic!(C); | ^ @@ -92,13 +92,9 @@ help: add a "{}" format string to Display the message | LL | panic!("{}", C); | +++++ -help: or use std::panic::panic_any instead - | -LL | std::panic::panic_any(C); - | ~~~~~~~~~~~~~~~~~~~~~ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:20:12 + --> $DIR/non-fmt-panic.rs:22:12 | LL | panic!(S); | ^ @@ -109,13 +105,9 @@ help: add a "{}" format string to Display the message | LL | panic!("{}", S); | +++++ -help: or use std::panic::panic_any instead - | -LL | std::panic::panic_any(S); - | ~~~~~~~~~~~~~~~~~~~~~ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:21:17 + --> $DIR/non-fmt-panic.rs:23:17 | LL | std::panic!(123); | ^^^ @@ -132,7 +124,7 @@ LL | std::panic::panic_any(123); | ~~~~~~~~~~~~~~~~~~~~~ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:22:18 + --> $DIR/non-fmt-panic.rs:24:18 | LL | core::panic!(&*"abc"); | ^^^^^^^ @@ -145,7 +137,7 @@ LL | core::panic!("{}", &*"abc"); | +++++ warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:23:12 + --> $DIR/non-fmt-panic.rs:25:12 | LL | panic!(concat!("{", "}")); | ^^^^^^^^^^^^^^^^^ @@ -161,7 +153,7 @@ LL | panic!("{}", concat!("{", "}")); | +++++ warning: panic message contains braces - --> $DIR/non-fmt-panic.rs:24:5 + --> $DIR/non-fmt-panic.rs:26:5 | LL | panic!(concat!("{", "{")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -173,7 +165,7 @@ LL | panic!("{}", concat!("{", "{")); | +++++ warning: panic message contains an unused formatting placeholder - --> $DIR/non-fmt-panic.rs:26:37 + --> $DIR/non-fmt-panic.rs:28:37 | LL | fancy_panic::fancy_panic!("test {} 123"); | ^^ @@ -181,7 +173,7 @@ LL | fancy_panic::fancy_panic!("test {} 123"); = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:36:12 + --> $DIR/non-fmt-panic.rs:38:12 | LL | panic!(a!()); | ^^^^ @@ -198,7 +190,7 @@ LL | std::panic::panic_any(a!()); | ~~~~~~~~~~~~~~~~~~~~~ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:38:12 + --> $DIR/non-fmt-panic.rs:40:12 | LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -213,7 +205,7 @@ LL + panic!("{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:39:20 + --> $DIR/non-fmt-panic.rs:41:20 | LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -228,7 +220,7 @@ LL + assert!(false, "{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:40:26 + --> $DIR/non-fmt-panic.rs:42:26 | LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ @@ -243,7 +235,7 @@ LL + debug_assert!(false, "{}", 1); | warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:42:12 + --> $DIR/non-fmt-panic.rs:44:12 | LL | panic![123]; | ^^^ @@ -260,7 +252,7 @@ LL | std::panic::panic_any(123); | ~~~~~~~~~~~~~~~~~~~~~~ ~ warning: panic message is not a string literal - --> $DIR/non-fmt-panic.rs:43:12 + --> $DIR/non-fmt-panic.rs:45:12 | LL | panic!{123}; | ^^^ diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 416d824c5645e..4e77d27d399c2 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -5,6 +5,7 @@ // ``` const fs = require("fs"); const path = require("path"); +const os = require('os'); const {Options, runTest} = require('browser-ui-test'); function showHelp() { @@ -70,12 +71,49 @@ function parseOptions(args) { return null; } +/// Print single char status information without \n +function char_printer(n_tests) { + const max_per_line = 10; + let current = 0; + return { + successful: function() { + current += 1; + if (current % max_per_line === 0) { + process.stdout.write(`. (${current}/${n_tests})${os.EOL}`); + } else { + process.stdout.write("."); + } + }, + erroneous: function() { + current += 1; + if (current % max_per_line === 0) { + process.stderr.write(`F (${current}/${n_tests})${os.EOL}`); + } else { + process.stderr.write("F"); + } + }, + finish: function() { + const spaces = " ".repeat(max_per_line - (current % max_per_line)); + process.stdout.write(`${spaces} (${current}/${n_tests})${os.EOL}${os.EOL}`); + }, + }; +} + +/// Sort array by .file_name property +function by_filename(a, b) { + return a.file_name - b.file_name; +} + async function main(argv) { let opts = parseOptions(argv.slice(2)); if (opts === null) { process.exit(1); } + // Print successful tests too + let debug = false; + // Run tests in sequentially + let no_headless = false; const options = new Options(); try { // This is more convenient that setting fields one by one. @@ -84,6 +122,7 @@ async function main(argv) { "--variable", "DOC_PATH", opts["doc_folder"], ]; if (opts["debug"]) { + debug = true; args.push("--debug"); } if (opts["show_text"]) { @@ -91,6 +130,7 @@ async function main(argv) { } if (opts["no_headless"]) { args.push("--no-headless"); + no_headless = true; } options.parseArguments(args); } catch (error) { @@ -101,25 +141,85 @@ async function main(argv) { let failed = false; let files; if (opts["files"].length === 0) { - files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml"); + files = fs.readdirSync(opts["tests_folder"]); } else { - files = opts["files"].filter(file => path.extname(file) == ".goml"); + files = opts["files"]; + } + files = files.filter(file => path.extname(file) == ".goml"); + if (files.length === 0) { + console.error("rustdoc-gui: No test selected"); + process.exit(2); } - files.sort(); - for (var i = 0; i < files.length; ++i) { - const testPath = path.join(opts["tests_folder"], files[i]); - await runTest(testPath, options).then(out => { - const [output, nb_failures] = out; - console.log(output); - if (nb_failures > 0) { + + console.log(`Running ${files.length} rustdoc-gui tests...`); + process.setMaxListeners(files.length + 1); + let tests = []; + let results = { + successful: [], + failed: [], + errored: [], + }; + const status_bar = char_printer(files.length); + for (let i = 0; i < files.length; ++i) { + const file_name = files[i]; + const testPath = path.join(opts["tests_folder"], file_name); + tests.push( + runTest(testPath, options) + .then(out => { + const [output, nb_failures] = out; + results[nb_failures === 0 ? "successful" : "failed"].push({ + file_name: file_name, + output: output, + }); + if (nb_failures > 0) { + status_bar.erroneous() + failed = true; + } else { + status_bar.successful() + } + }) + .catch(err => { + results.errored.push({ + file_name: file_name, + output: err, + }); + status_bar.erroneous(); failed = true; - } - }).catch(err => { - console.error(err); - failed = true; + }) + ); + if (no_headless) { + await tests[i]; + } + } + if (!no_headless) { + await Promise.all(tests); + } + status_bar.finish(); + + if (debug) { + results.successful.sort(by_filename); + results.successful.forEach(r => { + console.log(r.output); }); } + + if (results.failed.length > 0) { + console.log(""); + results.failed.sort(by_filename); + results.failed.forEach(r => { + console.log(r.output); + }); + } + if (results.errored.length > 0) { + console.log(os.EOL); + // print run errors on the bottom so developers see them better + results.errored.sort(by_filename); + results.errored.forEach(r => { + console.error(r.output); + }); + } + if (failed) { process.exit(1); }